Merge "Change contentEquals implementation to operate in O(n) time."
diff --git a/Android.bp b/Android.bp
index 4e7eba2..c0a2abb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -100,9 +100,9 @@
         ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.keymaster-V4-java-source",
-        ":android.hardware.security.keymint-V2-java-source",
+        ":android.hardware.security.keymint-V3-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
-        ":android.hardware.tv.tuner-V1-java-source",
+        ":android.hardware.tv.tuner-V2-java-source",
         ":android.security.apc-java-source",
         ":android.security.authorization-java-source",
         ":android.security.legacykeystore-java-source",
@@ -205,7 +205,7 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.contexthub-V1.1-java",
         "android.hardware.contexthub-V1.2-java",
-        "android.hardware.contexthub-V1-java",
+        "android.hardware.contexthub-V2-java",
         "android.hardware.gnss-V1.0-java",
         "android.hardware.gnss-V2.1-java",
         "android.hardware.health-V1.0-java-constants",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 0e08496..272b4f6 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -328,10 +328,12 @@
 
 java_library {
     name: "android_test_stubs_current",
-    // Modules do not have test APIs, but we want to include their SystemApis, like we include
-    // the SystemApi of framework-non-updatable-sources.
     static_libs: [
-        "all-modules-system-stubs",
+        // Updatable modules do not have test APIs, but we want to include their SystemApis, like we
+        // include the SystemApi of framework-non-updatable-sources.
+        "all-updatable-modules-system-stubs",
+        // Non-updatable modules on the other hand can have test APIs, so include their test-stubs.
+        "all-non-updatable-modules-test-stubs",
         "android-non-updatable.stubs.test",
         "private-stub-annotations-jar",
     ],
diff --git a/TEST_MAPPING b/TEST_MAPPING
index e178583..a48ce0c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -15,6 +15,22 @@
       ]
     }
   ],
+  "presubmit-pm": [
+    {
+      "name": "PackageManagerServiceServerTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ],
   "presubmit": [
     {
       "name": "ManagedProvisioningTests",
@@ -167,6 +183,20 @@
          "exclude-annotation": "org.junit.Ignore"
        }
      ]
+   },
+   {
+     "name": "PackageManagerServiceServerTests",
+     "options": [
+       {
+         "include-annotation": "android.platform.test.annotations.Presubmit"
+       },
+       {
+         "exclude-annotation": "androidx.test.filters.FlakyTest"
+       },
+       {
+         "exclude-annotation": "org.junit.Ignore"
+       }
+     ]
    }
  ]
 }
diff --git a/apct-tests/perftests/windowmanager/AndroidManifest.xml b/apct-tests/perftests/windowmanager/AndroidManifest.xml
index 95ede34..532a0fc 100644
--- a/apct-tests/perftests/windowmanager/AndroidManifest.xml
+++ b/apct-tests/perftests/windowmanager/AndroidManifest.xml
@@ -17,6 +17,10 @@
     package="com.android.perftests.wm">
 
     <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <!-- For perfetto trace files -->
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -26,6 +30,9 @@
             <action android:name="com.android.perftests.core.PERFTEST" />
           </intent-filter>
         </activity>
+
+        <activity android:name="android.wm.InTaskTransitionTest$TestActivity"
+            android:process=":test" />
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/InTaskTransitionTest.java b/apct-tests/perftests/windowmanager/src/android/wm/InTaskTransitionTest.java
new file mode 100644
index 0000000..2d2cf1c8
--- /dev/null
+++ b/apct-tests/perftests/windowmanager/src/android/wm/InTaskTransitionTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.perftests.utils.ManualBenchmarkState;
+import android.perftests.utils.PerfManualStatusReporter;
+import android.perftests.utils.PerfTestActivity;
+import android.view.WindowManagerGlobal;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+/** Measure the performance of warm launch activity in the same task. */
+public class InTaskTransitionTest extends WindowManagerPerfTestBase
+        implements RemoteCallback.OnResultListener {
+
+    private static final long TIMEOUT_MS = 5000;
+
+    @Rule
+    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
+
+    private final TransitionMetricsReader mMetricsReader = new TransitionMetricsReader();
+
+    @Test
+    @ManualBenchmarkState.ManualBenchmarkTest(
+            targetTestDurationNs = 20 * TIME_1_S_IN_NS,
+            statsReport = @ManualBenchmarkState.StatsReport(
+                    flags = ManualBenchmarkState.StatsReport.FLAG_ITERATION
+                            | ManualBenchmarkState.StatsReport.FLAG_MEAN
+                            | ManualBenchmarkState.StatsReport.FLAG_MAX))
+    public void testStartActivityInSameTask() {
+        final Context context = getInstrumentation().getContext();
+        final Activity activity = getInstrumentation().startActivitySync(
+                new Intent(context, PerfTestActivity.class)
+                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+        final Intent next = new Intent(context, TestActivity.class);
+        next.putExtra(TestActivity.CALLBACK, new RemoteCallback(this));
+
+        final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        long measuredTimeNs = 0;
+
+        boolean readerStarted = false;
+        while (state.keepRunning(measuredTimeNs)) {
+            if (!readerStarted && !state.isWarmingUp()) {
+                mMetricsReader.setCheckpoint();
+                readerStarted = true;
+            }
+            final long startTime = SystemClock.elapsedRealtimeNanos();
+            activity.startActivity(next);
+            synchronized (mMetricsReader) {
+                try {
+                    mMetricsReader.wait(TIMEOUT_MS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+            measuredTimeNs = SystemClock.elapsedRealtimeNanos() - startTime;
+        }
+
+        for (TransitionMetricsReader.TransitionMetrics metrics : mMetricsReader.getMetrics()) {
+            if (metrics.mTransitionDelayMs > 0) {
+                state.addExtraResult("transitionDelayMs", metrics.mTransitionDelayMs);
+            }
+            if (metrics.mWindowsDrawnDelayMs > 0) {
+                state.addExtraResult("windowsDrawnDelayMs", metrics.mWindowsDrawnDelayMs);
+            }
+        }
+    }
+
+    @Override
+    public void onResult(Bundle result) {
+        // The test activity is destroyed.
+        synchronized (mMetricsReader) {
+            mMetricsReader.notifyAll();
+        }
+    }
+
+    /** The test activity runs on a different process to trigger metrics logs. */
+    public static class TestActivity extends Activity implements Runnable {
+        static final String CALLBACK = "callback";
+
+        private RemoteCallback mCallback;
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            mCallback = getIntent().getParcelableExtra(CALLBACK, RemoteCallback.class);
+            if (mCallback != null) {
+                Looper.myLooper().getQueue().addIdleHandler(() -> {
+                    new Thread(this).start();
+                    return false;
+                });
+            }
+        }
+
+        @Override
+        public void run() {
+            // Wait until transition animation is finished and then finish self.
+            try {
+                WindowManagerGlobal.getWindowManagerService()
+                        .syncInputTransactions(true /* waitForAnimations */);
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+            finish();
+        }
+
+        @Override
+        protected void onDestroy() {
+            super.onDestroy();
+            if (mCallback != null) {
+                getMainThreadHandler().post(() -> mCallback.sendResult(null));
+            }
+        }
+    }
+}
diff --git a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
index 4b1982f..aea0326 100644
--- a/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
+++ b/apct-tests/perftests/windowmanager/src/android/wm/WindowManagerPerfTestBase.java
@@ -18,10 +18,17 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS;
+
 import android.app.Activity;
 import android.content.Intent;
+import android.metrics.LogMaker;
+import android.metrics.MetricsReader;
 import android.perftests.utils.PerfTestActivity;
 import android.perftests.utils.WindowPerfTestBase;
+import android.util.SparseArray;
 
 import androidx.test.runner.lifecycle.ActivityLifecycleCallback;
 import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry;
@@ -31,6 +38,7 @@
 import org.junit.runners.model.Statement;
 
 import java.io.File;
+import java.util.ArrayList;
 import java.util.concurrent.TimeUnit;
 
 public class WindowManagerPerfTestBase extends WindowPerfTestBase {
@@ -124,4 +132,42 @@
             }
         }
     }
+
+    static class TransitionMetricsReader {
+        final MetricsReader mMetricsReader = new MetricsReader();
+
+        static class TransitionMetrics {
+            int mTransitionDelayMs;
+            int mWindowsDrawnDelayMs;
+        }
+
+        TransitionMetrics[] getMetrics() {
+            mMetricsReader.read(0);
+            final ArrayList<LogMaker> logs = new ArrayList<>();
+            final LogMaker logTemplate = new LogMaker(APP_TRANSITION);
+            while (mMetricsReader.hasNext()) {
+                final LogMaker b = mMetricsReader.next();
+                if (logTemplate.isSubsetOf(b)) {
+                    logs.add(b);
+                }
+            }
+
+            final TransitionMetrics[] infoArray = new TransitionMetrics[logs.size()];
+            for (int i = 0; i < infoArray.length; i++) {
+                final LogMaker log = logs.get(i);
+                final SparseArray<Object> data = log.getEntries();
+                final TransitionMetrics info = new TransitionMetrics();
+                infoArray[i] = info;
+                info.mTransitionDelayMs =
+                        (int) data.get(APP_TRANSITION_DELAY_MS, -1);
+                info.mWindowsDrawnDelayMs =
+                        (int) data.get(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, -1);
+            }
+            return infoArray;
+        }
+
+        void setCheckpoint() {
+            mMetricsReader.checkpoint();
+        }
+    }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
index 652c49a..0c65b99 100644
--- a/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
+++ b/apex/jobscheduler/framework/java/android/app/JobSchedulerImpl.java
@@ -17,7 +17,9 @@
 package android.app;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.app.job.IJobScheduler;
+import android.app.job.IUserVisibleJobObserver;
 import android.app.job.JobInfo;
 import android.app.job.JobScheduler;
 import android.app.job.JobSnapshot;
@@ -141,4 +143,28 @@
             return null;
         }
     }
+
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @Override
+    public void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) {
+        // TODO(255767350): implement
+    }
+
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @Override
+    public void unregisterUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer) {
+        // TODO(255767350): implement
+    }
+
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @Override
+    public void stopUserVisibleJobsForUser(@NonNull String packageName, int userId) {
+        // TODO(255767350): implement
+    }
 }
diff --git a/apex/jobscheduler/framework/java/android/app/job/IUserVisibleJobObserver.aidl b/apex/jobscheduler/framework/java/android/app/job/IUserVisibleJobObserver.aidl
new file mode 100644
index 0000000..f65a47d
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/job/IUserVisibleJobObserver.aidl
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+import android.app.job.UserVisibleJobSummary;
+
+/**
+ * IPC protocol to know about user-visible job activity.
+ *
+ * @hide
+ */
+oneway interface IUserVisibleJobObserver {
+    /**
+     * Notify the client of all changes to a user-visible jobs' state.
+     * @param summary A token/summary that uniquely identifies and details a single running job
+     * @param isRunning whether the job is currently running or not
+     */
+    void onUserVisibleJobStateChanged(in UserVisibleJobSummary summary, boolean isRunning);
+}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index 76f71a2..13b6652 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -283,4 +283,32 @@
      */
     @SuppressWarnings("HiddenAbstractMethod")
     public abstract List<JobSnapshot> getAllJobSnapshots();
-}
\ No newline at end of file
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @SuppressWarnings("HiddenAbstractMethod")
+    public abstract void registerUserVisibleJobObserver(@NonNull IUserVisibleJobObserver observer);
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @SuppressWarnings("HiddenAbstractMethod")
+    public abstract void unregisterUserVisibleJobObserver(
+            @NonNull IUserVisibleJobObserver observer);
+
+    /**
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            android.Manifest.permission.MANAGE_ACTIVITY_TASKS,
+            android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    @SuppressWarnings("HiddenAbstractMethod")
+    public abstract void stopUserVisibleJobsForUser(@NonNull String packageName, int userId);
+}
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobService.java b/apex/jobscheduler/framework/java/android/app/job/JobService.java
index dabf728..bad641c 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobService.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobService.java
@@ -210,6 +210,7 @@
      * 30 seconds for a data transfer job if a payload size estimate
      * was not provided at the time of scheduling.
      *
+     * @hide
      * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long)
      */
     public final void updateEstimatedNetworkBytes(@NonNull JobParameters params,
@@ -227,6 +228,7 @@
      * 30 seconds for a data transfer job if a payload size estimate
      * was not provided at the time of scheduling.
      *
+     * @hide
      * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long)
      */
     public final void updateEstimatedNetworkBytes(@NonNull JobParameters params,
@@ -237,6 +239,7 @@
 
     /**
      * Tell JobScheduler how much data has successfully been transferred for the data transfer job.
+     * @hide
      */
     public final void updateTransferredNetworkBytes(@NonNull JobParameters params,
             @BytesLong long transferredDownloadBytes, @BytesLong long transferredUploadBytes) {
@@ -247,6 +250,7 @@
     /**
      * Tell JobScheduler how much data has been transferred for the data transfer
      * {@link JobWorkItem}.
+     * @hide
      */
     public final void updateTransferredNetworkBytes(@NonNull JobParameters params,
             @NonNull JobWorkItem item,
@@ -264,6 +268,7 @@
      * <p>
      * This must be implemented for all data transfer jobs.
      *
+     * @hide
      * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long)
      * @see JobInfo#NETWORK_BYTES_UNKNOWN
      */
@@ -287,6 +292,7 @@
      * <p>
      * This must be implemented for all data transfer jobs.
      *
+     * @hide
      * @see JobInfo.Builder#setEstimatedNetworkBytes(long, long)
      * @see JobInfo#NETWORK_BYTES_UNKNOWN
      */
@@ -313,6 +319,7 @@
      * <p>
      * This must be implemented for all data transfer jobs.
      *
+     * @hide
      * @see JobInfo#NETWORK_BYTES_UNKNOWN
      */
     // TODO(255371817): specify the actual time JS will wait for progress before requesting
@@ -341,6 +348,7 @@
      * <p>
      * This must be implemented for all data transfer jobs.
      *
+     * @hide
      * @see JobInfo#NETWORK_BYTES_UNKNOWN
      */
     // TODO(255371817): specify the actual time JS will wait for progress before requesting
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
index 6c4b686..83296a6 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobServiceEngine.java
@@ -367,6 +367,7 @@
     /**
      * Engine's request to get how much data has been downloaded.
      *
+     * @hide
      * @see JobService#getTransferredDownloadBytes()
      */
     @BytesLong
@@ -381,6 +382,7 @@
     /**
      * Engine's request to get how much data has been uploaded.
      *
+     * @hide
      * @see JobService#getTransferredUploadBytes()
      */
     @BytesLong
@@ -395,6 +397,7 @@
     /**
      * Call in to engine to report data transfer progress.
      *
+     * @hide
      * @see JobService#updateTransferredNetworkBytes(JobParameters, long, long)
      */
     public void updateTransferredNetworkBytes(@NonNull JobParameters params,
@@ -413,6 +416,7 @@
     /**
      * Call in to engine to report data transfer progress.
      *
+     * @hide
      * @see JobService#updateEstimatedNetworkBytes(JobParameters, JobWorkItem, long, long)
      */
     public void updateEstimatedNetworkBytes(@NonNull JobParameters params,
diff --git a/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.aidl b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.aidl
new file mode 100644
index 0000000..5160b42
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+parcelable UserVisibleJobSummary;
diff --git a/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java
new file mode 100644
index 0000000..afcbe7d
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/app/job/UserVisibleJobSummary.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.job;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Summary of a scheduled job that the user is meant to be aware of.
+ *
+ * @hide
+ */
+public class UserVisibleJobSummary implements Parcelable {
+    private final int mCallingUid;
+    private final int mSourceUserId;
+    @NonNull
+    private final String mSourcePackageName;
+    private final int mJobId;
+
+    public UserVisibleJobSummary(int callingUid, int sourceUserId,
+            @NonNull String sourcePackageName, int jobId) {
+        mCallingUid = callingUid;
+        mSourceUserId = sourceUserId;
+        mSourcePackageName = sourcePackageName;
+        mJobId = jobId;
+    }
+
+    protected UserVisibleJobSummary(Parcel in) {
+        mCallingUid = in.readInt();
+        mSourceUserId = in.readInt();
+        mSourcePackageName = in.readString();
+        mJobId = in.readInt();
+    }
+
+    public int getCallingUid() {
+        return mCallingUid;
+    }
+
+    public int getJobId() {
+        return mJobId;
+    }
+
+    public int getSourceUserId() {
+        return mSourceUserId;
+    }
+
+    public String getSourcePackageName() {
+        return mSourcePackageName;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof UserVisibleJobSummary)) return false;
+        UserVisibleJobSummary that = (UserVisibleJobSummary) o;
+        return mCallingUid == that.mCallingUid
+                && mSourceUserId == that.mSourceUserId
+                && mSourcePackageName.equals(that.mSourcePackageName)
+                && mJobId == that.mJobId;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 0;
+        result = 31 * result + mCallingUid;
+        result = 31 * result + mSourceUserId;
+        result = 31 * result + mSourcePackageName.hashCode();
+        result = 31 * result + mJobId;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "UserVisibleJobSummary{"
+                + "callingUid=" + mCallingUid
+                + ", sourceUserId=" + mSourceUserId
+                + ", sourcePackageName='" + mSourcePackageName + "'"
+                + ", jobId=" + mJobId
+                + "}";
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mCallingUid);
+        dest.writeInt(mSourceUserId);
+        dest.writeString(mSourcePackageName);
+        dest.writeInt(mJobId);
+    }
+
+    public static final Creator<UserVisibleJobSummary> CREATOR =
+            new Creator<UserVisibleJobSummary>() {
+                @Override
+                public UserVisibleJobSummary createFromParcel(Parcel in) {
+                    return new UserVisibleJobSummary(in);
+                }
+
+                @Override
+                public UserVisibleJobSummary[] newArray(int size) {
+                    return new UserVisibleJobSummary[size];
+                }
+            };
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
index e3bd5ac..e2d302f 100644
--- a/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
+++ b/apex/jobscheduler/service/java/com/android/server/DeviceIdleController.java
@@ -29,6 +29,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.BroadcastOptions;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -314,7 +315,9 @@
     private Sensor mMotionSensor;
     private LocationRequest mLocationRequest;
     private Intent mIdleIntent;
+    private Bundle mIdleIntentOptions;
     private Intent mLightIdleIntent;
+    private Bundle mLightIdleIntentOptions;
     private AnyMotionDetector mAnyMotionDetector;
     private final AppStateTrackerImpl mAppStateTracker;
     @GuardedBy("this")
@@ -1798,10 +1801,12 @@
                     } catch (RemoteException e) {
                     }
                     if (deepChanged) {
-                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL,
+                                null /* receiverPermission */, mIdleIntentOptions);
                     }
                     if (lightChanged) {
-                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
+                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,
+                                null /* receiverPermission */, mLightIdleIntentOptions);
                     }
                     EventLogTags.writeDeviceIdleOnComplete();
                     mGoingIdleWakeLock.release();
@@ -1821,13 +1826,13 @@
                         incActiveIdleOps();
                         mLocalActivityManager.broadcastIntentWithCallback(mIdleIntent,
                                 mIdleStartedDoneReceiver, null, UserHandle.USER_ALL,
-                                null, null, null);
+                                null, null, mIdleIntentOptions);
                     }
                     if (lightChanged) {
                         incActiveIdleOps();
                         mLocalActivityManager.broadcastIntentWithCallback(mLightIdleIntent,
                                 mIdleStartedDoneReceiver, null, UserHandle.USER_ALL,
-                                null, null, null);
+                                null, null, mLightIdleIntentOptions);
                     }
                     // Always start with one active op for the message being sent here.
                     // Now we are done!
@@ -1849,10 +1854,12 @@
                     } catch (RemoteException e) {
                     }
                     if (deepChanged) {
-                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL,
+                                null /* receiverPermission */, mIdleIntentOptions);
                     }
                     if (lightChanged) {
-                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL);
+                        getContext().sendBroadcastAsUser(mLightIdleIntent, UserHandle.ALL,
+                                null /* receiverPermission */, mLightIdleIntentOptions);
                     }
                     EventLogTags.writeDeviceIdleOffComplete();
                 } break;
@@ -2531,6 +2538,9 @@
                 mLightIdleIntent = new Intent(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
                 mLightIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
                         | Intent.FLAG_RECEIVER_FOREGROUND);
+                final BroadcastOptions options = BroadcastOptions.makeBasic();
+                options.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+                mIdleIntentOptions = mLightIdleIntentOptions = options.toBundle();
 
                 IntentFilter filter = new IntentFilter();
                 filter.addAction(Intent.ACTION_BATTERY_CHANGED);
@@ -4811,6 +4821,9 @@
                     Binder.restoreCallingIdentity(token);
                 }
             } else {
+                if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+                    return -1;
+                }
                 synchronized (this) {
                     for (int j=0; j<mPowerSaveWhitelistAppsExceptIdle.size(); j++) {
                         pw.print("system-excidle,");
@@ -4872,6 +4885,9 @@
                 pw.println("[-r] requires a package name");
                 return -1;
             } else {
+                if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+                    return -1;
+                }
                 dumpTempWhitelistSchedule(pw, false);
             }
         } else if ("except-idle-whitelist".equals(cmd)) {
@@ -4947,6 +4963,9 @@
                     Binder.restoreCallingIdentity(token);
                 }
             } else {
+                if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
+                    return -1;
+                }
                 synchronized (this) {
                     for (int j = 0; j < mPowerSaveWhitelistApps.size(); j++) {
                         pw.print(mPowerSaveWhitelistApps.keyAt(j));
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
index c2602f2..145ac52 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobStore.java
@@ -412,6 +412,14 @@
 
     /** Version of the db schema. */
     private static final int JOBS_FILE_VERSION = 1;
+    /**
+     * For legacy reasons, this tag is used to encapsulate the entire job list.
+     */
+    private static final String XML_TAG_JOB_INFO = "job-info";
+    /**
+     * For legacy reasons, this tag represents a single {@link JobStatus} object.
+     */
+    private static final String XML_TAG_JOB = "job";
     /** Tag corresponds to constraints this job needs. */
     private static final String XML_TAG_PARAMS_CONSTRAINTS = "constraints";
     /** Tag corresponds to execution parameters. */
@@ -645,19 +653,19 @@
                 out.startDocument(null, true);
                 out.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
-                out.startTag(null, "job-info");
+                out.startTag(null, XML_TAG_JOB_INFO);
                 out.attribute(null, "version", Integer.toString(JOBS_FILE_VERSION));
                 for (int i=0; i<jobList.size(); i++) {
                     JobStatus jobStatus = jobList.get(i);
                     if (DEBUG) {
                         Slog.d(TAG, "Saving job " + jobStatus.getJobId());
                     }
-                    out.startTag(null, "job");
+                    out.startTag(null, XML_TAG_JOB);
                     addAttributesToJobTag(out, jobStatus);
                     writeConstraintsToXml(out, jobStatus);
                     writeExecutionCriteriaToXml(out, jobStatus);
                     writeBundleToXml(jobStatus.getJob().getExtras(), out);
-                    out.endTag(null, "job");
+                    out.endTag(null, XML_TAG_JOB);
 
                     numJobs++;
                     if (jobStatus.getUid() == Process.SYSTEM_UID) {
@@ -667,7 +675,7 @@
                         }
                     }
                 }
-                out.endTag(null, "job-info");
+                out.endTag(null, XML_TAG_JOB_INFO);
                 out.endDocument();
 
                 file.finishWrite(fos);
@@ -903,17 +911,17 @@
                 return;
             }
             boolean needFileMigration = false;
-            long now = sElapsedRealtimeClock.millis();
+            long nowElapsed = sElapsedRealtimeClock.millis();
             for (File file : files) {
                 final AtomicFile aFile = createJobFile(file);
                 try (FileInputStream fis = aFile.openRead()) {
                     synchronized (mLock) {
-                        jobs = readJobMapImpl(fis, rtcGood);
+                        jobs = readJobMapImpl(fis, rtcGood, nowElapsed);
                         if (jobs != null) {
                             for (int i = 0; i < jobs.size(); i++) {
                                 JobStatus js = jobs.get(i);
                                 js.prepareLocked();
-                                js.enqueueTime = now;
+                                js.enqueueTime = nowElapsed;
                                 this.jobSet.add(js);
 
                                 numJobs++;
@@ -959,7 +967,7 @@
             }
         }
 
-        private List<JobStatus> readJobMapImpl(InputStream fis, boolean rtcIsGood)
+        private List<JobStatus> readJobMapImpl(InputStream fis, boolean rtcIsGood, long nowElapsed)
                 throws XmlPullParserException, IOException {
             TypedXmlPullParser parser = Xml.resolvePullParser(fis);
 
@@ -977,28 +985,24 @@
             }
 
             String tagName = parser.getName();
-            if ("job-info".equals(tagName)) {
+            if (XML_TAG_JOB_INFO.equals(tagName)) {
                 final List<JobStatus> jobs = new ArrayList<JobStatus>();
-                final int version;
+                final int version = parser.getAttributeInt(null, "version");
                 // Read in version info.
-                try {
-                    version = Integer.parseInt(parser.getAttributeValue(null, "version"));
-                    if (version > JOBS_FILE_VERSION || version < 0) {
-                        Slog.d(TAG, "Invalid version number, aborting jobs file read.");
-                        return null;
-                    }
-                } catch (NumberFormatException e) {
-                    Slog.e(TAG, "Invalid version number, aborting jobs file read.");
+                if (version > JOBS_FILE_VERSION || version < 0) {
+                    Slog.d(TAG, "Invalid version number, aborting jobs file read.");
                     return null;
                 }
+
                 eventType = parser.next();
                 do {
                     // Read each <job/>
                     if (eventType == XmlPullParser.START_TAG) {
                         tagName = parser.getName();
                         // Start reading job.
-                        if ("job".equals(tagName)) {
-                            JobStatus persistedJob = restoreJobFromXml(rtcIsGood, parser, version);
+                        if (XML_TAG_JOB.equals(tagName)) {
+                            JobStatus persistedJob =
+                                    restoreJobFromXml(rtcIsGood, parser, version, nowElapsed);
                             if (persistedJob != null) {
                                 if (DEBUG) {
                                     Slog.d(TAG, "Read out " + persistedJob);
@@ -1022,7 +1026,7 @@
          * @return Newly instantiated job holding all the information we just read out of the xml tag.
          */
         private JobStatus restoreJobFromXml(boolean rtcIsGood, TypedXmlPullParser parser,
-                int schemaVersion) throws XmlPullParserException, IOException {
+                int schemaVersion, long nowElapsed) throws XmlPullParserException, IOException {
             JobInfo.Builder jobBuilder;
             int uid, sourceUserId;
             long lastSuccessfulRunTime;
@@ -1113,18 +1117,9 @@
             }
 
             // Tuple of (earliest runtime, latest runtime) in UTC.
-            final Pair<Long, Long> rtcRuntimes;
-            try {
-                rtcRuntimes = buildRtcExecutionTimesFromXml(parser);
-            } catch (NumberFormatException e) {
-                if (DEBUG) {
-                    Slog.d(TAG, "Error parsing execution time parameters, skipping.");
-                }
-                return null;
-            }
+            final Pair<Long, Long> rtcRuntimes = buildRtcExecutionTimesFromXml(parser);
 
-            final long elapsedNow = sElapsedRealtimeClock.millis();
-            Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(rtcRuntimes, elapsedNow);
+            Pair<Long, Long> elapsedRuntimes = convertRtcBoundsToElapsed(rtcRuntimes, nowElapsed);
 
             if (XML_TAG_PERIODIC.equals(parser.getName())) {
                 try {
@@ -1137,8 +1132,8 @@
                     // from now. This is the latest the periodic could be pushed out. This could
                     // happen if the periodic ran early (at flex time before period), and then the
                     // device rebooted.
-                    if (elapsedRuntimes.second > elapsedNow + periodMillis + flexMillis) {
-                        final long clampedLateRuntimeElapsed = elapsedNow + flexMillis
+                    if (elapsedRuntimes.second > nowElapsed + periodMillis + flexMillis) {
+                        final long clampedLateRuntimeElapsed = nowElapsed + flexMillis
                                 + periodMillis;
                         final long clampedEarlyRuntimeElapsed = clampedLateRuntimeElapsed
                                 - flexMillis;
@@ -1163,11 +1158,11 @@
             } else if (XML_TAG_ONEOFF.equals(parser.getName())) {
                 try {
                     if (elapsedRuntimes.first != JobStatus.NO_EARLIEST_RUNTIME) {
-                        jobBuilder.setMinimumLatency(elapsedRuntimes.first - elapsedNow);
+                        jobBuilder.setMinimumLatency(elapsedRuntimes.first - nowElapsed);
                     }
                     if (elapsedRuntimes.second != JobStatus.NO_LATEST_RUNTIME) {
                         jobBuilder.setOverrideDeadline(
-                                elapsedRuntimes.second - elapsedNow);
+                                elapsedRuntimes.second - nowElapsed);
                     }
                 } catch (NumberFormatException e) {
                     Slog.d(TAG, "Error reading job execution criteria, skipping.");
@@ -1236,7 +1231,7 @@
 
             // And now we're done
             final int appBucket = JobSchedulerService.standbyBucketForPackage(sourcePackageName,
-                    sourceUserId, elapsedNow);
+                    sourceUserId, nowElapsed);
             JobStatus js = new JobStatus(
                     builtJob, uid, sourcePackageName, sourceUserId,
                     appBucket, sourceTag,
@@ -1246,9 +1241,10 @@
             return js;
         }
 
-        private JobInfo.Builder buildBuilderFromXml(XmlPullParser parser) throws NumberFormatException {
+        private JobInfo.Builder buildBuilderFromXml(TypedXmlPullParser parser)
+                throws XmlPullParserException {
             // Pull out required fields from <job> attributes.
-            int jobId = Integer.parseInt(parser.getAttributeValue(null, "jobid"));
+            int jobId = parser.getAttributeInt(null, "jobid");
             String packageName = parser.getAttributeValue(null, "package");
             String className = parser.getAttributeValue(null, "class");
             ComponentName cname = new ComponentName(packageName, className);
@@ -1405,20 +1401,13 @@
          * @return A Pair of timestamps in UTC wall-clock time.  The first is the earliest
          *     time at which the job is to become runnable, and the second is the deadline at
          *     which it becomes overdue to execute.
-         * @throws NumberFormatException
          */
-        private Pair<Long, Long> buildRtcExecutionTimesFromXml(XmlPullParser parser)
-                throws NumberFormatException {
-            String val;
+        private Pair<Long, Long> buildRtcExecutionTimesFromXml(TypedXmlPullParser parser) {
             // Pull out execution time data.
-            val = parser.getAttributeValue(null, "delay");
-            final long earliestRunTimeRtc = (val != null)
-                    ? Long.parseLong(val)
-                    : JobStatus.NO_EARLIEST_RUNTIME;
-            val = parser.getAttributeValue(null, "deadline");
-            final long latestRunTimeRtc = (val != null)
-                    ? Long.parseLong(val)
-                    : JobStatus.NO_LATEST_RUNTIME;
+            final long earliestRunTimeRtc =
+                    parser.getAttributeLong(null, "delay", JobStatus.NO_EARLIEST_RUNTIME);
+            final long latestRunTimeRtc =
+                    parser.getAttributeLong(null, "deadline", JobStatus.NO_LATEST_RUNTIME);
             return Pair.create(earliestRunTimeRtc, latestRunTimeRtc);
         }
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
index abc196f..b84c8a4 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Agent.java
@@ -286,7 +286,7 @@
 
         for (int i = 0; i < pkgNames.size(); ++i) {
             final String pkgName = pkgNames.valueAt(i);
-            final boolean isVip = mIrs.isVip(userId, pkgName);
+            final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
             SparseArrayMap<String, OngoingEvent> ongoingEvents =
                     mCurrentOngoingEvents.get(userId, pkgName);
             if (ongoingEvents != null) {
@@ -321,7 +321,7 @@
         final long nowElapsed = SystemClock.elapsedRealtime();
         final CompleteEconomicPolicy economicPolicy = mIrs.getCompleteEconomicPolicyLocked();
 
-        final boolean isVip = mIrs.isVip(userId, pkgName);
+        final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
         SparseArrayMap<String, OngoingEvent> ongoingEvents =
                 mCurrentOngoingEvents.get(userId, pkgName);
         if (ongoingEvents != null) {
@@ -397,7 +397,7 @@
                 if (actionAffordabilityNotes != null) {
                     final int size = actionAffordabilityNotes.size();
                     final long newBalance = getBalanceLocked(userId, pkgName);
-                    final boolean isVip = mIrs.isVip(userId, pkgName);
+                    final boolean isVip = mIrs.isVip(userId, pkgName, nowElapsed);
                     for (int n = 0; n < size; ++n) {
                         final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(n);
                         note.recalculateCosts(economicPolicy, userId, pkgName);
@@ -503,7 +503,8 @@
                     "Tried to adjust system balance for " + appToString(userId, pkgName));
             return;
         }
-        if (mIrs.isVip(userId, pkgName)) {
+        final boolean isVip = mIrs.isVip(userId, pkgName);
+        if (isVip) {
             // This could happen if the app was made a VIP after it started performing actions.
             // Continue recording the transaction for debugging purposes, but don't let it change
             // any numbers.
@@ -536,7 +537,6 @@
                     mActionAffordabilityNotes.get(userId, pkgName);
             if (actionAffordabilityNotes != null) {
                 final long newBalance = ledger.getCurrentBalance();
-                final boolean isVip = mIrs.isVip(userId, pkgName);
                 for (int i = 0; i < actionAffordabilityNotes.size(); ++i) {
                     final ActionAffordabilityNote note = actionAffordabilityNotes.valueAt(i);
                     final boolean isAffordable = isVip
@@ -830,7 +830,6 @@
 
     @GuardedBy("mLock")
     void onUserRemovedLocked(final int userId) {
-        mScribe.discardLedgersLocked(userId);
         mCurrentOngoingEvents.delete(userId);
         mBalanceThresholdAlarmQueue.removeAlarmsForUserId(userId);
     }
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
index fcb3e67..1ff389d 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InstalledPackageInfo.java
@@ -16,14 +16,20 @@
 
 package com.android.server.tare;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.AppGlobals;
+import android.content.Context;
+import android.content.PermissionChecker;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.InstallSourceInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.os.RemoteException;
 
+import com.android.internal.util.ArrayUtils;
+
 /** POJO to cache only the information about installed packages that TARE cares about. */
 class InstalledPackageInfo {
     static final int NO_UID = -1;
@@ -31,14 +37,22 @@
     public final int uid;
     public final String packageName;
     public final boolean hasCode;
+    public final boolean isSystemInstaller;
     @Nullable
     public final String installerPackageName;
 
-    InstalledPackageInfo(@NonNull PackageInfo packageInfo) {
+    InstalledPackageInfo(@NonNull Context context, @NonNull PackageInfo packageInfo) {
         final ApplicationInfo applicationInfo = packageInfo.applicationInfo;
         uid = applicationInfo == null ? NO_UID : applicationInfo.uid;
         packageName = packageInfo.packageName;
         hasCode = applicationInfo != null && applicationInfo.hasCode();
+        isSystemInstaller = applicationInfo != null
+                && ArrayUtils.indexOf(
+                packageInfo.requestedPermissions, Manifest.permission.INSTALL_PACKAGES) >= 0
+                && PackageManager.PERMISSION_GRANTED
+                == PermissionChecker.checkPermissionForPreflight(context,
+                Manifest.permission.INSTALL_PACKAGES, PermissionChecker.PID_UNKNOWN,
+                applicationInfo.uid, packageName);
         InstallSourceInfo installSourceInfo = null;
         try {
             installSourceInfo = AppGlobals.getPackageManager().getInstallSourceInfo(packageName);
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
index 17b8746..4001d9b 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/InternalResourceService.java
@@ -64,6 +64,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArrayMap;
+import android.util.SparseLongArray;
 import android.util.SparseSetArray;
 
 import com.android.internal.annotations.GuardedBy;
@@ -108,6 +109,16 @@
     /** The amount of time to delay reclamation by after boot. */
     private static final long RECLAMATION_STARTUP_DELAY_MS = 30_000L;
     /**
+     * The amount of time after TARE has first been set up that a system installer will be allowed
+     * expanded credit privileges.
+     */
+    static final long INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS = 7 * DAY_IN_MILLIS;
+    /**
+     * The amount of time to wait after TARE has first been set up before considering adjusting the
+     * stock/consumption limit.
+     */
+    private static final long STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS = 5 * DAY_IN_MILLIS;
+    /**
      * The battery level above which we may consider quantitative easing (increasing the consumption
      * limit).
      */
@@ -127,7 +138,7 @@
     private static final long STOCK_RECALCULATION_MIN_DATA_DURATION_MS = 8 * HOUR_IN_MILLIS;
     private static final int PACKAGE_QUERY_FLAGS =
             PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
-                    | PackageManager.MATCH_APEX;
+                    | PackageManager.MATCH_APEX | PackageManager.GET_PERMISSIONS;
 
     /** Global lock for all resource economy state. */
     private final Object mLock = new Object();
@@ -179,6 +190,13 @@
     @GuardedBy("mLock")
     private final SparseArrayMap<String, Boolean> mVipOverrides = new SparseArrayMap<>();
 
+    /**
+     * Set of temporary Very Important Packages and when their VIP status ends, in the elapsed
+     * realtime ({@link android.annotation.ElapsedRealtimeLong}) timebase.
+     */
+    @GuardedBy("mLock")
+    private final SparseArrayMap<String, Long> mTemporaryVips = new SparseArrayMap<>();
+
     /** Set of apps each installer is responsible for installing. */
     @GuardedBy("mLock")
     private final SparseArrayMap<String, ArraySet<String>> mInstallers = new SparseArrayMap<>();
@@ -308,6 +326,7 @@
     private static final int MSG_PROCESS_USAGE_EVENT = 2;
     private static final int MSG_NOTIFY_STATE_CHANGE_LISTENERS = 3;
     private static final int MSG_NOTIFY_STATE_CHANGE_LISTENER = 4;
+    private static final int MSG_CLEAN_UP_TEMP_VIP_LIST = 5;
     private static final String ALARM_TAG_WEALTH_RECLAMATION = "*tare.reclamation*";
 
     /**
@@ -413,6 +432,13 @@
         return userPkgs;
     }
 
+    @Nullable
+    InstalledPackageInfo getInstalledPackageInfo(final int userId, @NonNull final String pkgName) {
+        synchronized (mLock) {
+            return mPkgCache.get(userId, pkgName);
+        }
+    }
+
     @GuardedBy("mLock")
     long getConsumptionLimitLocked() {
         return mCurrentBatteryLevel * mScribe.getSatiatedConsumptionLimitLocked() / 100;
@@ -429,6 +455,11 @@
         return mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit();
     }
 
+
+    long getRealtimeSinceFirstSetupMs() {
+        return mScribe.getRealtimeSinceFirstSetupMs(SystemClock.elapsedRealtime());
+    }
+
     int getUid(final int userId, @NonNull final String pkgName) {
         synchronized (mPackageToUidCache) {
             Integer uid = mPackageToUidCache.get(userId, pkgName);
@@ -470,6 +501,10 @@
     }
 
     boolean isVip(final int userId, @NonNull String pkgName) {
+        return isVip(userId, pkgName, SystemClock.elapsedRealtime());
+    }
+
+    boolean isVip(final int userId, @NonNull String pkgName, final long nowElapsed) {
         synchronized (mLock) {
             final Boolean override = mVipOverrides.get(userId, pkgName);
             if (override != null) {
@@ -481,6 +516,12 @@
             // operate.
             return true;
         }
+        synchronized (mLock) {
+            final Long expirationTimeElapsed = mTemporaryVips.get(userId, pkgName);
+            if (expirationTimeElapsed != null) {
+                return nowElapsed <= expirationTimeElapsed;
+            }
+        }
         return false;
     }
 
@@ -569,7 +610,7 @@
             mPackageToUidCache.add(userId, pkgName, uid);
         }
         synchronized (mLock) {
-            final InstalledPackageInfo ipo = new InstalledPackageInfo(packageInfo);
+            final InstalledPackageInfo ipo = new InstalledPackageInfo(getContext(), packageInfo);
             final InstalledPackageInfo oldIpo = mPkgCache.add(userId, pkgName, ipo);
             maybeUpdateInstallerStatusLocked(oldIpo, ipo);
             mUidToPackageCache.add(uid, pkgName);
@@ -626,11 +667,16 @@
             final List<PackageInfo> pkgs =
                     mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
             for (int i = pkgs.size() - 1; i >= 0; --i) {
-                final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i));
+                final InstalledPackageInfo ipo =
+                        new InstalledPackageInfo(getContext(), pkgs.get(i));
                 final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
                 maybeUpdateInstallerStatusLocked(oldIpo, ipo);
             }
             mAgent.grantBirthrightsLocked(userId);
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            mScribe.setUserAddedTimeLocked(userId, nowElapsed);
+            grantInstallersTemporaryVipStatusLocked(userId,
+                    nowElapsed, INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS);
         }
     }
 
@@ -647,6 +693,7 @@
             mInstallers.delete(userId);
             mPkgCache.delete(userId);
             mAgent.onUserRemovedLocked(userId);
+            mScribe.onUserRemovedLocked(userId);
         }
     }
 
@@ -659,6 +706,10 @@
             maybeAdjustDesiredStockLevelLocked();
             return;
         }
+        if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
+            // Things can be very tumultuous soon after first setup.
+            return;
+        }
         // We don't need to increase the limit if the device runs out of consumable credits
         // when the battery is low.
         final long remainingConsumableCakes = mScribe.getRemainingConsumableCakesLocked();
@@ -687,6 +738,10 @@
         if (!mConfigObserver.ENABLE_TIP3) {
             return;
         }
+        if (getRealtimeSinceFirstSetupMs() < STOCK_ADJUSTMENT_FIRST_SETUP_GRACE_PERIOD_MS) {
+            // Things can be very tumultuous soon after first setup.
+            return;
+        }
         // Don't adjust the limit too often or while the battery is low.
         final long now = getCurrentTimeMillis();
         if ((now - mScribe.getLastStockRecalculationTimeLocked()) < STOCK_RECALCULATION_DELAY_MS
@@ -776,6 +831,28 @@
     }
 
     @GuardedBy("mLock")
+    private void grantInstallersTemporaryVipStatusLocked(int userId, long nowElapsed,
+            long grantDurationMs) {
+        final long grantEndTimeElapsed = nowElapsed + grantDurationMs;
+        final int uIdx = mPkgCache.indexOfKey(userId);
+        if (uIdx < 0) {
+            return;
+        }
+        for (int pIdx = mPkgCache.numElementsForKey(uIdx) - 1; pIdx >= 0; --pIdx) {
+            final InstalledPackageInfo ipo = mPkgCache.valueAt(uIdx, pIdx);
+
+            if (ipo.isSystemInstaller) {
+                final Long currentGrantEndTimeElapsed = mTemporaryVips.get(userId, ipo.packageName);
+                if (currentGrantEndTimeElapsed == null
+                        || currentGrantEndTimeElapsed < grantEndTimeElapsed) {
+                    mTemporaryVips.add(userId, ipo.packageName, grantEndTimeElapsed);
+                }
+            }
+        }
+        mHandler.sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST, grantDurationMs);
+    }
+
+    @GuardedBy("mLock")
     private void processUsageEventLocked(final int userId, @NonNull UsageEvents.Event event) {
         if (!mIsEnabled) {
             return;
@@ -870,7 +947,8 @@
             final List<PackageInfo> pkgs =
                     mPackageManager.getInstalledPackagesAsUser(PACKAGE_QUERY_FLAGS, userId);
             for (int i = pkgs.size() - 1; i >= 0; --i) {
-                final InstalledPackageInfo ipo = new InstalledPackageInfo(pkgs.get(i));
+                final InstalledPackageInfo ipo =
+                        new InstalledPackageInfo(getContext(), pkgs.get(i));
                 final InstalledPackageInfo oldIpo = mPkgCache.add(userId, ipo.packageName, ipo);
                 maybeUpdateInstallerStatusLocked(oldIpo, ipo);
             }
@@ -953,11 +1031,17 @@
         synchronized (mLock) {
             mCompleteEconomicPolicy.setup(mConfigObserver.getAllDeviceConfigProperties());
             loadInstalledPackageListLocked();
+            final SparseLongArray timeSinceUsersAdded;
             final boolean isFirstSetup = !mScribe.recordExists();
+            final long nowElapsed = SystemClock.elapsedRealtime();
             if (isFirstSetup) {
                 mAgent.grantBirthrightsLocked();
                 mScribe.setConsumptionLimitLocked(
                         mCompleteEconomicPolicy.getInitialSatiatedConsumptionLimit());
+                // Set the last reclamation time to now so we don't start reclaiming assets
+                // too early.
+                mScribe.setLastReclamationTimeLocked(getCurrentTimeMillis());
+                timeSinceUsersAdded = new SparseLongArray();
             } else {
                 mScribe.loadFromDiskLocked();
                 if (mScribe.getSatiatedConsumptionLimitLocked()
@@ -971,6 +1055,21 @@
                     // Adjust the supply in case battery level changed while the device was off.
                     adjustCreditSupplyLocked(true);
                 }
+                timeSinceUsersAdded = mScribe.getRealtimeSinceUsersAddedLocked(nowElapsed);
+            }
+
+            final int[] userIds = LocalServices.getService(UserManagerInternal.class).getUserIds();
+            for (int userId : userIds) {
+                final long timeSinceUserAddedMs = timeSinceUsersAdded.get(userId, 0);
+                // Temporarily mark installers as VIPs so they aren't subject to credit
+                // limits and policies on first boot.
+                if (timeSinceUserAddedMs < INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS) {
+                    final long remainingGraceDurationMs =
+                            INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS - timeSinceUserAddedMs;
+
+                    grantInstallersTemporaryVipStatusLocked(userId, nowElapsed,
+                            remainingGraceDurationMs);
+                }
             }
             scheduleUnusedWealthReclamationLocked();
         }
@@ -1079,6 +1178,36 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
+                case MSG_CLEAN_UP_TEMP_VIP_LIST: {
+                    removeMessages(MSG_CLEAN_UP_TEMP_VIP_LIST);
+
+                    synchronized (mLock) {
+                        final long nowElapsed = SystemClock.elapsedRealtime();
+
+                        long earliestExpiration = Long.MAX_VALUE;
+                        for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
+                            final int userId = mTemporaryVips.keyAt(u);
+
+                            for (int p = mTemporaryVips.numElementsForKeyAt(u) - 1; p >= 0; --p) {
+                                final String pkgName = mTemporaryVips.keyAt(u, p);
+                                final Long expiration = mTemporaryVips.valueAt(u, p);
+
+                                if (expiration == null || expiration < nowElapsed) {
+                                    mTemporaryVips.delete(userId, pkgName);
+                                } else {
+                                    earliestExpiration = Math.min(earliestExpiration, expiration);
+                                }
+                            }
+                        }
+
+                        if (earliestExpiration < Long.MAX_VALUE) {
+                            sendEmptyMessageDelayed(MSG_CLEAN_UP_TEMP_VIP_LIST,
+                                    earliestExpiration - nowElapsed);
+                        }
+                    }
+                }
+                break;
+
                 case MSG_NOTIFY_AFFORDABILITY_CHANGE_LISTENER: {
                     final SomeArgs args = (SomeArgs) msg.obj;
                     final int userId = args.argi1;
@@ -1558,6 +1687,7 @@
             boolean printedVips = false;
             pw.println();
             pw.print("VIPs:");
+            pw.increaseIndent();
             for (int u = 0; u < mVipOverrides.numMaps(); ++u) {
                 final int userId = mVipOverrides.keyAt(u);
 
@@ -1576,6 +1706,32 @@
             } else {
                 pw.print(" None");
             }
+            pw.decreaseIndent();
+            pw.println();
+
+            boolean printedTempVips = false;
+            pw.println();
+            pw.print("Temp VIPs:");
+            pw.increaseIndent();
+            for (int u = 0; u < mTemporaryVips.numMaps(); ++u) {
+                final int userId = mTemporaryVips.keyAt(u);
+
+                for (int p = 0; p < mTemporaryVips.numElementsForKeyAt(u); ++p) {
+                    final String pkgName = mTemporaryVips.keyAt(u, p);
+
+                    printedTempVips = true;
+                    pw.println();
+                    pw.print(appToString(userId, pkgName));
+                    pw.print("=");
+                    pw.print(mTemporaryVips.valueAt(u, p));
+                }
+            }
+            if (printedTempVips) {
+                pw.println();
+            } else {
+                pw.print(" None");
+            }
+            pw.decreaseIndent();
             pw.println();
 
             pw.println();
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
index 7cf459c..c2a6e43 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/JobSchedulerEconomicPolicy.java
@@ -117,6 +117,7 @@
 import static com.android.server.tare.Modifier.COST_MODIFIER_DEVICE_IDLE;
 import static com.android.server.tare.Modifier.COST_MODIFIER_POWER_SAVE_MODE;
 import static com.android.server.tare.Modifier.COST_MODIFIER_PROCESS_STATE;
+import static com.android.server.tare.TareUtils.appToString;
 import static com.android.server.tare.TareUtils.cakeToString;
 
 import android.annotation.NonNull;
@@ -210,6 +211,22 @@
         if (mIrs.isPackageRestricted(userId, pkgName)) {
             return 0;
         }
+        final InstalledPackageInfo ipo = mIrs.getInstalledPackageInfo(userId, pkgName);
+        if (ipo == null) {
+            Slog.wtfStack(TAG,
+                    "Tried to get max balance of invalid app: " + appToString(userId, pkgName));
+        } else {
+            // A system installer's max balance is elevated for some time after first boot so
+            // they can use jobs to download and install apps.
+            if (ipo.isSystemInstaller) {
+                final long timeSinceFirstSetupMs = mIrs.getRealtimeSinceFirstSetupMs();
+                final boolean stillExempted = timeSinceFirstSetupMs
+                        < InternalResourceService.INSTALLER_FIRST_SETUP_GRACE_PERIOD_MS;
+                if (stillExempted) {
+                    return mMaxSatiatedConsumptionLimit;
+                }
+            }
+        }
         return mMaxSatiatedBalance;
     }
 
diff --git a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
index ee448b5..b41c0d1 100644
--- a/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
+++ b/apex/jobscheduler/service/java/com/android/server/tare/Scribe.java
@@ -24,6 +24,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.Environment;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.AtomicFile;
@@ -33,6 +34,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseArrayMap;
+import android.util.SparseLongArray;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -88,6 +90,7 @@
             "lastStockRecalculationTime";
     private static final String XML_ATTR_REMAINING_CONSUMABLE_CAKES = "remainingConsumableCakes";
     private static final String XML_ATTR_CONSUMPTION_LIMIT = "consumptionLimit";
+    private static final String XML_ATTR_TIME_SINCE_FIRST_SETUP_MS = "timeSinceFirstSetup";
     private static final String XML_ATTR_PR_DISCHARGE = "discharge";
     private static final String XML_ATTR_PR_BATTERY_LEVEL = "batteryLevel";
     private static final String XML_ATTR_PR_PROFIT = "profit";
@@ -112,6 +115,11 @@
     private final InternalResourceService mIrs;
     private final Analyst mAnalyst;
 
+    /**
+     * The value of elapsed realtime since TARE was first setup that was read from disk.
+     * This will only be changed when the persisted file is read.
+     */
+    private long mLoadedTimeSinceFirstSetup;
     @GuardedBy("mIrs.getLock()")
     private long mLastReclamationTime;
     @GuardedBy("mIrs.getLock()")
@@ -122,6 +130,9 @@
     private long mRemainingConsumableCakes;
     @GuardedBy("mIrs.getLock()")
     private final SparseArrayMap<String, Ledger> mLedgers = new SparseArrayMap<>();
+    /** Offsets used to calculate the total realtime since each user was added. */
+    @GuardedBy("mIrs.getLock()")
+    private final SparseLongArray mRealtimeSinceUsersAddedOffsets = new SparseLongArray();
 
     private final Runnable mCleanRunnable = this::cleanupLedgers;
     private final Runnable mWriteRunnable = this::writeState;
@@ -163,8 +174,9 @@
     }
 
     @GuardedBy("mIrs.getLock()")
-    void discardLedgersLocked(final int userId) {
+    void onUserRemovedLocked(final int userId) {
         mLedgers.delete(userId);
+        mRealtimeSinceUsersAddedOffsets.delete(userId);
         postWrite();
     }
 
@@ -215,6 +227,11 @@
         return sum;
     }
 
+    /** Returns the cumulative elapsed realtime since TARE was first setup. */
+    long getRealtimeSinceFirstSetupMs(long nowElapsed) {
+        return mLoadedTimeSinceFirstSetup + nowElapsed;
+    }
+
     /** Returns the total amount of cakes that remain to be consumed. */
     @GuardedBy("mIrs.getLock()")
     long getRemainingConsumableCakesLocked() {
@@ -222,6 +239,16 @@
     }
 
     @GuardedBy("mIrs.getLock()")
+    SparseLongArray getRealtimeSinceUsersAddedLocked(long nowElapsed) {
+        final SparseLongArray realtimes = new SparseLongArray();
+        for (int i = mRealtimeSinceUsersAddedOffsets.size() - 1; i >= 0; --i) {
+            realtimes.put(mRealtimeSinceUsersAddedOffsets.keyAt(i),
+                    mRealtimeSinceUsersAddedOffsets.valueAt(i) + nowElapsed);
+        }
+        return realtimes;
+    }
+
+    @GuardedBy("mIrs.getLock()")
     void loadFromDiskLocked() {
         mLedgers.clear();
         if (!recordExists()) {
@@ -276,7 +303,8 @@
                 }
             }
 
-            final long endTimeCutoff = System.currentTimeMillis() - MAX_TRANSACTION_AGE_MS;
+            final long now = System.currentTimeMillis();
+            final long endTimeCutoff = now - MAX_TRANSACTION_AGE_MS;
             long earliestEndTime = Long.MAX_VALUE;
             for (eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
                     eventType = parser.next()) {
@@ -294,6 +322,12 @@
                                 parser.getAttributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME);
                         mLastStockRecalculationTime = parser.getAttributeLong(null,
                                 XML_ATTR_LAST_STOCK_RECALCULATION_TIME, 0);
+                        mLoadedTimeSinceFirstSetup =
+                                parser.getAttributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
+                                        // If there's no recorded time since first setup, then
+                                        // offset the current elapsed time so it doesn't shift the
+                                        // timing too much.
+                                        -SystemClock.elapsedRealtime());
                         mSatiatedConsumptionLimit =
                                 parser.getAttributeLong(null, XML_ATTR_CONSUMPTION_LIMIT,
                                         mIrs.getInitialSatiatedConsumptionLimitLocked());
@@ -356,6 +390,13 @@
     }
 
     @GuardedBy("mIrs.getLock()")
+    void setUserAddedTimeLocked(int userId, long timeElapsed) {
+        // Use the current time as an offset so that when we persist the time, it correctly persists
+        // as "time since now".
+        mRealtimeSinceUsersAddedOffsets.put(userId, -timeElapsed);
+    }
+
+    @GuardedBy("mIrs.getLock()")
     void tearDownLocked() {
         TareHandlerThread.getHandler().removeCallbacks(mCleanRunnable);
         TareHandlerThread.getHandler().removeCallbacks(mWriteRunnable);
@@ -486,6 +527,14 @@
             // Don't return early since we need to go through all the ledger tags and get to the end
             // of the user tag.
         }
+        if (curUser != UserHandle.USER_NULL) {
+            mRealtimeSinceUsersAddedOffsets.put(curUser,
+                            parser.getAttributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
+                                    // If there's no recorded time since first setup, then
+                                    // offset the current elapsed time so it doesn't shift the
+                                    // timing too much.
+                                    -SystemClock.elapsedRealtime()));
+        }
         long earliestEndTime = Long.MAX_VALUE;
 
         for (int eventType = parser.next(); eventType != XmlPullParser.END_DOCUMENT;
@@ -630,6 +679,8 @@
                 out.attributeLong(null, XML_ATTR_LAST_RECLAMATION_TIME, mLastReclamationTime);
                 out.attributeLong(null,
                         XML_ATTR_LAST_STOCK_RECALCULATION_TIME, mLastStockRecalculationTime);
+                out.attributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
+                        mLoadedTimeSinceFirstSetup + SystemClock.elapsedRealtime());
                 out.attributeLong(null, XML_ATTR_CONSUMPTION_LIMIT, mSatiatedConsumptionLimit);
                 out.attributeLong(null, XML_ATTR_REMAINING_CONSUMABLE_CAKES,
                         mRemainingConsumableCakes);
@@ -665,6 +716,9 @@
 
         out.startTag(null, XML_TAG_USER);
         out.attributeInt(null, XML_ATTR_USER_ID, userId);
+        out.attributeLong(null, XML_ATTR_TIME_SINCE_FIRST_SETUP_MS,
+                mRealtimeSinceUsersAddedOffsets.get(userId,
+                        mLoadedTimeSinceFirstSetup + SystemClock.elapsedRealtime()));
         for (int pIdx = mLedgers.numElementsForKey(userId) - 1; pIdx >= 0; --pIdx) {
             final String pkgName = mLedgers.keyAt(uIdx, pIdx);
             final Ledger ledger = mLedgers.get(userId, pkgName);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 67d711c..b1c8b51 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -63,6 +63,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
+import android.app.AppOpsManager;
 import android.app.usage.AppStandbyInfo;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManager.ForcedReasons;
@@ -108,6 +109,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.SparseLongArray;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -116,6 +118,8 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.ConcurrentUtils;
@@ -279,6 +283,13 @@
     @GuardedBy("mPendingIdleStateChecks")
     private final SparseLongArray mPendingIdleStateChecks = new SparseLongArray();
 
+    /**
+     * Map of uids to their current app-op mode for
+     * {@link AppOpsManager#OPSTR_SYSTEM_EXEMPT_FROM_APP_STANDBY}.
+     */
+    @GuardedBy("mSystemExemptionAppOpMode")
+    private final SparseIntArray mSystemExemptionAppOpMode = new SparseIntArray();
+
     // Cache the active network scorer queried from the network scorer service
     private volatile String mCachedNetworkScorer = null;
     // The last time the network scorer service was queried
@@ -488,6 +499,7 @@
 
     private AppWidgetManager mAppWidgetManager;
     private PackageManager mPackageManager;
+    private AppOpsManager mAppOpsManager;
     Injector mInjector;
 
     private static class Pool<T> {
@@ -647,6 +659,28 @@
             settingsObserver.start();
 
             mAppWidgetManager = mContext.getSystemService(AppWidgetManager.class);
+            mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
+            IAppOpsService iAppOpsService = mInjector.getAppOpsService();
+            try {
+                iAppOpsService.startWatchingMode(
+                        AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY,
+                        /*packageName=*/ null,
+                        new IAppOpsCallback.Stub() {
+                            @Override
+                            public void opChanged(int op, int uid, String packageName) {
+                                final int userId = UserHandle.getUserId(uid);
+                                synchronized (mSystemExemptionAppOpMode) {
+                                    mSystemExemptionAppOpMode.delete(uid);
+                                }
+                                mHandler.obtainMessage(
+                                        MSG_CHECK_PACKAGE_IDLE_STATE, userId, uid, packageName)
+                                        .sendToTarget();
+                            }
+                        });
+            } catch (RemoteException e) {
+                // Should not happen.
+                Slog.wtf(TAG, "Failed start watching for app op", e);
+            }
 
             mInjector.registerDisplayListener(mDisplayListener, mHandler);
             synchronized (mAppIdleLock) {
@@ -1417,6 +1451,23 @@
                 return STANDBY_BUCKET_EXEMPTED;
             }
 
+            final int uid = UserHandle.getUid(userId, appId);
+            synchronized (mSystemExemptionAppOpMode) {
+                if (mSystemExemptionAppOpMode.indexOfKey(uid) >= 0) {
+                    if (mSystemExemptionAppOpMode.get(uid)
+                            == AppOpsManager.MODE_ALLOWED) {
+                        return STANDBY_BUCKET_EXEMPTED;
+                    }
+                } else {
+                    int mode = mAppOpsManager.checkOpNoThrow(
+                            AppOpsManager.OP_SYSTEM_EXEMPT_FROM_APP_STANDBY, uid, packageName);
+                    mSystemExemptionAppOpMode.put(uid, mode);
+                    if (mode == AppOpsManager.MODE_ALLOWED) {
+                        return STANDBY_BUCKET_EXEMPTED;
+                    }
+                }
+            }
+
             if (mAppWidgetManager != null
                     && mInjector.isBoundWidgetPackage(mAppWidgetManager, packageName, userId)) {
                 return STANDBY_BUCKET_ACTIVE;
@@ -2129,6 +2180,12 @@
                     clearAppIdleForPackage(pkgName, userId);
                 }
             }
+            synchronized (mSystemExemptionAppOpMode) {
+                if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
+                    mSystemExemptionAppOpMode.delete(UserHandle.getUid(userId, getAppId(pkgName)));
+                }
+            }
+
         }
     }
 
@@ -2524,6 +2581,11 @@
             }
         }
 
+        IAppOpsService getAppOpsService() {
+            return IAppOpsService.Stub.asInterface(
+                    ServiceManager.getService(Context.APP_OPS_SERVICE));
+        }
+
         /**
          * Returns {@code true} if the supplied package is the wellbeing app. Otherwise,
          * returns {@code false}.
diff --git a/api/api.go b/api/api.go
index ba0fdc1..c91ff81 100644
--- a/api/api.go
+++ b/api/api.go
@@ -36,6 +36,8 @@
 // built against module_current SDK). Instead they are directly statically
 // linked into the all-framework-module-lib, which is building against hidden
 // APIs.
+// In addition, the modules in this list are allowed to contribute to test APIs
+// stubs.
 var non_updatable_modules = []string{virtualization}
 
 // The intention behind this soong plugin is to generate a number of "merged"
@@ -246,9 +248,33 @@
 }
 
 func createMergedSystemStubs(ctx android.LoadHookContext, modules []string) {
+	// First create the all-updatable-modules-system-stubs
+	{
+		updatable_modules := removeAll(modules, non_updatable_modules)
+		props := libraryProps{}
+		props.Name = proptools.StringPtr("all-updatable-modules-system-stubs")
+		props.Static_libs = transformArray(updatable_modules, "", ".stubs.system")
+		props.Sdk_version = proptools.StringPtr("module_current")
+		props.Visibility = []string{"//frameworks/base"}
+		ctx.CreateModule(java.LibraryFactory, &props)
+	}
+	// Now merge all-updatable-modules-system-stubs and stubs from non-updatable modules
+	// into all-modules-system-stubs.
+	{
+		props := libraryProps{}
+		props.Name = proptools.StringPtr("all-modules-system-stubs")
+		props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.system")
+		props.Static_libs = append(props.Static_libs, "all-updatable-modules-system-stubs")
+		props.Sdk_version = proptools.StringPtr("module_current")
+		props.Visibility = []string{"//frameworks/base"}
+		ctx.CreateModule(java.LibraryFactory, &props)
+	}
+}
+
+func createMergedTestStubsForNonUpdatableModules(ctx android.LoadHookContext) {
 	props := libraryProps{}
-	props.Name = proptools.StringPtr("all-modules-system-stubs")
-	props.Static_libs = transformArray(modules, "", ".stubs.system")
+	props.Name = proptools.StringPtr("all-non-updatable-modules-test-stubs")
+	props.Static_libs = transformArray(non_updatable_modules, "", ".stubs.test")
 	props.Sdk_version = proptools.StringPtr("module_current")
 	props.Visibility = []string{"//frameworks/base"}
 	ctx.CreateModule(java.LibraryFactory, &props)
@@ -360,6 +386,7 @@
 
 	createMergedPublicStubs(ctx, bootclasspath)
 	createMergedSystemStubs(ctx, bootclasspath)
+	createMergedTestStubsForNonUpdatableModules(ctx)
 	createMergedFrameworkModuleLibStubs(ctx, bootclasspath)
 	createMergedFrameworkImpl(ctx, bootclasspath)
 
diff --git a/boot/preloaded-classes b/boot/preloaded-classes
index d8b348e..528ce86 100644
--- a/boot/preloaded-classes
+++ b/boot/preloaded-classes
@@ -9358,8 +9358,8 @@
 android.widget.inline.InlinePresentationSpec$BaseBuilder
 android.widget.inline.InlinePresentationSpec$Builder
 android.widget.inline.InlinePresentationSpec
-android.window.BackEvent$1
-android.window.BackEvent
+android.window.BackMotionEvent$1
+android.window.BackMotionEvent
 android.window.ClientWindowFrames$1
 android.window.ClientWindowFrames
 android.window.CompatOnBackInvokedCallback
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 7a08cbd..5f06c97 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -71,6 +71,7 @@
     host_supported: true,
     srcs: [
         "libidmap2/**/*.cpp",
+        "self_targeting/*.cpp",
     ],
     export_include_dirs: ["include"],
     target: {
diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
index 5e189f2..7b38bd1 100644
--- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
+++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
@@ -39,7 +39,7 @@
   void Write8(uint8_t value);
   void Write16(uint16_t value);
   void Write32(uint32_t value);
-  void WriteString(const StringPiece& value);
+  void WriteString(StringPiece value);
   std::ostream& stream_;
 };
 
diff --git a/cmds/idmap2/include/idmap2/ResourceContainer.h b/cmds/idmap2/include/idmap2/ResourceContainer.h
index 2452ff0..4d28321 100644
--- a/cmds/idmap2/include/idmap2/ResourceContainer.h
+++ b/cmds/idmap2/include/idmap2/ResourceContainer.h
@@ -46,14 +46,6 @@
   ~TargetResourceContainer() override = default;
 };
 
-struct OverlayManifestInfo {
-  std::string package_name;     // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string name;             // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_package;   // NOLINT(misc-non-private-member-variables-in-classes)
-  std::string target_name;      // NOLINT(misc-non-private-member-variables-in-classes)
-  ResourceId resource_mapping;  // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
 struct OverlayData {
   struct ResourceIdValue {
     // The overlay resource id.
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index 2214a83..c2b0abe 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -30,13 +30,13 @@
 #define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
 
 // use typedefs to let the compiler warn us about implicit casts
-using ResourceId = uint32_t;  // 0xpptteeee
+using ResourceId = android::ResourceId;  // 0xpptteeee
 using PackageId = uint8_t;    // pp in 0xpptteeee
 using TypeId = uint8_t;       // tt in 0xpptteeee
 using EntryId = uint16_t;     // eeee in 0xpptteeee
 
-using DataType = uint8_t;    // Res_value::dataType
-using DataValue = uint32_t;  // Res_value::data
+using DataType = android::DataType;    // Res_value::dataType
+using DataValue = android::DataValue;  // Res_value::data
 
 struct TargetValue {
   DataType data_type;
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 4b271a1..8976924 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -38,7 +38,7 @@
   stream_.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
 }
 
-void BinaryStreamVisitor::WriteString(const StringPiece& value) {
+void BinaryStreamVisitor::WriteString(StringPiece value) {
   // pad with null to nearest word boundary;
   size_t padding_size = CalculatePadding(value.size());
   Write32(value.size());
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index d517e29..dd5be21c 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -101,10 +101,10 @@
 }
 
 Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
-  using ConfigMap = std::map<std::string, TargetValue>;
-  using EntryMap = std::map<std::string, ConfigMap>;
-  using TypeMap = std::map<std::string, EntryMap>;
-  using PackageMap = std::map<std::string, TypeMap>;
+  using ConfigMap = std::map<std::string, TargetValue, std::less<>>;
+  using EntryMap = std::map<std::string, ConfigMap, std::less<>>;
+  using TypeMap = std::map<std::string, EntryMap, std::less<>>;
+  using PackageMap = std::map<std::string, TypeMap, std::less<>>;
   PackageMap package_map;
   android::StringPool string_pool;
   for (const auto& res_entry : entries_) {
@@ -116,8 +116,7 @@
       return Error("failed to parse resource name '%s'", res_entry.resource_name.c_str());
     }
 
-    std::string package_name =
-        package_substr.empty() ? target_package_name_ : package_substr.to_string();
+    std::string_view package_name = package_substr.empty() ? target_package_name_ : package_substr;
     if (type_name.empty()) {
       return Error("resource name '%s' missing type name", res_entry.resource_name.c_str());
     }
@@ -133,17 +132,14 @@
                     .first;
     }
 
-    auto type = package->second.find(type_name.to_string());
+    auto type = package->second.find(type_name);
     if (type == package->second.end()) {
-      type =
-          package->second
-              .insert(std::make_pair(type_name.to_string(), EntryMap()))
-              .first;
+      type = package->second.insert(std::make_pair(type_name, EntryMap())).first;
     }
 
-    auto entry = type->second.find(entry_name.to_string());
+    auto entry = type->second.find(entry_name);
     if (entry == type->second.end()) {
-      entry = type->second.insert(std::make_pair(entry_name.to_string(), ConfigMap())).first;
+      entry = type->second.insert(std::make_pair(entry_name, ConfigMap())).first;
     }
 
     auto value = entry->second.find(res_entry.configuration);
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 813dff1..7c0b937 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -317,7 +317,7 @@
   }
 
   std::unique_ptr<IdmapData> data(new IdmapData());
-  data->string_pool_data_ = resource_mapping.GetStringPoolData().to_string();
+  data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData());
   uint32_t inline_value_count = 0;
   std::set<std::string> config_set;
   for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
diff --git a/cmds/idmap2/libidmap2/PolicyUtils.cpp b/cmds/idmap2/libidmap2/PolicyUtils.cpp
index 4e3f54d2..76c70ca 100644
--- a/cmds/idmap2/libidmap2/PolicyUtils.cpp
+++ b/cmds/idmap2/libidmap2/PolicyUtils.cpp
@@ -53,7 +53,7 @@
 
   for (const auto& policy : kPolicyStringToFlag) {
     if ((bitmask & policy.second) != 0) {
-      policies.emplace_back(policy.first.to_string());
+      policies.emplace_back(policy.first);
     }
   }
 
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index bb31c11..b2300ce 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -89,7 +89,7 @@
     // If the overlay supplies a target overlayable name, the resource must belong to the
     // overlayable defined with the specified name to be overlaid.
     return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
-                 overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
+                 overlay_info.target_name.c_str(), (*overlayable_info)->name.data());
   }
 
   // Enforce policy restrictions if the resource is declared as overlayable.
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
new file mode 100644
index 0000000..a8aa033
--- /dev/null
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <sys/stat.h>
+
+#include <fstream>
+#include <optional>
+
+#define LOG_TAG "SelfTargeting"
+
+#include "androidfw/ResourceTypes.h"
+#include "idmap2/BinaryStreamVisitor.h"
+#include "idmap2/FabricatedOverlay.h"
+#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+using android::idmap2::BinaryStreamVisitor;
+using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
+
+namespace android::self_targeting {
+
+constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR;  // u=rw-, g=---, o=---
+
+extern "C" bool
+CreateFrroFile(std::string& out_err_result, const std::string& packageName,
+               const std::string& overlayName, const std::string& targetPackageName,
+               const std::optional<std::string>& targetOverlayable,
+               const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+               const std::string& frro_file_path) {
+    android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
+                                                        targetPackageName);
+    if (targetOverlayable.has_value()) {
+        builder.SetOverlayable(targetOverlayable.value_or(std::string()));
+    }
+    for (const auto& entry_params : entries_params) {
+        const auto dataType = entry_params.data_type;
+        if (entry_params.data_binary_value.has_value()) {
+            builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
+                                     entry_params.configuration);
+        } else  if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
+           builder.SetResourceValue(entry_params.resource_name, dataType,
+                                    entry_params.data_value, entry_params.configuration);
+        } else if (dataType == Res_value::TYPE_STRING) {
+           builder.SetResourceValue(entry_params.resource_name, dataType,
+                                    entry_params.data_string_value , entry_params.configuration);
+        } else {
+            out_err_result = base::StringPrintf("Unsupported data type %d", dataType);
+            return false;
+        }
+    }
+
+    const auto frro = builder.Build();
+    std::ofstream fout(frro_file_path);
+    if (fout.fail()) {
+        out_err_result = base::StringPrintf("open output stream fail %s", std::strerror(errno));
+        return false;
+    }
+    auto result = frro->ToBinaryStream(fout);
+    if (!result) {
+        unlink(frro_file_path.c_str());
+        out_err_result = base::StringPrintf("to stream fail %s", result.GetErrorMessage().c_str());
+        return false;
+    }
+    fout.close();
+    if (fout.fail()) {
+        unlink(frro_file_path.c_str());
+        out_err_result = base::StringPrintf("output stream fail %s", std::strerror(errno));
+        return false;
+    }
+    if (chmod(frro_file_path.c_str(), kIdmapFilePermission) == -1) {
+        out_err_result = base::StringPrintf("Failed to change the file permission %s",
+                                            frro_file_path.c_str());
+        return false;
+    }
+    return true;
+}
+
+static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
+                                        const bool isProduct, const bool isTargetSignature,
+                                        const bool isOdm, const bool isOem) {
+    auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);
+
+    if (isSystem) {
+        fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
+    }
+    if (isVendor) {
+        fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
+    }
+    if (isProduct) {
+        fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
+    }
+    if (isOdm) {
+        fulfilled_policy |= PolicyFlags::ODM_PARTITION;
+    }
+    if (isOem) {
+        fulfilled_policy |= PolicyFlags::OEM_PARTITION;
+    }
+    if (isTargetSignature) {
+        fulfilled_policy |= PolicyFlags::SIGNATURE;
+    }
+
+    // Not support actor_signature and config_overlay_signature
+    fulfilled_policy &=
+            ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);
+
+    ALOGV(
+            "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
+            " isTargetSignature = %d, isOdm = %d, isOem = %d,",
+            fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
+    return fulfilled_policy;
+}
+
+extern "C" bool
+CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
+                const std::string& idmapPath, const std::string& overlayName,
+                const bool isSystem, const bool isVendor, const bool isProduct,
+                const bool isTargetSignature, const bool isOdm, const bool isOem) {
+    // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
+    // guarantees that existing memory maps will continue to be valid and unaffected. The file must
+    // be deleted before attempting to create the idmap, so that if idmap  creation fails, the
+    // overlay will no longer be usable.
+    unlink(idmapPath.c_str());
+
+    const auto target = idmap2::TargetResourceContainer::FromPath(targetPath);
+    if (!target) {
+        out_err = base::StringPrintf("Failed to load target %s because of %s", targetPath.c_str(),
+                                     target.GetErrorMessage().c_str());
+        return false;
+    }
+
+    const auto overlay = OverlayResourceContainer::FromPath(overlayPath);
+    if (!overlay) {
+        out_err = base::StringPrintf("Failed to load overlay %s because of %s", overlayPath.c_str(),
+                                     overlay.GetErrorMessage().c_str());
+        return false;
+    }
+
+    // Overlay self target process. Only allow self-targeting types.
+    const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
+                                                       isTargetSignature, isOdm, isOem);
+
+    const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
+                                             fulfilled_policies, true /* enforce_overlayable */);
+    if (!idmap) {
+        out_err = base::StringPrintf("Failed to create idmap because of %s",
+                                     idmap.GetErrorMessage().c_str());
+        return false;
+    }
+
+    std::ofstream fout(idmapPath.c_str());
+    if (fout.fail()) {
+        out_err = base::StringPrintf("Failed to create idmap %s because of %s", idmapPath.c_str(),
+                                     strerror(errno));
+        return false;
+    }
+
+    BinaryStreamVisitor visitor(fout);
+    (*idmap)->accept(&visitor);
+    fout.close();
+    if (fout.fail()) {
+        unlink(idmapPath.c_str());
+        out_err = base::StringPrintf("Failed to write idmap %s because of %s", idmapPath.c_str(),
+                                     strerror(errno));
+        return false;
+    }
+    if (chmod(idmapPath.c_str(), kIdmapFilePermission) == -1) {
+        out_err = base::StringPrintf("Failed to change the file permission %s", idmapPath.c_str());
+        return false;
+    }
+    return true;
+}
+
+extern "C" bool
+GetFabricatedOverlayInfo(std::string& out_err, const std::string& overlay_path,
+                         OverlayManifestInfo& out_info) {
+    const auto overlay = idmap2::FabricatedOverlayContainer::FromPath(overlay_path);
+    if (!overlay) {
+        out_err = base::StringPrintf("Failed to write idmap %s because of %s",
+                                     overlay_path.c_str(), strerror(errno));
+        return false;
+    }
+
+    out_info = (*overlay)->GetManifestInfo();
+
+    return true;
+}
+
+}  // namespace android::self_targeting
+
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 7d80493..26e20f6 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -29,12 +29,18 @@
 import java.util.function.Consumer;
 import java.util.concurrent.Executor;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class UsbCommand extends Svc.Command {
     public UsbCommand() {
         super("usb");
     }
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     @Override
     public String shortHelp() {
         return "Control Usb state";
@@ -92,8 +98,10 @@
 
             if ("setFunctions".equals(args[1])) {
                 try {
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    System.out.println("setCurrentFunctions opId:" + operationId);
                     usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString(
-                            args.length >= 3 ? args[2] : ""));
+                            args.length >= 3 ? args[2] : ""), operationId);
                 } catch (RemoteException e) {
                     System.err.println("Error communicating with UsbManager: " + e);
                 }
diff --git a/config/preloaded-classes b/config/preloaded-classes
index f750249..fa60140 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -9389,8 +9389,8 @@
 android.widget.inline.InlinePresentationSpec$BaseBuilder
 android.widget.inline.InlinePresentationSpec$Builder
 android.widget.inline.InlinePresentationSpec
-android.window.BackEvent$1
-android.window.BackEvent
+android.window.BackMotionEvent$1
+android.window.BackMotionEvent
 android.window.ClientWindowFrames$1
 android.window.ClientWindowFrames
 android.window.CompatOnBackInvokedCallback
diff --git a/core/api/current.txt b/core/api/current.txt
index 3af4394..0f34e42 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -94,6 +94,7 @@
     field public static final String FOREGROUND_SERVICE_CAMERA = "android.permission.FOREGROUND_SERVICE_CAMERA";
     field public static final String FOREGROUND_SERVICE_CONNECTED_DEVICE = "android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE";
     field public static final String FOREGROUND_SERVICE_DATA_SYNC = "android.permission.FOREGROUND_SERVICE_DATA_SYNC";
+    field public static final String FOREGROUND_SERVICE_FILE_MANAGEMENT = "android.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT";
     field public static final String FOREGROUND_SERVICE_HEALTH = "android.permission.FOREGROUND_SERVICE_HEALTH";
     field public static final String FOREGROUND_SERVICE_LOCATION = "android.permission.FOREGROUND_SERVICE_LOCATION";
     field public static final String FOREGROUND_SERVICE_MEDIA_PLAYBACK = "android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK";
@@ -1041,6 +1042,7 @@
     field public static final int max = 16843062; // 0x1010136
     field public static final int maxAspectRatio = 16844128; // 0x1010560
     field public static final int maxButtonHeight = 16844029; // 0x10104fd
+    field public static final int maxConcurrentSessionsCount;
     field public static final int maxDate = 16843584; // 0x1010340
     field public static final int maxEms = 16843095; // 0x1010157
     field public static final int maxHeight = 16843040; // 0x1010120
@@ -1260,6 +1262,7 @@
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
+    field public static final int requiredDisplayCategory;
     field public static final int requiredFeature = 16844116; // 0x1010554
     field public static final int requiredForAllUsers = 16843728; // 0x10103d0
     field public static final int requiredNotFeature = 16844117; // 0x1010555
@@ -1507,7 +1510,6 @@
     field public static final int targetCellWidth = 16844340; // 0x1010634
     field public static final int targetClass = 16842799; // 0x101002f
     field @Deprecated public static final int targetDescriptions = 16843680; // 0x10103a0
-    field public static final int targetDisplayCategory;
     field public static final int targetId = 16843740; // 0x10103dc
     field public static final int targetName = 16843853; // 0x101044d
     field public static final int targetPackage = 16842785; // 0x1010021
@@ -3115,6 +3117,7 @@
     method public boolean onGesture(@NonNull android.accessibilityservice.AccessibilityGestureEvent);
     method public abstract void onInterrupt();
     method protected boolean onKeyEvent(android.view.KeyEvent);
+    method public void onMotionEvent(@NonNull android.view.MotionEvent);
     method protected void onServiceConnected();
     method public void onSystemActionsChanged();
     method public final boolean performGlobalAction(int);
@@ -3272,6 +3275,7 @@
     method @Deprecated public String getDescription();
     method public String getId();
     method public int getInteractiveUiTimeoutMillis();
+    method public int getMotionEventSources();
     method public int getNonInteractiveUiTimeoutMillis();
     method public android.content.pm.ResolveInfo getResolveInfo();
     method public String getSettingsActivityName();
@@ -3281,6 +3285,7 @@
     method @Nullable public CharSequence loadIntro(@NonNull android.content.pm.PackageManager);
     method public CharSequence loadSummary(android.content.pm.PackageManager);
     method public void setInteractiveUiTimeoutMillis(@IntRange(from=0) int);
+    method public void setMotionEventSources(int);
     method public void setNonInteractiveUiTimeoutMillis(@IntRange(from=0) int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CAPABILITY_CAN_CONTROL_MAGNIFICATION = 16; // 0x10
@@ -5291,11 +5296,8 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.app.ForegroundServiceStartNotAllowedException> CREATOR;
   }
 
-  public final class ForegroundServiceTypeNotAllowedException extends android.app.ServiceStartNotAllowedException implements android.os.Parcelable {
-    ctor public ForegroundServiceTypeNotAllowedException(@NonNull String);
-    method public int describeContents();
-    method public void writeToParcel(@NonNull android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.app.ForegroundServiceTypeNotAllowedException> CREATOR;
+  public abstract class ForegroundServiceTypeException extends android.app.ServiceStartNotAllowedException {
+    ctor public ForegroundServiceTypeException(@NonNull String);
   }
 
   @Deprecated public class Fragment implements android.content.ComponentCallbacks2 android.view.View.OnCreateContextMenuListener {
@@ -5738,6 +5740,13 @@
     method @Deprecated public void setIntentRedelivery(boolean);
   }
 
+  public final class InvalidForegroundServiceTypeException extends android.app.ForegroundServiceTypeException implements android.os.Parcelable {
+    ctor public InvalidForegroundServiceTypeException(@NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.InvalidForegroundServiceTypeException> CREATOR;
+  }
+
   public class KeyguardManager {
     method @RequiresPermission(android.Manifest.permission.SUBSCRIBE_TO_KEYGUARD_LOCKED_STATE) public void addKeyguardLockedStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.app.KeyguardManager.KeyguardLockedStateListener);
     method @Deprecated public android.content.Intent createConfirmDeviceCredentialIntent(CharSequence, CharSequence);
@@ -5892,6 +5901,13 @@
     method public void showDialog();
   }
 
+  public final class MissingForegroundServiceTypeException extends android.app.ForegroundServiceTypeException implements android.os.Parcelable {
+    ctor public MissingForegroundServiceTypeException(@NonNull String);
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.MissingForegroundServiceTypeException> CREATOR;
+  }
+
   public class NativeActivity extends android.app.Activity implements android.view.InputQueue.Callback android.view.SurfaceHolder.Callback2 android.view.ViewTreeObserver.OnGlobalLayoutListener {
     ctor public NativeActivity();
     method public void onGlobalLayout();
@@ -6957,6 +6973,7 @@
     method @Deprecated public void onStart(android.content.Intent, int);
     method public int onStartCommand(android.content.Intent, int, int);
     method public void onTaskRemoved(android.content.Intent);
+    method public void onTimeout(int);
     method public void onTrimMemory(int);
     method public boolean onUnbind(android.content.Intent);
     method public final void startForeground(int, android.app.Notification);
@@ -8475,31 +8492,19 @@
 
   public abstract class JobService extends android.app.Service {
     ctor public JobService();
-    method public long getTransferredDownloadBytes();
-    method public long getTransferredDownloadBytes(@NonNull android.app.job.JobWorkItem);
-    method public long getTransferredUploadBytes();
-    method public long getTransferredUploadBytes(@NonNull android.app.job.JobWorkItem);
     method public final void jobFinished(android.app.job.JobParameters, boolean);
     method public final android.os.IBinder onBind(android.content.Intent);
     method public abstract boolean onStartJob(android.app.job.JobParameters);
     method public abstract boolean onStopJob(android.app.job.JobParameters);
-    method public final void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, long, long);
-    method public final void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
-    method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, long, long);
-    method public final void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
     field public static final String PERMISSION_BIND = "android.permission.BIND_JOB_SERVICE";
   }
 
   public abstract class JobServiceEngine {
     ctor public JobServiceEngine(android.app.Service);
     method public final android.os.IBinder getBinder();
-    method public long getTransferredDownloadBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem);
-    method public long getTransferredUploadBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem);
     method public void jobFinished(android.app.job.JobParameters, boolean);
     method public abstract boolean onStartJob(android.app.job.JobParameters);
     method public abstract boolean onStopJob(android.app.job.JobParameters);
-    method public void updateEstimatedNetworkBytes(@NonNull android.app.job.JobParameters, @NonNull android.app.job.JobWorkItem, long, long);
-    method public void updateTransferredNetworkBytes(@NonNull android.app.job.JobParameters, @Nullable android.app.job.JobWorkItem, long, long);
   }
 
   public final class JobWorkItem implements android.os.Parcelable {
@@ -11200,10 +11205,10 @@
     field public String parentActivityName;
     field public String permission;
     field public int persistableMode;
+    field @Nullable public String requiredDisplayCategory;
     field public int screenOrientation;
     field public int softInputMode;
     field public String targetActivity;
-    field @Nullable public String targetDisplayCategory;
     field public String taskAffinity;
     field public int theme;
     field public int uiOptions;
@@ -11664,6 +11669,7 @@
 
   public class PackageInstaller {
     method public void abandonSession(int);
+    method public void checkInstallConstraints(@NonNull java.util.List<java.lang.String>, @NonNull android.content.pm.PackageInstaller.InstallConstraints, @NonNull java.util.function.Consumer<android.content.pm.PackageInstaller.InstallConstraintsResult>);
     method public int createSession(@NonNull android.content.pm.PackageInstaller.SessionParams) throws java.io.IOException;
     method @Deprecated @Nullable public android.content.pm.PackageInstaller.SessionInfo getActiveStagedSession();
     method @NonNull public java.util.List<android.content.pm.PackageInstaller.SessionInfo> getActiveStagedSessions();
@@ -11708,6 +11714,35 @@
     field public static final int STATUS_SUCCESS = 0; // 0x0
   }
 
+  public static final class PackageInstaller.InstallConstraints implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isRequireAppNotForeground();
+    method public boolean isRequireAppNotInteracting();
+    method public boolean isRequireAppNotTopVisible();
+    method public boolean isRequireDeviceIdle();
+    method public boolean isRequireNotInCall();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.InstallConstraints> CREATOR;
+    field @NonNull public static final android.content.pm.PackageInstaller.InstallConstraints GENTLE_UPDATE;
+  }
+
+  public static final class PackageInstaller.InstallConstraints.Builder {
+    ctor public PackageInstaller.InstallConstraints.Builder();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints build();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotForeground();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotInteracting();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotTopVisible();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints.Builder requireDeviceIdle();
+    method @NonNull public android.content.pm.PackageInstaller.InstallConstraints.Builder requireNotInCall();
+  }
+
+  public static final class PackageInstaller.InstallConstraintsResult implements android.os.Parcelable {
+    method public int describeContents();
+    method public boolean isAllConstraintsSatisfied();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.InstallConstraintsResult> CREATOR;
+  }
+
   public static final class PackageInstaller.PreapprovalDetails implements android.os.Parcelable {
     method public int describeContents();
     method @Nullable public android.graphics.Bitmap getIcon();
@@ -11736,6 +11771,7 @@
     method @NonNull public int[] getChildSessionIds();
     method @NonNull public String[] getNames() throws java.io.IOException;
     method public int getParentSessionId();
+    method public boolean isKeepApplicationEnabledSetting();
     method public boolean isMultiPackage();
     method public boolean isStaged();
     method @NonNull public java.io.InputStream openRead(@NonNull String) throws java.io.IOException;
@@ -11787,6 +11823,7 @@
     method public boolean hasParentSessionId();
     method public boolean isActive();
     method public boolean isCommitted();
+    method public boolean isKeepApplicationEnabledSetting();
     method public boolean isMultiPackage();
     method public boolean isSealed();
     method public boolean isStaged();
@@ -11819,6 +11856,7 @@
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setInstallScenario(int);
+    method public void setKeepApplicationEnabledSetting();
     method public void setMultiPackage();
     method public void setOriginatingUid(int);
     method public void setOriginatingUri(@Nullable android.net.Uri);
@@ -12433,6 +12471,7 @@
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CAMERA}, anyOf={android.Manifest.permission.CAMERA}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CAMERA = 64; // 0x40
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE}, anyOf={android.Manifest.permission.BLUETOOTH_CONNECT, android.Manifest.permission.CHANGE_NETWORK_STATE, android.Manifest.permission.CHANGE_WIFI_STATE, android.Manifest.permission.CHANGE_WIFI_MULTICAST_STATE, android.Manifest.permission.NFC, android.Manifest.permission.TRANSMIT_IR}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE = 16; // 0x10
     field @Deprecated @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_DATA_SYNC, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC = 1; // 0x1
+    field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT) public static final int FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT = 4096; // 0x1000
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_HEALTH}, anyOf={android.Manifest.permission.ACTIVITY_RECOGNITION, android.Manifest.permission.BODY_SENSORS, android.Manifest.permission.HIGH_SAMPLING_RATE_SENSORS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_HEALTH = 256; // 0x100
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_LOCATION}, anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_LOCATION = 8; // 0x8
     field public static final int FOREGROUND_SERVICE_TYPE_MANIFEST = -1; // 0xffffffff
@@ -12441,9 +12480,10 @@
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_MICROPHONE}, anyOf={android.Manifest.permission.CAPTURE_AUDIO_OUTPUT, android.Manifest.permission.RECORD_AUDIO}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128; // 0x80
     field @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0
     field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL}, anyOf={android.Manifest.permission.MANAGE_OWN_CALLS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4
-    field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200
-    field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000
-    field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400
+    field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200
+    field public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 2048; // 0x800
+    field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000
+    field @RequiresPermission(android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400
     field public int flags;
     field public String permission;
   }
@@ -12983,11 +13023,21 @@
 
 package android.credentials {
 
-  public final class CreateCredentialRequest implements android.os.Parcelable {
-    ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle);
+  public final class ClearCredentialStateRequest implements android.os.Parcelable {
+    ctor public ClearCredentialStateRequest(@NonNull android.os.Bundle);
     method public int describeContents();
     method @NonNull public android.os.Bundle getData();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.credentials.ClearCredentialStateRequest> CREATOR;
+  }
+
+  public final class CreateCredentialRequest implements android.os.Parcelable {
+    ctor public CreateCredentialRequest(@NonNull String, @NonNull android.os.Bundle, @NonNull android.os.Bundle, boolean);
+    method public int describeContents();
+    method @NonNull public android.os.Bundle getCandidateQueryData();
+    method @NonNull public android.os.Bundle getCredentialData();
     method @NonNull public String getType();
+    method public boolean requireSystemProvider();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.credentials.CreateCredentialRequest> CREATOR;
   }
@@ -13010,8 +13060,9 @@
   }
 
   public final class CredentialManager {
-    method public void executeCreateCredential(@NonNull android.credentials.CreateCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CredentialManagerException>);
-    method public void executeGetCredential(@NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.CredentialManagerException>);
+    method public void clearCredentialState(@NonNull android.credentials.ClearCredentialStateRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.credentials.CredentialManagerException>);
+    method public void executeCreateCredential(@NonNull android.credentials.CreateCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.CreateCredentialResponse,android.credentials.CredentialManagerException>);
+    method public void executeGetCredential(@NonNull android.credentials.GetCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<android.credentials.GetCredentialResponse,android.credentials.CredentialManagerException>);
   }
 
   public class CredentialManagerException extends java.lang.Exception {
@@ -13024,10 +13075,11 @@
   }
 
   public final class GetCredentialOption implements android.os.Parcelable {
-    ctor public GetCredentialOption(@NonNull String, @NonNull android.os.Bundle);
+    ctor public GetCredentialOption(@NonNull String, @NonNull android.os.Bundle, boolean);
     method public int describeContents();
     method @NonNull public android.os.Bundle getData();
     method @NonNull public String getType();
+    method public boolean requireSystemProvider();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.credentials.GetCredentialOption> CREATOR;
   }
@@ -15439,7 +15491,6 @@
   }
 
   public static class PathIterator.Segment {
-    ctor public PathIterator.Segment(@NonNull int, @NonNull float[], float);
     method public float getConicWeight();
     method @NonNull public float[] getPoints();
     method @NonNull public int getVerb();
@@ -21968,6 +22019,11 @@
     field public static final int AVCProfileHigh422 = 32; // 0x20
     field public static final int AVCProfileHigh444 = 64; // 0x40
     field public static final int AVCProfileMain = 2; // 0x2
+    field public static final int DTS_HDProfileHRA = 1; // 0x1
+    field public static final int DTS_HDProfileLBR = 2; // 0x2
+    field public static final int DTS_HDProfileMA = 4; // 0x4
+    field public static final int DTS_UHDProfileP1 = 1; // 0x1
+    field public static final int DTS_UHDProfileP2 = 2; // 0x2
     field public static final int DolbyVisionLevel8k30 = 1024; // 0x400
     field public static final int DolbyVisionLevel8k60 = 2048; // 0x800
     field public static final int DolbyVisionLevelFhd24 = 4; // 0x4
@@ -23524,6 +23580,7 @@
     method public void registerRouteCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.RouteCallback, @NonNull android.media.RouteDiscoveryPreference);
     method public void registerTransferCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.MediaRouter2.TransferCallback);
     method public void setOnGetControllerHintsListener(@Nullable android.media.MediaRouter2.OnGetControllerHintsListener);
+    method public void setRouteListingPreference(@Nullable android.media.RouteListingPreference);
     method public void stop();
     method public void transferTo(@NonNull android.media.MediaRoute2Info);
     method public void unregisterControllerCallback(@NonNull android.media.MediaRouter2.ControllerCallback);
@@ -23897,6 +23954,28 @@
     method @NonNull public android.media.RouteDiscoveryPreference.Builder setShouldPerformActiveScan(boolean);
   }
 
+  public final class RouteListingPreference implements android.os.Parcelable {
+    ctor public RouteListingPreference(@NonNull java.util.List<android.media.RouteListingPreference.Item>);
+    method public int describeContents();
+    method @NonNull public java.util.List<android.media.RouteListingPreference.Item> getItems();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteListingPreference> CREATOR;
+  }
+
+  public static final class RouteListingPreference.Item implements android.os.Parcelable {
+    ctor public RouteListingPreference.Item(@NonNull String, int, int);
+    method public int describeContents();
+    method public int getDisableReason();
+    method public int getFlags();
+    method @NonNull public String getRouteId();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteListingPreference.Item> CREATOR;
+    field public static final int DISABLE_REASON_NONE = 0; // 0x0
+    field public static final int DISABLE_REASON_SUBSCRIPTION_REQUIRED = 1; // 0x1
+    field public static final int FLAG_ONGOING_SESSION = 1; // 0x1
+    field public static final int FLAG_SUGGESTED_ROUTE = 2; // 0x2
+  }
+
   public final class RoutingSessionInfo implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public String getClientPackageName();
@@ -32639,7 +32718,6 @@
     method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.QUERY_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.content.pm.UserProperties getUserProperties(@NonNull android.os.UserHandle);
     method public android.os.Bundle getUserRestrictions();
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public android.os.Bundle getUserRestrictions(android.os.UserHandle);
-    method @NonNull @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers();
     method public boolean hasUserRestriction(String);
     method public boolean isDemoUser();
     method public static boolean isHeadlessSystemUserMode();
@@ -32653,7 +32731,6 @@
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public boolean isUserRunningOrStopping(android.os.UserHandle);
     method public boolean isUserUnlocked();
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.INTERACT_ACROSS_USERS"}, conditional=true) public boolean isUserUnlocked(android.os.UserHandle);
-    method public boolean isUserVisible();
     method @RequiresPermission(anyOf={"android.permission.MANAGE_USERS", "android.permission.MODIFY_QUIET_MODE"}, conditional=true) public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle);
     method public boolean requestQuietModeEnabled(boolean, @NonNull android.os.UserHandle, int);
     method @Deprecated public boolean setRestrictionsChallenge(String);
@@ -35852,6 +35929,7 @@
     method public static boolean canDrawOverlays(android.content.Context);
     field public static final String ACTION_ACCESSIBILITY_SETTINGS = "android.settings.ACCESSIBILITY_SETTINGS";
     field public static final String ACTION_ADD_ACCOUNT = "android.settings.ADD_ACCOUNT_SETTINGS";
+    field public static final String ACTION_ADVANCED_MEMORY_PROTECTION_SETTINGS = "android.settings.ADVANCED_MEMORY_PROTECTION_SETTINGS";
     field public static final String ACTION_AIRPLANE_MODE_SETTINGS = "android.settings.AIRPLANE_MODE_SETTINGS";
     field public static final String ACTION_ALL_APPS_NOTIFICATION_SETTINGS = "android.settings.ALL_APPS_NOTIFICATION_SETTINGS";
     field public static final String ACTION_APN_SETTINGS = "android.settings.APN_SETTINGS";
@@ -35893,14 +35971,13 @@
     field public static final String ACTION_MANAGE_ALL_SIM_PROFILES_SETTINGS = "android.settings.MANAGE_ALL_SIM_PROFILES_SETTINGS";
     field public static final String ACTION_MANAGE_APPLICATIONS_SETTINGS = "android.settings.MANAGE_APPLICATIONS_SETTINGS";
     field public static final String ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION = "android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
-    field public static final String ACTION_MANAGE_APP_LONG_JOBS = "android.settings.MANAGE_APP_LONG_JOBS";
+    field public static final String ACTION_MANAGE_APP_LONG_RUNNING_JOBS = "android.settings.MANAGE_APP_LONG_RUNNING_JOBS";
     field public static final String ACTION_MANAGE_DEFAULT_APPS_SETTINGS = "android.settings.MANAGE_DEFAULT_APPS_SETTINGS";
     field public static final String ACTION_MANAGE_OVERLAY_PERMISSION = "android.settings.action.MANAGE_OVERLAY_PERMISSION";
     field public static final String ACTION_MANAGE_SUPERVISOR_RESTRICTED_SETTING = "android.settings.MANAGE_SUPERVISOR_RESTRICTED_SETTING";
     field public static final String ACTION_MANAGE_UNKNOWN_APP_SOURCES = "android.settings.MANAGE_UNKNOWN_APP_SOURCES";
     field public static final String ACTION_MANAGE_WRITE_SETTINGS = "android.settings.action.MANAGE_WRITE_SETTINGS";
     field public static final String ACTION_MEMORY_CARD_SETTINGS = "android.settings.MEMORY_CARD_SETTINGS";
-    field public static final String ACTION_MEMTAG_SETTINGS = "android.settings.MEMTAG_SETTINGS";
     field public static final String ACTION_NETWORK_OPERATOR_SETTINGS = "android.settings.NETWORK_OPERATOR_SETTINGS";
     field public static final String ACTION_NFCSHARING_SETTINGS = "android.settings.NFCSHARING_SETTINGS";
     field public static final String ACTION_NFC_PAYMENT_SETTINGS = "android.settings.NFC_PAYMENT_SETTINGS";
@@ -39303,6 +39380,149 @@
 
 }
 
+package android.service.credentials {
+
+  public final class Action implements android.os.Parcelable {
+    ctor public Action(@NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
+    method public int describeContents();
+    method @NonNull public android.app.PendingIntent getPendingIntent();
+    method @NonNull public android.app.slice.Slice getSlice();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.Action> CREATOR;
+  }
+
+  public final class BeginCreateCredentialRequest implements android.os.Parcelable {
+    ctor public BeginCreateCredentialRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method @NonNull public String getCallingPackage();
+    method @NonNull public android.os.Bundle getData();
+    method @NonNull public String getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginCreateCredentialRequest> CREATOR;
+  }
+
+  public final class BeginCreateCredentialResponse implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.service.credentials.CreateEntry> getCreateEntries();
+    method @Nullable public android.service.credentials.CreateEntry getRemoteCreateEntry();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.BeginCreateCredentialResponse> CREATOR;
+  }
+
+  public static final class BeginCreateCredentialResponse.Builder {
+    ctor public BeginCreateCredentialResponse.Builder();
+    method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder addCreateEntry(@NonNull android.service.credentials.CreateEntry);
+    method @NonNull public android.service.credentials.BeginCreateCredentialResponse build();
+    method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setCreateEntries(@NonNull java.util.List<android.service.credentials.CreateEntry>);
+    method @NonNull public android.service.credentials.BeginCreateCredentialResponse.Builder setRemoteCreateEntry(@Nullable android.service.credentials.CreateEntry);
+  }
+
+  public final class CreateCredentialRequest implements android.os.Parcelable {
+    ctor public CreateCredentialRequest(@NonNull String, @NonNull String, @NonNull android.os.Bundle);
+    method public int describeContents();
+    method @NonNull public String getCallingPackage();
+    method @NonNull public android.os.Bundle getData();
+    method @NonNull public String getType();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CreateCredentialRequest> CREATOR;
+  }
+
+  public final class CreateEntry implements android.os.Parcelable {
+    ctor public CreateEntry(@NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
+    method public int describeContents();
+    method @NonNull public android.app.PendingIntent getPendingIntent();
+    method @NonNull public android.app.slice.Slice getSlice();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CreateEntry> CREATOR;
+  }
+
+  public final class CredentialEntry implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.credentials.Credential getCredential();
+    method @Nullable public android.app.PendingIntent getPendingIntent();
+    method @NonNull public android.app.slice.Slice getSlice();
+    method @NonNull public String getType();
+    method public boolean isAutoSelectAllowed();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CredentialEntry> CREATOR;
+  }
+
+  public static final class CredentialEntry.Builder {
+    ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.app.PendingIntent);
+    ctor public CredentialEntry.Builder(@NonNull String, @NonNull android.app.slice.Slice, @NonNull android.credentials.Credential);
+    method @NonNull public android.service.credentials.CredentialEntry build();
+    method @NonNull public android.service.credentials.CredentialEntry.Builder setAutoSelectAllowed(@NonNull boolean);
+  }
+
+  public class CredentialProviderException extends java.lang.Exception {
+    ctor public CredentialProviderException(int, @NonNull String, @NonNull Throwable);
+    ctor public CredentialProviderException(int, @NonNull String);
+    ctor public CredentialProviderException(int, @NonNull Throwable);
+    ctor public CredentialProviderException(int);
+    method public int getErrorCode();
+    field public static final int ERROR_UNKNOWN = 0; // 0x0
+  }
+
+  public abstract class CredentialProviderService extends android.app.Service {
+    ctor public CredentialProviderService();
+    method public abstract void onBeginCreateCredential(@NonNull android.service.credentials.BeginCreateCredentialRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.BeginCreateCredentialResponse,android.service.credentials.CredentialProviderException>);
+    method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
+    method public abstract void onGetCredentials(@NonNull android.service.credentials.GetCredentialsRequest, @NonNull android.os.CancellationSignal, @NonNull android.os.OutcomeReceiver<android.service.credentials.GetCredentialsResponse,android.service.credentials.CredentialProviderException>);
+    field public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
+    field public static final String EXTRA_CREATE_CREDENTIAL_REQUEST = "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST";
+    field public static final String EXTRA_CREATE_CREDENTIAL_RESULT = "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT";
+    field public static final String EXTRA_CREDENTIAL_RESULT = "android.service.credentials.extra.CREDENTIAL_RESULT";
+    field public static final String EXTRA_ERROR = "android.service.credentials.extra.ERROR";
+    field public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT = "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT";
+    field public static final String SERVICE_INTERFACE = "android.service.credentials.CredentialProviderService";
+  }
+
+  public final class CredentialsResponseContent implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public java.util.List<android.service.credentials.Action> getActions();
+    method @NonNull public java.util.List<android.service.credentials.CredentialEntry> getCredentialEntries();
+    method @Nullable public android.service.credentials.CredentialEntry getRemoteCredentialEntry();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.CredentialsResponseContent> CREATOR;
+  }
+
+  public static final class CredentialsResponseContent.Builder {
+    ctor public CredentialsResponseContent.Builder();
+    method @NonNull public android.service.credentials.CredentialsResponseContent.Builder addAction(@NonNull android.service.credentials.Action);
+    method @NonNull public android.service.credentials.CredentialsResponseContent.Builder addCredentialEntry(@NonNull android.service.credentials.CredentialEntry);
+    method @NonNull public android.service.credentials.CredentialsResponseContent build();
+    method @NonNull public android.service.credentials.CredentialsResponseContent.Builder setActions(@NonNull java.util.List<android.service.credentials.Action>);
+    method @NonNull public android.service.credentials.CredentialsResponseContent.Builder setCredentialEntries(@NonNull java.util.List<android.service.credentials.CredentialEntry>);
+    method @NonNull public android.service.credentials.CredentialsResponseContent.Builder setRemoteCredentialEntry(@Nullable android.service.credentials.CredentialEntry);
+  }
+
+  public final class GetCredentialsRequest implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getCallingPackage();
+    method @NonNull public java.util.List<android.credentials.GetCredentialOption> getGetCredentialOptions();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsRequest> CREATOR;
+  }
+
+  public static final class GetCredentialsRequest.Builder {
+    ctor public GetCredentialsRequest.Builder(@NonNull String);
+    method @NonNull public android.service.credentials.GetCredentialsRequest.Builder addGetCredentialOption(@NonNull android.credentials.GetCredentialOption);
+    method @NonNull public android.service.credentials.GetCredentialsRequest build();
+    method @NonNull public android.service.credentials.GetCredentialsRequest.Builder setGetCredentialOptions(@NonNull java.util.List<android.credentials.GetCredentialOption>);
+  }
+
+  public final class GetCredentialsResponse implements android.os.Parcelable {
+    method @NonNull public static android.service.credentials.GetCredentialsResponse createWithAuthentication(@NonNull android.service.credentials.Action);
+    method @NonNull public static android.service.credentials.GetCredentialsResponse createWithResponseContent(@NonNull android.service.credentials.CredentialsResponseContent);
+    method public int describeContents();
+    method @Nullable public android.service.credentials.Action getAuthenticationAction();
+    method @Nullable public android.service.credentials.CredentialsResponseContent getCredentialsResponseContent();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.credentials.GetCredentialsResponse> CREATOR;
+  }
+
+}
+
 package android.service.dreams {
 
   public class DreamService extends android.app.Service implements android.view.Window.Callback {
@@ -41839,6 +42059,7 @@
     field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool";
     field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int";
     field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int";
+    field public static final String KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL = "include_lte_for_nr_advanced_threshold_bandwidth_bool";
     field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool";
     field public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL = "is_opportunistic_subscription_bool";
     field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool";
@@ -45465,6 +45686,19 @@
     method public int previousStartBoundary(@IntRange(from=0) int);
   }
 
+  public class Highlights {
+    method @NonNull public android.graphics.Paint getPaint(int);
+    method @NonNull public int[] getRanges(int);
+    method public int getSize();
+  }
+
+  public static final class Highlights.Builder {
+    ctor public Highlights.Builder();
+    method @NonNull public android.text.Highlights.Builder addRange(@NonNull android.graphics.Paint, int, int);
+    method @NonNull public android.text.Highlights.Builder addRanges(@NonNull android.graphics.Paint, @NonNull int...);
+    method @NonNull public android.text.Highlights build();
+  }
+
   public class Html {
     method public static String escapeHtml(CharSequence);
     method @Deprecated public static android.text.Spanned fromHtml(String);
@@ -45556,6 +45790,9 @@
     ctor protected Layout(CharSequence, android.text.TextPaint, int, android.text.Layout.Alignment, float, float);
     method public void draw(android.graphics.Canvas);
     method public void draw(android.graphics.Canvas, android.graphics.Path, android.graphics.Paint, int);
+    method public void draw(@NonNull android.graphics.Canvas, @Nullable java.util.List<android.graphics.Path>, @Nullable java.util.List<android.graphics.Paint>, @Nullable android.graphics.Path, @Nullable android.graphics.Paint, int);
+    method public void drawBackground(@NonNull android.graphics.Canvas);
+    method public void drawText(@NonNull android.graphics.Canvas);
     method public void fillCharacterBounds(@IntRange(from=0) int, @IntRange(from=0) int, @NonNull float[], @IntRange(from=0) int);
     method public final android.text.Layout.Alignment getAlignment();
     method public abstract int getBottomPadding();
@@ -48490,6 +48727,7 @@
     method public float getRefreshRate();
     method public int getRotation();
     method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
+    method @NonNull public android.view.DisplayShape getShape();
     method @Deprecated public void getSize(android.graphics.Point);
     method public int getState();
     method public android.view.Display.Mode[] getSupportedModes();
@@ -48520,7 +48758,7 @@
     method public float getDesiredMaxAverageLuminance();
     method public float getDesiredMaxLuminance();
     method public float getDesiredMinLuminance();
-    method public int[] getSupportedHdrTypes();
+    method @Deprecated public int[] getSupportedHdrTypes();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.Display.HdrCapabilities> CREATOR;
     field public static final int HDR_TYPE_DOLBY_VISION = 1; // 0x1
@@ -48537,6 +48775,7 @@
     method public int getPhysicalHeight();
     method public int getPhysicalWidth();
     method public float getRefreshRate();
+    method @NonNull public int[] getSupportedHdrTypes();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
   }
@@ -48570,6 +48809,13 @@
     method @NonNull public android.view.DisplayCutout.Builder setWaterfallInsets(@NonNull android.graphics.Insets);
   }
 
+  public final class DisplayShape implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public android.graphics.Path getPath();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.DisplayShape> CREATOR;
+  }
+
   public final class DragAndDropPermissions implements android.os.Parcelable {
     method public int describeContents();
     method public void release();
@@ -51951,6 +52197,7 @@
     method @Deprecated @NonNull public android.view.WindowInsets consumeStableInsets();
     method @Deprecated @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
     method @Nullable public android.view.DisplayCutout getDisplayCutout();
+    method @Nullable public android.view.DisplayShape getDisplayShape();
     method @NonNull public android.graphics.Insets getInsets(int);
     method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
     method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
@@ -51986,6 +52233,7 @@
     ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
     method @NonNull public android.view.WindowInsets build();
     method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+    method @NonNull public android.view.WindowInsets.Builder setDisplayShape(@NonNull android.view.DisplayShape);
     method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
     method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
     method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
@@ -52464,7 +52712,7 @@
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
     method public int getLiveRegion();
     method public int getMaxTextLength();
-    method public int getMinMillisBetweenContentChanges();
+    method @NonNull public java.time.Duration getMinDurationBetweenContentChanges();
     method public int getMovementGranularities();
     method public CharSequence getPackageName();
     method @Nullable public CharSequence getPaneTitle();
@@ -52553,7 +52801,7 @@
     method public void setLiveRegion(int);
     method public void setLongClickable(boolean);
     method public void setMaxTextLength(int);
-    method public void setMinMillisBetweenContentChanges(int);
+    method public void setMinDurationBetweenContentChanges(@NonNull java.time.Duration);
     method public void setMovementGranularities(int);
     method public void setMultiLine(boolean);
     method public void setPackageName(CharSequence);
@@ -58359,6 +58607,7 @@
     method public boolean getFreezesText();
     method public int getGravity();
     method @ColorInt public int getHighlightColor();
+    method @Nullable public android.text.Highlights getHighlights();
     method public CharSequence getHint();
     method public final android.content.res.ColorStateList getHintTextColors();
     method public int getHyphenationFrequency();
@@ -58488,6 +58737,7 @@
     method public void setGravity(int);
     method public void setHeight(int);
     method public void setHighlightColor(@ColorInt int);
+    method public void setHighlights(@Nullable android.text.Highlights);
     method public final void setHint(CharSequence);
     method public final void setHint(@StringRes int);
     method public final void setHintTextColor(@ColorInt int);
@@ -58910,6 +59160,22 @@
 
 package android.window {
 
+  public final class BackEvent {
+    ctor public BackEvent(float, float, float, int);
+    method @FloatRange(from=0, to=1) public float getProgress();
+    method public int getSwipeEdge();
+    method public float getTouchX();
+    method public float getTouchY();
+    field public static final int EDGE_LEFT = 0; // 0x0
+    field public static final int EDGE_RIGHT = 1; // 0x1
+  }
+
+  public interface OnBackAnimationCallback extends android.window.OnBackInvokedCallback {
+    method public default void onBackCancelled();
+    method public default void onBackProgressed(@NonNull android.window.BackEvent);
+    method public default void onBackStarted(@NonNull android.window.BackEvent);
+  }
+
   public interface OnBackInvokedCallback {
     method public void onBackInvoked();
   }
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b6e2d2a..286a800 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -121,6 +121,7 @@
     field public static final int GADGET_HAL_V1_0 = 10; // 0xa
     field public static final int GADGET_HAL_V1_1 = 11; // 0xb
     field public static final int GADGET_HAL_V1_2 = 12; // 0xc
+    field public static final int GADGET_HAL_V2_0 = 20; // 0x14
     field public static final int USB_DATA_TRANSFER_RATE_10G = 10240; // 0x2800
     field public static final int USB_DATA_TRANSFER_RATE_20G = 20480; // 0x5000
     field public static final int USB_DATA_TRANSFER_RATE_40G = 40960; // 0xa000
@@ -392,7 +393,6 @@
     method public static void traceBegin(long, @NonNull String);
     method public static void traceCounter(long, @NonNull String, int);
     method public static void traceEnd(long);
-    field public static final long TRACE_TAG_AIDL = 16777216L; // 0x1000000L
     field public static final long TRACE_TAG_NETWORK = 2097152L; // 0x200000L
   }
 
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 99be1a2..3d5139b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1474,6 +1474,7 @@
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void cancelBackups();
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void excludeKeysFromRestore(@NonNull String, @NonNull java.util.List<java.lang.String>);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public long getAvailableRestoreToken(String);
+    method @NonNull public android.app.backup.BackupRestoreEventLogger getBackupRestoreEventLogger(@NonNull android.app.backup.BackupAgent);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.Intent getConfigurationIntent(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public String getCurrentTransport();
     method @Nullable @RequiresPermission(android.Manifest.permission.BACKUP) public android.content.ComponentName getCurrentTransportComponent();
@@ -1592,6 +1593,33 @@
     field public final long bytesTransferred;
   }
 
+  public class BackupRestoreEventLogger {
+    method public void logBackupMetaData(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, @NonNull String);
+    method public void logItemsBackedUp(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int);
+    method public void logItemsBackupFailed(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int, @android.app.backup.BackupRestoreEventLogger.BackupRestoreError @Nullable String);
+    method public void logItemsRestoreFailed(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int, @android.app.backup.BackupRestoreEventLogger.BackupRestoreError @Nullable String);
+    method public void logItemsRestored(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, int);
+    method public void logRestoreMetadata(@android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull String, @NonNull String);
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface BackupRestoreEventLogger.BackupRestoreDataType {
+  }
+
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface BackupRestoreEventLogger.BackupRestoreError {
+  }
+
+  public static final class BackupRestoreEventLogger.DataTypeResult implements android.os.Parcelable {
+    ctor public BackupRestoreEventLogger.DataTypeResult(@NonNull String);
+    method public int describeContents();
+    method @android.app.backup.BackupRestoreEventLogger.BackupRestoreDataType @NonNull public String getDataType();
+    method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getErrors();
+    method public int getFailCount();
+    method @Nullable public byte[] getMetadataHash();
+    method public int getSuccessCount();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.app.backup.BackupRestoreEventLogger.DataTypeResult> CREATOR;
+  }
+
   public class BackupTransport {
     ctor public BackupTransport();
     method public int abortFullRestore();
@@ -2956,13 +2984,19 @@
   public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
     method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
+    method @NonNull public android.content.Context createContext();
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.audio.VirtualAudioDevice createVirtualAudioDevice(@NonNull android.hardware.display.VirtualDisplay, @Nullable java.util.concurrent.Executor, @Nullable android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback);
     method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
-    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method @Nullable public android.hardware.display.VirtualDisplay createVirtualDisplay(@IntRange(from=1) int, @IntRange(from=1) int, @IntRange(from=1) int, @NonNull java.util.List<java.lang.String>, @Nullable android.view.Surface, int, @Nullable java.util.concurrent.Executor, @Nullable android.hardware.display.VirtualDisplay.Callback);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualDpad createVirtualDpad(@NonNull android.hardware.input.VirtualDpadConfig);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.input.VirtualKeyboardConfig);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.input.VirtualMouseConfig);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.input.VirtualTouchscreenConfig);
+    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
     method public int getDeviceId();
+    method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
     method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
     method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
@@ -2980,6 +3014,7 @@
     method public int getLockState();
     method @Nullable public String getName();
     method @NonNull public java.util.Set<android.os.UserHandle> getUsersWithMatchingAccounts();
+    method @NonNull public java.util.List<android.companion.virtual.sensor.VirtualSensorConfig> getVirtualSensorConfigs();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int ACTIVITY_POLICY_DEFAULT_ALLOWED = 0; // 0x0
     field public static final int ACTIVITY_POLICY_DEFAULT_BLOCKED = 1; // 0x1
@@ -2995,12 +3030,13 @@
 
   public static final class VirtualDeviceParams.Builder {
     ctor public VirtualDeviceParams.Builder();
-    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder addDevicePolicy(int, int);
+    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder addVirtualSensorConfig(@NonNull android.companion.virtual.sensor.VirtualSensorConfig);
     method @NonNull public android.companion.virtual.VirtualDeviceParams build();
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedActivities(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setAllowedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedActivities(@NonNull java.util.Set<android.content.ComponentName>);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setBlockedCrossTaskNavigations(@NonNull java.util.Set<android.content.ComponentName>);
+    method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setDevicePolicy(int, int);
     method @NonNull @RequiresPermission(value=android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY, conditional=true) public android.companion.virtual.VirtualDeviceParams.Builder setLockState(int);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setName(@NonNull String);
     method @NonNull public android.companion.virtual.VirtualDeviceParams.Builder setUsersWithMatchingAccounts(@NonNull java.util.Set<android.os.UserHandle>);
@@ -3053,6 +3089,50 @@
 
 }
 
+package android.companion.virtual.sensor {
+
+  public class VirtualSensor {
+    method @NonNull public String getName();
+    method public int getType();
+    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendSensorEvent(@NonNull android.companion.virtual.sensor.VirtualSensorEvent);
+  }
+
+  public static interface VirtualSensor.SensorStateChangeCallback {
+    method public void onStateChanged(boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
+  }
+
+  public final class VirtualSensorConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method @NonNull public String getName();
+    method public int getType();
+    method @Nullable public String getVendor();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensorConfig> CREATOR;
+  }
+
+  public static final class VirtualSensorConfig.Builder {
+    ctor public VirtualSensorConfig.Builder(int, @NonNull String);
+    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
+    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setStateChangeCallback(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.sensor.VirtualSensor.SensorStateChangeCallback);
+    method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
+  }
+
+  public final class VirtualSensorEvent implements android.os.Parcelable {
+    method public int describeContents();
+    method public long getTimestampNanos();
+    method @NonNull public float[] getValues();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.sensor.VirtualSensorEvent> CREATOR;
+  }
+
+  public static final class VirtualSensorEvent.Builder {
+    ctor public VirtualSensorEvent.Builder(@NonNull float[]);
+    method @NonNull public android.companion.virtual.sensor.VirtualSensorEvent build();
+    method @NonNull public android.companion.virtual.sensor.VirtualSensorEvent.Builder setTimestampNanos(long);
+  }
+
+}
+
 package android.content {
 
   public class ApexEnvironment {
@@ -3146,6 +3226,7 @@
     field public static final String TRANSLATION_MANAGER_SERVICE = "translation";
     field public static final String UI_TRANSLATION_SERVICE = "ui_translation";
     field public static final String UWB_SERVICE = "uwb";
+    field public static final String VIRTUALIZATION_SERVICE = "virtualization";
     field public static final String VR_SERVICE = "vrmanager";
     field public static final String WALLPAPER_EFFECTS_GENERATION_SERVICE = "wallpaper_effects_generation";
     field public static final String WEARABLE_SENSING_SERVICE = "wearable_sensing";
@@ -4160,15 +4241,18 @@
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public java.util.List<java.lang.String> getAllowedCecSettingStringValues(@NonNull String);
     method @Nullable public android.hardware.hdmi.HdmiClient getClient(int);
     method @NonNull public java.util.List<android.hardware.hdmi.HdmiDeviceInfo> getConnectedDevices();
+    method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getEarcEnabled();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecEnabled();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecVersion();
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getHdmiCecVolumeControlEnabled();
     method public int getPhysicalAddress();
     method @Nullable public android.hardware.hdmi.HdmiPlaybackClient getPlaybackClient();
+    method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerControlMode();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public String getPowerStateChangeOnActiveSourceLost();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getRoutingControl();
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSadPresenceInQuery(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSoundbarMode();
     method @Nullable public android.hardware.hdmi.HdmiSwitchClient getSwitchClient();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioControl();
     method @NonNull @RequiresPermission(android.Manifest.permission.HDMI_CEC) public int getSystemAudioModeMuting();
@@ -4181,6 +4265,7 @@
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHdmiCecEnabledChangeListener(@NonNull android.hardware.hdmi.HdmiControlManager.CecSettingChangeListener);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void removeHotplugEventListener(android.hardware.hdmi.HdmiControlManager.HotplugEventListener);
     method public void setActiveSource(@NonNull android.hardware.hdmi.HdmiDeviceInfo);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setEarcEnabled(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecEnabled(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVersion(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setHdmiCecVolumeControlEnabled(int);
@@ -4189,6 +4274,7 @@
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setRoutingControl(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSadPresenceInQuery(@NonNull String, int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSadsPresenceInQuery(@NonNull java.util.List<java.lang.String>, int);
+    method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSoundbarMode(int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setStandbyMode(boolean);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioControl(@NonNull int);
     method @RequiresPermission(android.Manifest.permission.HDMI_CEC) public void setSystemAudioModeMuting(@NonNull int);
@@ -4216,6 +4302,7 @@
     field public static final String CEC_SETTING_NAME_QUERY_SAD_TRUEHD = "query_sad_truehd";
     field public static final String CEC_SETTING_NAME_QUERY_SAD_WMAPRO = "query_sad_wmapro";
     field public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control";
+    field public static final String CEC_SETTING_NAME_SOUNDBAR_MODE = "soundbar_mode";
     field public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL = "system_audio_control";
     field public static final String CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING = "system_audio_mode_muting";
     field public static final String CEC_SETTING_NAME_TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep";
@@ -4235,6 +4322,8 @@
     field public static final int DEVICE_EVENT_ADD_DEVICE = 1; // 0x1
     field public static final int DEVICE_EVENT_REMOVE_DEVICE = 2; // 0x2
     field public static final int DEVICE_EVENT_UPDATE_DEVICE = 3; // 0x3
+    field public static final int EARC_FEATURE_DISABLED = 0; // 0x0
+    field public static final int EARC_FEATURE_ENABLED = 1; // 0x1
     field public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
     field public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
     field public static final int HDMI_CEC_CONTROL_DISABLED = 0; // 0x0
@@ -4294,6 +4383,9 @@
     field public static final int RESULT_TIMEOUT = 1; // 0x1
     field public static final int ROUTING_CONTROL_DISABLED = 0; // 0x0
     field public static final int ROUTING_CONTROL_ENABLED = 1; // 0x1
+    field public static final String SETTING_NAME_EARC_ENABLED = "earc_enabled";
+    field public static final int SOUNDBAR_MODE_DISABLED = 0; // 0x0
+    field public static final int SOUNDBAR_MODE_ENABLED = 1; // 0x1
     field public static final int SYSTEM_AUDIO_CONTROL_DISABLED = 0; // 0x0
     field public static final int SYSTEM_AUDIO_CONTROL_ENABLED = 1; // 0x1
     field public static final int SYSTEM_AUDIO_MODE_MUTING_DISABLED = 0; // 0x0
@@ -4468,7 +4560,7 @@
 
   public class HdmiSwitchClient extends android.hardware.hdmi.HdmiClient {
     method public int getDeviceType();
-    method @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
+    method @Deprecated @NonNull public java.util.List<android.hardware.hdmi.HdmiPortInfo> getPortInfo();
     method public void selectPort(int, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
     method public void selectPort(int, @NonNull java.util.concurrent.Executor, @NonNull android.hardware.hdmi.HdmiSwitchClient.OnSelectListener);
   }
@@ -4549,6 +4641,34 @@
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
   }
 
+  public final class VirtualDpadConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualDpadConfig> CREATOR;
+  }
+
+  public static final class VirtualDpadConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualDpadConfig.Builder> {
+    ctor public VirtualDpadConfig.Builder();
+    method @NonNull public android.hardware.input.VirtualDpadConfig build();
+  }
+
+  public abstract class VirtualInputDeviceConfig {
+    ctor protected VirtualInputDeviceConfig(@NonNull android.hardware.input.VirtualInputDeviceConfig.Builder<? extends android.hardware.input.VirtualInputDeviceConfig.Builder<?>>);
+    ctor protected VirtualInputDeviceConfig(@NonNull android.os.Parcel);
+    method public int getAssociatedDisplayId();
+    method @NonNull public String getInputDeviceName();
+    method public int getProductId();
+    method public int getVendorId();
+  }
+
+  public abstract static class VirtualInputDeviceConfig.Builder<T extends android.hardware.input.VirtualInputDeviceConfig.Builder<T>> {
+    ctor public VirtualInputDeviceConfig.Builder();
+    method @NonNull public T setAssociatedDisplayId(int);
+    method @NonNull public T setInputDeviceName(@NonNull String);
+    method @NonNull public T setProductId(int);
+    method @NonNull public T setVendorId(int);
+  }
+
   public final class VirtualKeyEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -4571,6 +4691,17 @@
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendKeyEvent(@NonNull android.hardware.input.VirtualKeyEvent);
   }
 
+  public final class VirtualKeyboardConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualKeyboardConfig> CREATOR;
+  }
+
+  public static final class VirtualKeyboardConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualKeyboardConfig.Builder> {
+    ctor public VirtualKeyboardConfig.Builder();
+    method @NonNull public android.hardware.input.VirtualKeyboardConfig build();
+  }
+
   public class VirtualMouse implements java.io.Closeable {
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
     method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.graphics.PointF getCursorPosition();
@@ -4601,6 +4732,17 @@
     method @NonNull public android.hardware.input.VirtualMouseButtonEvent.Builder setButtonCode(int);
   }
 
+  public final class VirtualMouseConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualMouseConfig> CREATOR;
+  }
+
+  public static final class VirtualMouseConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualMouseConfig.Builder> {
+    ctor public VirtualMouseConfig.Builder();
+    method @NonNull public android.hardware.input.VirtualMouseConfig build();
+  }
+
   public final class VirtualMouseRelativeEvent implements android.os.Parcelable {
     method public int describeContents();
     method public float getRelativeX();
@@ -4667,6 +4809,21 @@
     method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void sendTouchEvent(@NonNull android.hardware.input.VirtualTouchEvent);
   }
 
+  public final class VirtualTouchscreenConfig extends android.hardware.input.VirtualInputDeviceConfig implements android.os.Parcelable {
+    method public int describeContents();
+    method public int getHeightInPixels();
+    method public int getWidthInPixels();
+    method public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.hardware.input.VirtualTouchscreenConfig> CREATOR;
+  }
+
+  public static final class VirtualTouchscreenConfig.Builder extends android.hardware.input.VirtualInputDeviceConfig.Builder<android.hardware.input.VirtualTouchscreenConfig.Builder> {
+    ctor public VirtualTouchscreenConfig.Builder();
+    method @NonNull public android.hardware.input.VirtualTouchscreenConfig build();
+    method @NonNull public android.hardware.input.VirtualTouchscreenConfig.Builder setHeightInPixels(int);
+    method @NonNull public android.hardware.input.VirtualTouchscreenConfig.Builder setWidthInPixels(int);
+  }
+
 }
 
 package android.hardware.lights {
@@ -5521,6 +5678,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setCurrentFunctions(long);
     field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_ACCESSORY_HANDSHAKE = "android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE";
     field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_CHANGED = "android.hardware.usb.action.USB_PORT_CHANGED";
+    field @RequiresPermission(android.Manifest.permission.MANAGE_USB) public static final String ACTION_USB_PORT_COMPLIANCE_CHANGED = "android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED";
     field public static final String ACTION_USB_STATE = "android.hardware.usb.action.USB_STATE";
     field public static final String EXTRA_ACCESSORY_HANDSHAKE_END = "android.hardware.usb.extra.ACCESSORY_HANDSHAKE_END";
     field public static final String EXTRA_ACCESSORY_START = "android.hardware.usb.extra.ACCESSORY_START";
@@ -5548,6 +5706,7 @@
     method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USB) public android.hardware.usb.UsbPortStatus getStatus();
     method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void resetUsbPort(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USB) public void setRoles(int, int);
+    method @CheckResult @RequiresPermission(android.Manifest.permission.MANAGE_USB) public boolean supportsComplianceWarnings();
     field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_INTERNAL = 1; // 0x1
     field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_NOT_SUPPORTED = 2; // 0x2
     field public static final int ENABLE_LIMIT_POWER_TRANSFER_ERROR_OTHER = 4; // 0x4
@@ -5573,6 +5732,7 @@
 
   public final class UsbPortStatus implements android.os.Parcelable {
     method public int describeContents();
+    method @CheckResult @NonNull public int[] getComplianceWarnings();
     method public int getCurrentDataRole();
     method public int getCurrentMode();
     method public int getCurrentPowerRole();
@@ -5583,6 +5743,10 @@
     method public boolean isPowerTransferLimited();
     method public boolean isRoleCombinationSupported(int, int);
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int COMPLIANCE_WARNING_BC_1_2 = 3; // 0x3
+    field public static final int COMPLIANCE_WARNING_DEBUG_ACCESSORY = 2; // 0x2
+    field public static final int COMPLIANCE_WARNING_MISSING_RP = 4; // 0x4
+    field public static final int COMPLIANCE_WARNING_OTHER = 1; // 0x1
     field @NonNull public static final android.os.Parcelable.Creator<android.hardware.usb.UsbPortStatus> CREATOR;
     field public static final int DATA_ROLE_DEVICE = 2; // 0x2
     field public static final int DATA_ROLE_HOST = 1; // 0x1
@@ -6461,7 +6625,6 @@
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_MUTED = 4; // 0x4
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_VOLUME = 2; // 0x2
-    field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_UNKNOWN = -1; // 0xffffffff
     field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_VOLUME_SHAPER = 32; // 0x20
     field public static final int PLAYER_STATE_IDLE = 1; // 0x1
     field public static final int PLAYER_STATE_PAUSED = 3; // 0x3
@@ -7256,6 +7419,7 @@
     method @NonNull public java.util.List<android.media.tv.tuner.frontend.FrontendStatusReadiness> getFrontendStatusReadiness(@NonNull int[]);
     method @IntRange(from=0xffffffff) public int getMaxNumberOfFrontends(int);
     method @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean hasUnusedFrontend(int);
+    method public boolean isLnaSupported();
     method public boolean isLowestPriority(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_TV_DESCRAMBLER) public android.media.tv.tuner.Descrambler openDescrambler();
     method @Nullable public android.media.tv.tuner.dvr.DvrPlayback openDvrPlayback(long, @NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.dvr.OnPlaybackStatusChangedListener);
@@ -7454,6 +7618,7 @@
     field public static final int VIDEO_STREAM_TYPE_VC1 = 7; // 0x7
     field public static final int VIDEO_STREAM_TYPE_VP8 = 8; // 0x8
     field public static final int VIDEO_STREAM_TYPE_VP9 = 9; // 0x9
+    field public static final int VIDEO_STREAM_TYPE_VVC = 13; // 0xd
   }
 
   public static class AvSettings.Builder {
@@ -7646,6 +7811,7 @@
     field public static final int INDEX_TYPE_SC = 1; // 0x1
     field public static final int INDEX_TYPE_SC_AVC = 3; // 0x3
     field public static final int INDEX_TYPE_SC_HEVC = 2; // 0x2
+    field public static final int INDEX_TYPE_SC_VVC = 4; // 0x4
     field public static final int MPT_INDEX_AUDIO = 262144; // 0x40000
     field public static final int MPT_INDEX_MPT = 65536; // 0x10000
     field public static final int MPT_INDEX_TIMESTAMP_TARGET_AUDIO = 1048576; // 0x100000
@@ -7668,6 +7834,13 @@
     field public static final int SC_INDEX_SEQUENCE = 8; // 0x8
     field public static final int SC_INDEX_SI_SLICE = 128; // 0x80
     field public static final int SC_INDEX_SP_SLICE = 256; // 0x100
+    field public static final int SC_VVC_INDEX_AUD = 64; // 0x40
+    field public static final int SC_VVC_INDEX_SLICE_CRA = 4; // 0x4
+    field public static final int SC_VVC_INDEX_SLICE_GDR = 8; // 0x8
+    field public static final int SC_VVC_INDEX_SLICE_IDR_N_LP = 2; // 0x2
+    field public static final int SC_VVC_INDEX_SLICE_IDR_W_RADL = 1; // 0x1
+    field public static final int SC_VVC_INDEX_SPS = 32; // 0x20
+    field public static final int SC_VVC_INDEX_VPS = 16; // 0x10
     field public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = 4096; // 0x1000
     field public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = 8; // 0x8
     field public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = 4; // 0x4
@@ -9246,6 +9419,7 @@
   }
 
   public class WifiNl80211Manager {
+    ctor public WifiNl80211Manager(@NonNull android.content.Context, @NonNull android.os.IBinder);
     method public void abortScan(@NonNull String);
     method public void enableVerboseLogging(boolean);
     method @NonNull public int[] getChannelsMhzForBand(int);
@@ -9945,6 +10119,10 @@
     field public static final int STATUS_WAITING_REBOOT = 5; // 0x5
   }
 
+  public final class Trace {
+    field public static final long TRACE_TAG_AIDL = 16777216L; // 0x1000000L
+  }
+
   public class UpdateEngine {
     ctor public UpdateEngine();
     method @NonNull @WorkerThread public android.os.UpdateEngine.AllocateSpaceResult allocateSpace(@NonNull String, @NonNull String[]);
@@ -10029,6 +10207,8 @@
     method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public android.os.NewUserResponse createUser(@NonNull android.os.NewUserRequest);
     method @NonNull public java.util.List<android.os.UserHandle> getAllProfiles();
     method @NonNull public java.util.List<android.os.UserHandle> getEnabledProfiles();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getMainUser();
+    method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public android.os.UserHandle getPreviousForegroundUser();
     method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}) public android.os.UserHandle getProfileParent(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableProfileCount(@NonNull String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public int getRemainingCreatableUserCount(@NonNull String);
@@ -10042,6 +10222,7 @@
     method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public int getUserRestrictionSource(String, android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.QUERY_USERS}) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
     method @RequiresPermission(allOf={android.Manifest.permission.READ_PHONE_STATE, android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public int getUserSwitchability();
+    method @NonNull @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public java.util.Set<android.os.UserHandle> getVisibleUsers();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean hasRestrictedProfiles();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean hasUserRestrictionForUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isAdminUser();
@@ -10059,6 +10240,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS, android.Manifest.permission.GET_ACCOUNTS_PRIVILEGED}) public boolean isUserNameSet();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS, android.Manifest.permission.QUERY_USERS}) public boolean isUserOfType(@NonNull String);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional=true) public boolean isUserUnlockingOrUnlocked(@NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.INTERACT_ACROSS_USERS", "android.permission.MANAGE_USERS"}) public boolean isUserVisible();
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public boolean removeUser(@NonNull android.os.UserHandle);
     method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_USERS, android.Manifest.permission.CREATE_USERS}) public int removeUserWhenPossible(@NonNull android.os.UserHandle, boolean);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(@NonNull android.graphics.Bitmap) throws android.os.UserManager.UserOperationException;
@@ -10556,6 +10738,7 @@
     field @Deprecated public static final String NAMESPACE_DEX_BOOT = "dex_boot";
     field public static final String NAMESPACE_DISPLAY_MANAGER = "display_manager";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
+    field public static final String NAMESPACE_HDMI_CONTROL = "hdmi_control";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
     field public static final String NAMESPACE_INTELLIGENCE_ATTENTION = "intelligence_attention";
     field public static final String NAMESPACE_LMKD_NATIVE = "lmkd_native";
@@ -12205,6 +12388,7 @@
     method @Nullable public android.media.AudioTimestamp getTimestamp();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.service.voice.HotwordAudioStream> CREATOR;
+    field public static final String KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES = "android.service.voice.key.AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES";
   }
 
   public static final class HotwordAudioStream.Builder {
@@ -12804,14 +12988,14 @@
     method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy();
   }
 
-  public final class CallAttributes implements android.os.Parcelable {
-    ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
-    method public int describeContents();
-    method @NonNull public android.telephony.CallQuality getCallQuality();
-    method public int getNetworkType();
-    method @NonNull public android.telephony.PreciseCallState getPreciseCallState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
+  @Deprecated public final class CallAttributes implements android.os.Parcelable {
+    ctor @Deprecated public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
+    method @Deprecated public int describeContents();
+    method @Deprecated @NonNull public android.telephony.CallQuality getCallQuality();
+    method @Deprecated public int getNetworkType();
+    method @Deprecated @NonNull public android.telephony.PreciseCallState getPreciseCallState();
+    method @Deprecated public void writeToParcel(android.os.Parcel, int);
+    field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
   }
 
   public final class CallForwardingInfo implements android.os.Parcelable {
@@ -12891,6 +13075,28 @@
     method @NonNull public android.telephony.CallQuality.Builder setUplinkCallQualityLevel(int);
   }
 
+  public final class CallState implements android.os.Parcelable {
+    method public int describeContents();
+    method @Nullable public android.telephony.CallQuality getCallQuality();
+    method public int getCallState();
+    method public int getImsCallServiceType();
+    method @Nullable public String getImsCallSessionId();
+    method public int getImsCallType();
+    method public int getNetworkType();
+    method public void writeToParcel(@Nullable android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallState> CREATOR;
+  }
+
+  public static final class CallState.Builder {
+    ctor public CallState.Builder(int);
+    method @NonNull public android.telephony.CallState build();
+    method @NonNull public android.telephony.CallState.Builder setCallQuality(@Nullable android.telephony.CallQuality);
+    method @NonNull public android.telephony.CallState.Builder setImsCallServiceType(int);
+    method @NonNull public android.telephony.CallState.Builder setImsCallSessionId(@Nullable String);
+    method @NonNull public android.telephony.CallState.Builder setImsCallType(int);
+    method @NonNull public android.telephony.CallState.Builder setNetworkType(int);
+  }
+
   public class CarrierConfigManager {
     method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName();
     method @NonNull public static android.os.PersistableBundle getDefaultConfig();
@@ -13641,7 +13847,8 @@
   }
 
   public static interface TelephonyCallback.CallAttributesListener {
-    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+    method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>);
   }
 
   public static interface TelephonyCallback.DataEnabledListener {
@@ -14742,6 +14949,7 @@
     field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
     field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0
     field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1
+    field public static final int CALL_TYPE_NONE = 0; // 0x0
     field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3
     field public static final int CALL_TYPE_VOICE = 2; // 0x2
     field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1
@@ -15806,6 +16014,7 @@
   public class ImsSmsImplBase {
     ctor public ImsSmsImplBase();
     method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int);
+    method public void acknowledgeSms(int, @IntRange(from=0, to=65535) int, int, @NonNull byte[]);
     method public void acknowledgeSmsReport(int, @IntRange(from=0, to=65535) int, int);
     method public String getSmsFormat();
     method public void onReady();
@@ -16106,6 +16315,12 @@
   public abstract class AccessibilityDisplayProxy {
     ctor public AccessibilityDisplayProxy(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.List<android.accessibilityservice.AccessibilityServiceInfo>);
     method public int getDisplayId();
+    method @NonNull public final java.util.List<android.accessibilityservice.AccessibilityServiceInfo> getInstalledAndEnabledServices();
+    method @NonNull public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
+    method public void interrupt();
+    method public void onAccessibilityEvent(@NonNull android.view.accessibility.AccessibilityEvent);
+    method public void onProxyConnected();
+    method public void setInstalledAndEnabledServices(@NonNull java.util.List<android.accessibilityservice.AccessibilityServiceInfo>);
   }
 
   public final class AccessibilityManager {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 121741e0..25c4652 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -440,6 +440,7 @@
     method @NonNull public java.util.Set<java.lang.String> getAdoptedShellPermissions();
     method @Deprecated public boolean grantRuntimePermission(String, String, android.os.UserHandle);
     method public boolean injectInputEvent(@NonNull android.view.InputEvent, boolean, boolean);
+    method public void injectInputEventToInputFilter(@NonNull android.view.InputEvent);
     method @Deprecated public boolean revokeRuntimePermission(String, String, android.os.UserHandle);
     method public void syncInputTransactions();
     method public void syncInputTransactions(boolean);
@@ -459,6 +460,8 @@
 
   public class WallpaperManager {
     method @Nullable public android.graphics.Bitmap getBitmap();
+    method @Nullable public android.graphics.Rect peekBitmapDimensions();
+    method @Nullable public android.graphics.Rect peekBitmapDimensions(int);
     method public boolean shouldEnableWideColorGamut();
     method @RequiresPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) public boolean wallpaperSupportsWcg(int);
   }
@@ -1037,6 +1040,7 @@
     method @NonNull public static android.util.Pair<java.util.List<android.graphics.Typeface>,java.util.List<android.graphics.Typeface>> changeDefaultFontForTest(@NonNull java.util.List<android.graphics.Typeface>, @NonNull java.util.List<android.graphics.Typeface>);
     method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException;
     method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory();
+    method public void releaseNativeObjectForTest();
     method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException;
   }
 
@@ -1249,6 +1253,7 @@
     field public static final int SWITCHING_TYPE_NONE = 0; // 0x0
     field public static final int SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY = 3; // 0x3
     field public static final int SWITCHING_TYPE_WITHIN_GROUPS = 1; // 0x1
+    field public static final int VIRTUAL_DISPLAY_FLAG_OWN_FOCUS = 16384; // 0x4000
     field public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 512; // 0x200
   }
 
@@ -1312,6 +1317,14 @@
 
 }
 
+package android.hardware.location {
+
+  public final class ContextHubManager {
+    method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public long[] getPreloadedNanoAppIds(@NonNull android.hardware.location.ContextHubInfo);
+  }
+
+}
+
 package android.hardware.soundtrigger {
 
   public class KeyphraseEnrollmentInfo {
@@ -1905,6 +1918,7 @@
   }
 
   public abstract class VibrationEffect implements android.os.Parcelable {
+    method @Nullable public abstract long[] computeCreateWaveformOffOnTimingsOrNull();
     method public static android.os.VibrationEffect get(int);
     method public static android.os.VibrationEffect get(int, boolean);
     method @Nullable public static android.os.VibrationEffect get(android.net.Uri, android.content.Context);
@@ -1919,6 +1933,7 @@
   }
 
   public static final class VibrationEffect.Composed extends android.os.VibrationEffect {
+    method @Nullable public long[] computeCreateWaveformOffOnTimingsOrNull();
     method public long getDuration();
     method public int getRepeatIndex();
     method @NonNull public java.util.List<android.os.vibrator.VibrationEffectSegment> getSegments();
@@ -2882,6 +2897,10 @@
     method @NonNull public android.view.Display.Mode.Builder setResolution(int, int);
   }
 
+  public final class DisplayShape implements android.os.Parcelable {
+    method @NonNull public static android.view.DisplayShape fromSpecString(@NonNull String, float, int, int);
+  }
+
   public class FocusFinder {
     method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
   }
@@ -3264,6 +3283,7 @@
 
   public class Spinner extends android.widget.AbsSpinner implements android.content.DialogInterface.OnClickListener {
     method public boolean isPopupShowing();
+    method public void onClick(int);
   }
 
   @android.widget.RemoteViews.RemoteView public class TextClock extends android.widget.TextView {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index af0fa39..a4a12d7 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -417,6 +417,16 @@
     ],
 }
 
+// This file group is used by service fuzzer
+filegroup {
+    name: "framework-core-sources-for-fuzzers",
+    srcs: [
+        "android/os/IInterface.java",
+        "android/os/Binder.java",
+        "android/os/IBinder.java",
+    ],
+}
+
 aidl_interface {
     name: "android.os.statsbootstrap_aidl",
     unstable: true,
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 02a81ac..968ed87 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -54,6 +54,7 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
@@ -797,6 +798,8 @@
 
     private FingerprintGestureController mFingerprintGestureController;
 
+    private int mMotionEventSources;
+
     /**
      * Callback for {@link android.view.accessibility.AccessibilityEvent}s.
      *
@@ -820,7 +823,11 @@
             for (int i = 0; i < mMagnificationControllers.size(); i++) {
                 mMagnificationControllers.valueAt(i).onServiceConnectedLocked();
             }
-            updateInputMethod(getServiceInfo());
+            final AccessibilityServiceInfo info = getServiceInfo();
+            if (info != null) {
+                updateInputMethod(info);
+                mMotionEventSources = info.getMotionEventSources();
+            }
         }
         if (mSoftKeyboardController != null) {
             mSoftKeyboardController.onServiceConnected();
@@ -946,6 +953,25 @@
     }
 
     /**
+     * Callback that allows an accessibility service to observe generic {@link MotionEvent}s.
+     * <p>
+     * Prefer {@link TouchInteractionController} to observe and control touchscreen events,
+     * including touch gestures. If this or any enabled service is using
+     * {@link AccessibilityServiceInfo#FLAG_REQUEST_TOUCH_EXPLORATION_MODE} then
+     * {@link #onMotionEvent} will not receive touchscreen events.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> The service must first request to listen to events using
+     * {@link AccessibilityServiceInfo#setMotionEventSources}.
+     * {@link MotionEvent}s from sources in {@link AccessibilityServiceInfo#getMotionEventSources()}
+     * are not sent to the rest of the system. To stop listening to events from a given source, call
+     * {@link AccessibilityServiceInfo#setMotionEventSources} with that source removed.
+     * </p>
+     * @param event The event to be processed.
+     */
+    public void onMotionEvent(@NonNull MotionEvent event) { }
+
+    /**
      * Gets the windows on the screen of the default display. This method returns only the windows
      * that a sighted user can interact with, as opposed to all windows.
      * For example, if there is a modal dialog shown and the user cannot touch
@@ -2521,6 +2547,7 @@
     public final void setServiceInfo(AccessibilityServiceInfo info) {
         mInfo = info;
         updateInputMethod(info);
+        mMotionEventSources = info.getMotionEventSources();
         sendServiceInfo();
     }
 
@@ -2724,7 +2751,7 @@
 
             @Override
             public void onMotionEvent(MotionEvent event) {
-                AccessibilityService.this.onMotionEvent(event);
+                AccessibilityService.this.sendMotionEventToCallback(event);
             }
 
             @Override
@@ -3359,14 +3386,23 @@
         }
     }
 
-    void onMotionEvent(MotionEvent event) {
-        TouchInteractionController controller;
-        synchronized (mLock) {
-            int displayId = event.getDisplayId();
-            controller = mTouchInteractionControllers.get(displayId);
+    void sendMotionEventToCallback(MotionEvent event) {
+        boolean sendingTouchEventToTouchInteractionController = false;
+        if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
+            TouchInteractionController controller;
+            synchronized (mLock) {
+                int displayId = event.getDisplayId();
+                controller = mTouchInteractionControllers.get(displayId);
+            }
+            if (controller != null) {
+                sendingTouchEventToTouchInteractionController = true;
+                controller.onMotionEvent(event);
+            }
         }
-        if (controller != null) {
-            controller.onMotionEvent(event);
+        final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
+        if ((mMotionEventSources & eventSourceWithoutClass) != 0
+                && !sendingTouchEventToTouchInteractionController) {
+            onMotionEvent(event);
         }
     }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 295eaaf..ae57959 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -612,6 +612,12 @@
     private boolean mIsAccessibilityTool = false;
 
     /**
+     * The bit mask of {@link android.view.InputDevice} sources that the accessibility
+     * service wants to listen to for generic {@link android.view.MotionEvent}s.
+     */
+    private int mMotionEventSources = 0;
+
+    /**
      * Creates a new instance.
      */
     public AccessibilityServiceInfo() {
@@ -785,6 +791,7 @@
         mNonInteractiveUiTimeout = other.mNonInteractiveUiTimeout;
         mInteractiveUiTimeout = other.mInteractiveUiTimeout;
         flags = other.flags;
+        mMotionEventSources = other.mMotionEventSources;
         // NOTE: Ensure that only properties that are safe to be modified by the service itself
         // are included here (regardless of hidden setters, etc.).
     }
@@ -956,6 +963,44 @@
     }
 
     /**
+     * Returns the bit mask of {@link android.view.InputDevice} sources that the accessibility
+     * service wants to listen to for generic {@link android.view.MotionEvent}s.
+     */
+    public int getMotionEventSources() {
+        return mMotionEventSources;
+    }
+
+    /**
+     * Sets the bit mask of {@link android.view.InputDevice} sources that the accessibility
+     * service wants to listen to for generic {@link android.view.MotionEvent}s.
+     *
+     * <p>
+     * Note: including an {@link android.view.InputDevice} source that does not send
+     * {@link android.view.MotionEvent}s is effectively a no-op for that source, since you will
+     * not receive any events from that source.
+     * </p>
+     * <p>
+     * Allowed sources include:
+     * <li>{@link android.view.InputDevice#SOURCE_MOUSE}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_STYLUS}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_BLUETOOTH_STYLUS}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_TRACKBALL}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_MOUSE_RELATIVE}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_TOUCHPAD}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_TOUCH_NAVIGATION}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_ROTARY_ENCODER}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_JOYSTICK}</li>
+     * <li>{@link android.view.InputDevice#SOURCE_SENSOR}</li>
+     * </p>
+     *
+     * @param motionEventSources A bit mask of {@link android.view.InputDevice} sources.
+     * @see AccessibilityService#onMotionEvent
+     */
+    public void setMotionEventSources(int motionEventSources) {
+        mMotionEventSources = motionEventSources;
+    }
+
+    /**
      * The localized summary of the accessibility service.
      * <p>
      *    <strong>Statically set from
@@ -1179,6 +1224,7 @@
         parcel.writeBoolean(mIsAccessibilityTool);
         parcel.writeString(mTileServiceName);
         parcel.writeInt(mIntroResId);
+        parcel.writeInt(mMotionEventSources);
     }
 
     private void initFromParcel(Parcel parcel) {
@@ -1203,6 +1249,7 @@
         mIsAccessibilityTool = parcel.readBoolean();
         mTileServiceName = parcel.readString();
         mIntroResId = parcel.readInt();
+        mMotionEventSources = parcel.readInt();
     }
 
     @Override
diff --git a/core/java/android/accounts/ChooseTypeAndAccountActivity.java b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
index 4d4a4d7..e447d86 100644
--- a/core/java/android/accounts/ChooseTypeAndAccountActivity.java
+++ b/core/java/android/accounts/ChooseTypeAndAccountActivity.java
@@ -402,7 +402,7 @@
                 mExistingAccounts = AccountManager.get(this).getAccountsForPackage(mCallingPackage,
                         mCallingUid);
                 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_NEW_TASK);
-                startActivityForResult(intent, REQUEST_ADD_ACCOUNT);
+                startActivityForResult(new Intent(intent), REQUEST_ADD_ACCOUNT);
                 return;
             }
         } catch (OperationCanceledException e) {
diff --git a/core/java/android/app/ActivityClient.java b/core/java/android/app/ActivityClient.java
index 4cf48ab..324b8e7 100644
--- a/core/java/android/app/ActivityClient.java
+++ b/core/java/android/app/ActivityClient.java
@@ -227,12 +227,13 @@
     }
 
     /**
-     * Returns the windowing mode of the task that hosts the activity, or {@code -1} if task is not
-     * found.
+     * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if
+     * the task {@link Configuration} cannot be obtained.
      */
-    public int getTaskWindowingMode(IBinder activityToken) {
+    @Nullable
+    public Configuration getTaskConfiguration(IBinder activityToken) {
         try {
-            return getActivityClientController().getTaskWindowingMode(activityToken);
+            return getActivityClientController().getTaskConfiguration(activityToken);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a61ade0..2dccd4d 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -47,6 +47,8 @@
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
 import android.app.servertransaction.ActivityLifecycleItem;
 import android.app.servertransaction.ActivityLifecycleItem.LifecycleState;
 import android.app.servertransaction.ActivityRelaunchItem;
@@ -500,6 +502,7 @@
 
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     static volatile Handler sMainThreadHandler;  // set once in main()
+    private long mStartSeq; // Only accesssed from the main thread
 
     Bundle mCoreSettings = null;
 
@@ -799,7 +802,7 @@
         ApplicationInfo appInfo;
         int backupMode;
         int userId;
-        int operationType;
+        @BackupDestination int backupDestination;
         public String toString() {
             return "CreateBackupAgentData{appInfo=" + appInfo
                     + " backupAgent=" + appInfo.backupAgentName
@@ -1034,12 +1037,12 @@
         }
 
         public final void scheduleCreateBackupAgent(ApplicationInfo app,
-                int backupMode, int userId, int operationType) {
+                int backupMode, int userId, @BackupDestination int backupDestination) {
             CreateBackupAgentData d = new CreateBackupAgentData();
             d.appInfo = app;
             d.backupMode = backupMode;
             d.userId = userId;
-            d.operationType = operationType;
+            d.backupDestination = backupDestination;
 
             sendMessage(H.CREATE_BACKUP_AGENT, d);
         }
@@ -4402,7 +4405,8 @@
                     context.setOuterContext(agent);
                     agent.attach(context);
 
-                    agent.onCreate(UserHandle.of(data.userId), data.operationType);
+                    agent.onCreate(UserHandle.of(data.userId), data.backupDestination,
+                            getOperationTypeFromBackupMode(data.backupMode));
                     binder = agent.onBind();
                     backupAgents.put(packageName, agent);
                 } catch (Exception e) {
@@ -4430,6 +4434,22 @@
         }
     }
 
+    @OperationType
+    private static int getOperationTypeFromBackupMode(int backupMode) {
+        switch (backupMode) {
+            case ApplicationThreadConstants.BACKUP_MODE_RESTORE:
+            case ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL:
+                return OperationType.RESTORE;
+            case ApplicationThreadConstants.BACKUP_MODE_FULL:
+            case ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL:
+                return OperationType.BACKUP;
+            default:
+                Slog.w(TAG, "Invalid backup mode when initialising BackupAgent: "
+                        + backupMode);
+                return OperationType.UNKNOWN;
+        }
+    }
+
     private String getBackupAgentName(CreateBackupAgentData data) {
         String agentName = data.appInfo.backupAgentName;
         // full backup operation but no app-supplied agent?  use the default implementation
@@ -4743,14 +4763,16 @@
         if (s != null) {
             try {
                 if (localLOGV) Slog.v(TAG, "Timeout short service " + s);
-                s.callOnTimeout(startId);
 
-                // TODO(short-service): Do we need "service executing" for timeout?
-                // (see handleStopService())
+                // Unlike other service callbacks, we don't do serviceDoneExecuting() here.
+                // "service executing" state is used to boost the procstate / oom-adj, but
+                // for short-FGS timeout, we have a specific control for them anyway, so
+                // we don't have to do that.
+                s.callOnTimeout(startId);
             } catch (Exception e) {
                 if (!mInstrumentation.onException(s, e)) {
                     throw new RuntimeException(
-                            "Unable to timeout service " + s
+                            "Unable to call onTimeout on service " + s
                                     + ": " + e.toString(), e);
                 }
                 Slog.i(TAG, "handleTimeoutService: exception for " + token, e);
@@ -6407,23 +6429,28 @@
     }
 
     private void handleTrimMemory(int level) {
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory");
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "trimMemory: " + level);
+        }
         if (DEBUG_MEMORY_TRIM) Slog.v(TAG, "Trimming memory to level: " + level);
 
-        if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
-            PropertyInvalidatedCache.onTrimMemory();
-        }
+        try {
+            if (level >= ComponentCallbacks2.TRIM_MEMORY_COMPLETE) {
+                PropertyInvalidatedCache.onTrimMemory();
+            }
 
-        final ArrayList<ComponentCallbacks2> callbacks =
-                collectComponentCallbacks(true /* includeUiContexts */);
+            final ArrayList<ComponentCallbacks2> callbacks =
+                    collectComponentCallbacks(true /* includeUiContexts */);
 
-        final int N = callbacks.size();
-        for (int i = 0; i < N; i++) {
-            callbacks.get(i).onTrimMemory(level);
+            final int N = callbacks.size();
+            for (int i = 0; i < N; i++) {
+                callbacks.get(i).onTrimMemory(level);
+            }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
 
         WindowManagerGlobal.getInstance().trimMemory(level);
-        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
         if (SystemProperties.getInt("debug.am.run_gc_trim_level", Integer.MAX_VALUE) <= level) {
             unscheduleGcIdler();
@@ -6658,34 +6685,6 @@
         StrictMode.initThreadDefaults(data.appInfo);
         StrictMode.initVmDefaults(data.appInfo);
 
-        if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) {
-            // XXX should have option to change the port.
-            Debug.changeDebugPort(8100);
-            if (data.debugMode == ApplicationThreadConstants.DEBUG_WAIT) {
-                Slog.w(TAG, "Application " + data.info.getPackageName()
-                      + " is waiting for the debugger on port 8100...");
-
-                IActivityManager mgr = ActivityManager.getService();
-                try {
-                    mgr.showWaitingForDebugger(mAppThread, true);
-                } catch (RemoteException ex) {
-                    throw ex.rethrowFromSystemServer();
-                }
-
-                Debug.waitForDebugger();
-
-                try {
-                    mgr.showWaitingForDebugger(mAppThread, false);
-                } catch (RemoteException ex) {
-                    throw ex.rethrowFromSystemServer();
-                }
-
-            } else {
-                Slog.w(TAG, "Application " + data.info.getPackageName()
-                      + " can be debugged on port 8100...");
-            }
-        }
-
         // Allow binder tracing, and application-generated systrace messages if we're profileable.
         boolean isAppDebuggable = (data.appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         boolean isAppProfileable = isAppDebuggable || data.appInfo.isProfileable();
@@ -6785,6 +6784,42 @@
         Application app;
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
         final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
+
+        final IActivityManager mgr = ActivityManager.getService();
+        try {
+            mgr.finishAttachApplication(mStartSeq);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+
+        // Wait for debugger after we have notified the system to finish attach application
+        if (data.debugMode != ApplicationThreadConstants.DEBUG_OFF) {
+            // XXX should have option to change the port.
+            Debug.changeDebugPort(8100);
+            if (data.debugMode == ApplicationThreadConstants.DEBUG_WAIT) {
+                Slog.w(TAG, "Application " + data.info.getPackageName()
+                        + " is waiting for the debugger on port 8100...");
+
+                try {
+                    mgr.showWaitingForDebugger(mAppThread, true);
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+
+                Debug.waitForDebugger();
+
+                try {
+                    mgr.showWaitingForDebugger(mAppThread, false);
+                } catch (RemoteException ex) {
+                    throw ex.rethrowFromSystemServer();
+                }
+
+            } else {
+                Slog.w(TAG, "Application " + data.info.getPackageName()
+                        + " can be debugged on port 8100...");
+            }
+        }
+
         try {
             // If the app is being launched for full backup or restore, bring it up in
             // a restricted environment with the base application class.
@@ -7625,6 +7660,8 @@
         sCurrentActivityThread = this;
         mConfigurationController = new ConfigurationController(this);
         mSystemThread = system;
+        mStartSeq = startSeq;
+
         if (!system) {
             android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
                                                     UserHandle.myUserId());
diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java
index f25e639..9d5c01a 100644
--- a/core/java/android/app/BroadcastOptions.java
+++ b/core/java/android/app/BroadcastOptions.java
@@ -767,11 +767,11 @@
      */
     @SystemApi
     public void setDeliveryGroupMatchingKey(@NonNull String namespace, @NonNull String key) {
-        Preconditions.checkArgument(!namespace.contains("/"),
-                "namespace should not contain '/'");
-        Preconditions.checkArgument(!key.contains("/"),
-                "key should not contain '/'");
-        mDeliveryGroupMatchingKey = namespace + "/" + key;
+        Preconditions.checkArgument(!namespace.contains(":"),
+                "namespace should not contain ':'");
+        Preconditions.checkArgument(!key.contains(":"),
+                "key should not contain ':'");
+        mDeliveryGroupMatchingKey = namespace + ":" + key;
     }
 
     /**
@@ -779,7 +779,7 @@
      * broadcast belongs to.
      *
      * @return the delivery group namespace and key that was previously set using
-     *         {@link #setDeliveryGroupMatchingKey(String, String)}, concatenated with a {@code /}.
+     *         {@link #setDeliveryGroupMatchingKey(String, String)}, concatenated with a {@code :}.
      * @hide
      */
     @SystemApi
diff --git a/core/java/android/app/ForegroundServiceTypeException.java b/core/java/android/app/ForegroundServiceTypeException.java
new file mode 100644
index 0000000..9a9180e
--- /dev/null
+++ b/core/java/android/app/ForegroundServiceTypeException.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+
+/**
+ * Base exception thrown when an app tries to start a foreground {@link Service}
+ * without a valid type.
+ */
+public abstract class ForegroundServiceTypeException extends ServiceStartNotAllowedException {
+    /**
+     * Constructor.
+     */
+    public ForegroundServiceTypeException(@NonNull String message) {
+        super(message);
+    }
+}
diff --git a/core/java/android/app/ForegroundServiceTypeNotAllowedException.java b/core/java/android/app/ForegroundServiceTypeNotAllowedException.java
deleted file mode 100644
index c258242..0000000
--- a/core/java/android/app/ForegroundServiceTypeNotAllowedException.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.app;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Exception thrown when an app tries to start a foreground {@link Service} without a valid type.
- */
-public final class ForegroundServiceTypeNotAllowedException
-        extends ServiceStartNotAllowedException implements Parcelable {
-    /**
-     * Constructor.
-     */
-    public ForegroundServiceTypeNotAllowedException(@NonNull String message) {
-        super(message);
-    }
-
-    ForegroundServiceTypeNotAllowedException(@NonNull Parcel source) {
-        super(source.readString());
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeString(getMessage());
-    }
-
-    public static final @NonNull Creator<android.app.ForegroundServiceTypeNotAllowedException>
-            CREATOR = new Creator<android.app.ForegroundServiceTypeNotAllowedException>() {
-                @NonNull
-                public android.app.ForegroundServiceTypeNotAllowedException createFromParcel(
-                        Parcel source) {
-                    return new android.app.ForegroundServiceTypeNotAllowedException(source);
-                }
-
-                @NonNull
-                public android.app.ForegroundServiceTypeNotAllowedException[] newArray(int size) {
-                    return new android.app.ForegroundServiceTypeNotAllowedException[size];
-                }
-            };
-}
diff --git a/core/java/android/app/ForegroundServiceTypePolicy.java b/core/java/android/app/ForegroundServiceTypePolicy.java
index e419e06..e99e360 100644
--- a/core/java/android/app/ForegroundServiceTypePolicy.java
+++ b/core/java/android/app/ForegroundServiceTypePolicy.java
@@ -23,8 +23,10 @@
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CONNECTED_DEVICE;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_HEALTH;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
@@ -47,14 +49,17 @@
 import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.Overridable;
 import android.content.Context;
+import android.content.PermissionChecker;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.content.pm.ServiceInfo.ForegroundServiceType;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbManager;
+import android.healthconnect.HealthConnectManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.permission.PermissionCheckerManager;
 import android.util.ArraySet;
 import android.util.SparseArray;
 
@@ -65,8 +70,10 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Optional;
+import java.util.Set;
 
 /**
  * This class enforces the policies around the foreground service types.
@@ -153,6 +160,20 @@
     public static final long FGS_TYPE_PERMISSION_CHANGE_ID = 254662522L;
 
     /**
+     * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST}.
+     *
+     * @hide
+     */
+    public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_MANIFEST =
+            new ForegroundServiceTypePolicyInfo(
+            FOREGROUND_SERVICE_TYPE_MANIFEST,
+            FGS_TYPE_NONE_DEPRECATION_CHANGE_ID,
+            FGS_TYPE_NONE_DISABLED_CHANGE_ID,
+            null,
+            null
+    );
+
+    /**
      * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}.
      *
      * @hide
@@ -392,6 +413,22 @@
     );
 
     /**
+     * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT}.
+     *
+     * @hide
+     */
+    public static final @NonNull ForegroundServiceTypePolicyInfo FGS_TYPE_POLICY_FILE_MANAGEMENT =
+            new ForegroundServiceTypePolicyInfo(
+            FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT,
+            ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+            ForegroundServiceTypePolicyInfo.INVALID_CHANGE_ID,
+            new ForegroundServiceTypePermissions(new ForegroundServiceTypePermission[] {
+                new RegularPermission(Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT)
+            }, true),
+            null
+    );
+
+    /**
      * The policy for the {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE}.
      *
      * @hide
@@ -640,11 +677,12 @@
          *
          * For test only.
          */
-        public @NonNull Optional<String[]> getRequiredAllOfPermissionsForTest() {
+        public @NonNull Optional<String[]> getRequiredAllOfPermissionsForTest(
+                @NonNull Context context) {
             if (mAllOfPermissions == null) {
                 return Optional.empty();
             }
-            return Optional.of(mAllOfPermissions.toStringArray());
+            return Optional.of(mAllOfPermissions.toStringArray(context));
         }
 
         /**
@@ -653,11 +691,12 @@
          *
          * For test only.
          */
-        public @NonNull Optional<String[]> getRequiredAnyOfPermissionsForTest() {
+        public @NonNull Optional<String[]> getRequiredAnyOfPermissionsForTest(
+                @NonNull Context context) {
             if (mAnyOfPermissions == null) {
                 return Optional.empty();
             }
-            return Optional.of(mAnyOfPermissions.toStringArray());
+            return Optional.of(mAnyOfPermissions.toStringArray(context));
         }
 
         /**
@@ -793,12 +832,12 @@
             return sb.toString();
         }
 
-        @NonNull String[] toStringArray() {
-            final String[] names = new String[mPermissions.length];
+        @NonNull String[] toStringArray(Context context) {
+            final ArrayList<String> list = new ArrayList<>();
             for (int i = 0; i < mPermissions.length; i++) {
-                names[i] = mPermissions[i].mName;
+                mPermissions[i].addToList(context, list);
             }
-            return names;
+            return list.toArray(new String[list.size()]);
         }
     }
 
@@ -811,7 +850,7 @@
         /**
          * The name of this permission.
          */
-        final @NonNull String mName;
+        protected final @NonNull String mName;
 
         /**
          * Constructor.
@@ -831,6 +870,10 @@
         public String toString() {
             return mName;
         }
+
+        void addToList(@NonNull Context context, @NonNull ArrayList<String> list) {
+            list.add(mName);
+        }
     }
 
     /**
@@ -844,15 +887,25 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
+            return checkPermission(context, mName, callerUid, callerPid, packageName,
+                    allowWhileInUse);
+        }
+
+        @SuppressLint("AndroidFrameworkRequiresPermission")
+        @PackageManager.PermissionResult
+        int checkPermission(@NonNull Context context, @NonNull String name, int callerUid,
+                int callerPid, String packageName, boolean allowWhileInUse) {
             // Simple case, check if it's already granted.
-            if (context.checkPermission(mName, callerPid, callerUid) == PERMISSION_GRANTED) {
+            @PackageManager.PermissionResult int result;
+            if ((result = PermissionChecker.checkPermissionForPreflight(context, name,
+                    callerPid, callerUid, packageName)) == PERMISSION_GRANTED) {
                 return PERMISSION_GRANTED;
             }
-            if (allowWhileInUse) {
+            if (allowWhileInUse && result == PermissionCheckerManager.PERMISSION_SOFT_DENIED) {
                 // Check its appops
-                final int opCode = AppOpsManager.permissionToOpCode(mName);
+                final int opCode = AppOpsManager.permissionToOpCode(name);
                 final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
                 if (opCode != AppOpsManager.OP_NONE) {
                     final int currentMode = appOpsManager.unsafeCheckOpRawNoThrow(opCode, callerUid,
@@ -880,7 +933,7 @@
 
         @Override
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class);
             final int mode = appOpsManager.unsafeCheckOpRawNoThrow(mOpCode, callerUid, packageName);
@@ -900,7 +953,7 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final UsbManager usbManager = context.getSystemService(UsbManager.class);
             final HashMap<String, UsbDevice> devices = usbManager.getDeviceList();
@@ -926,7 +979,7 @@
         @Override
         @SuppressLint("AndroidFrameworkRequiresPermission")
         @PackageManager.PermissionResult
-        public int checkPermission(Context context, int callerUid, int callerPid,
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
                 String packageName, boolean allowWhileInUse) {
             final UsbManager usbManager = context.getSystemService(UsbManager.class);
             final UsbAccessory[] accessories = usbManager.getAccessoryList();
@@ -941,6 +994,45 @@
         }
     }
 
+    static class HealthConnectPermission extends RegularPermission {
+        private @Nullable String[] mPermissionNames;
+
+        HealthConnectPermission() {
+            super("Health Connect");
+        }
+
+        @Override
+        @SuppressLint("AndroidFrameworkRequiresPermission")
+        @PackageManager.PermissionResult
+        public int checkPermission(@NonNull Context context, int callerUid, int callerPid,
+                String packageName, boolean allowWhileInUse) {
+            final String[] perms = getPermissions(context);
+            for (String perm : perms) {
+                if (checkPermission(context, perm, callerUid, callerPid,
+                        packageName, allowWhileInUse) == PERMISSION_GRANTED) {
+                    return PERMISSION_GRANTED;
+                }
+            }
+            return PERMISSION_DENIED;
+        }
+
+        @Override
+        void addToList(@NonNull Context context, @NonNull ArrayList<String> list) {
+            final String[] perms = getPermissions(context);
+            for (String perm : perms) {
+                list.add(perm);
+            }
+        }
+
+        private @NonNull String[] getPermissions(@NonNull Context context) {
+            if (mPermissionNames != null) {
+                return mPermissionNames;
+            }
+            final Set<String> healthPerms = HealthConnectManager.getHealthPermissions(context);
+            return mPermissionNames = healthPerms.toArray(new String[healthPerms.size()]);
+        }
+    }
+
     /**
      * The default policy for the foreground service types.
      *
@@ -954,6 +1046,8 @@
          * Constructor
          */
         public DefaultForegroundServiceTypePolicy() {
+            mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_MANIFEST,
+                    FGS_TYPE_POLICY_MANIFEST);
             mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_NONE,
                     FGS_TYPE_POLICY_NONE);
             mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_DATA_SYNC,
@@ -980,6 +1074,8 @@
                     FGS_TYPE_POLICY_SYSTEM_EXEMPTED);
             mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
                     FGS_TYPE_POLICY_SHORT_SERVICE);
+            mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT,
+                    FGS_TYPE_POLICY_FILE_MANAGEMENT);
             mForegroundServiceTypePolicies.put(FOREGROUND_SERVICE_TYPE_SPECIAL_USE,
                     FGS_TYPE_POLICY_SPECIAL_USE);
         }
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index f92194d..2f51b17 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -213,7 +213,7 @@
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
     public @GameMode int[] getAvailableGameModes(@NonNull String packageName) {
         try {
-            return mService.getAvailableGameModes(packageName);
+            return mService.getAvailableGameModes(packageName, mContext.getUserId());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/IActivityClientController.aidl b/core/java/android/app/IActivityClientController.aidl
index 62481ba..8b655b9 100644
--- a/core/java/android/app/IActivityClientController.aidl
+++ b/core/java/android/app/IActivityClientController.aidl
@@ -78,7 +78,11 @@
     boolean willActivityBeVisible(in IBinder token);
     int getDisplayId(in IBinder activityToken);
     int getTaskForActivity(in IBinder token, in boolean onlyRoot);
-    int getTaskWindowingMode(in IBinder activityToken);
+    /**
+     * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if
+     * the task {@link Configuration} cannot be obtained.
+     */
+    Configuration getTaskConfiguration(in IBinder activityToken);
     IBinder getActivityTokenBelow(IBinder token);
     ComponentName getCallingActivity(in IBinder token);
     String getCallingPackage(in IBinder token);
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 7475ef8..040111c 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -147,6 +147,7 @@
     oneway void finishReceiver(in IBinder who, int resultCode, in String resultData, in Bundle map,
             boolean abortBroadcast, int flags);
     void attachApplication(in IApplicationThread app, long startSeq);
+    void finishAttachApplication(long startSeq);
     List<ActivityManager.RunningTaskInfo> getTasks(int maxNum);
     @UnsupportedAppUsage
     void moveTaskToFront(in IApplicationThread caller, in String callingPackage, int task,
@@ -304,7 +305,7 @@
     @UnsupportedAppUsage
     void resumeAppSwitches();
     boolean bindBackupAgent(in String packageName, int backupRestoreMode, int targetUserId,
-            int operationType);
+            int backupDestination);
     void backupAgentCreated(in String packageName, in IBinder agent, int userId);
     void unbindBackupAgent(in ApplicationInfo appInfo);
     int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
@@ -718,8 +719,8 @@
 
     /**
      * Control the app freezer state. Returns true in case of success, false if the operation
-     * didn't succeed (for example, when the app freezer isn't supported). 
-     * Handling the freezer state via this method is reentrant, that is it can be 
+     * didn't succeed (for example, when the app freezer isn't supported).
+     * Handling the freezer state via this method is reentrant, that is it can be
      * disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to
      * enable match, the freezer is re-enabled at last enable only.
      * @param enable set it to true to enable the app freezer, false to disable it.
@@ -798,4 +799,7 @@
      * <p>Typically used only by automotive builds when the vehicle has multiple displays.
      */
     @nullable int[] getSecondaryDisplayIdsForStartingBackgroundUsers();
+
+    /** Returns if the service is a short-service is still "alive" and past the timeout. */
+    boolean shouldServiceTimeOut(in ComponentName className, in IBinder token);
 }
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index aea097d..3d6ab6f 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -29,7 +29,7 @@
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
     void setGameMode(String packageName, int gameMode, int userId);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
-    int[] getAvailableGameModes(String packageName);
+    int[] getAvailableGameModes(String packageName, int userId);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
     boolean isAngleEnabled(String packageName, int userId);
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_GAME_MODE)")
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 623af5f..fbb0748 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -40,6 +40,7 @@
     void connect(IAccessibilityServiceClient client, int flags);
     void disconnect();
     boolean injectInputEvent(in InputEvent event, boolean sync, boolean waitForAnimations);
+    void injectInputEventToInputFilter(in InputEvent event);
     void syncInputTransactions(boolean waitForAnimations);
     boolean setRotation(int rotation);
     Bitmap takeScreenshot(in Rect crop);
diff --git a/core/java/android/app/InvalidForegroundServiceTypeException.java b/core/java/android/app/InvalidForegroundServiceTypeException.java
new file mode 100644
index 0000000..6ff0262
--- /dev/null
+++ b/core/java/android/app/InvalidForegroundServiceTypeException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception thrown when an app tries to start a foreground {@link Service} with an invalid type.
+ */
+public final class InvalidForegroundServiceTypeException
+        extends ForegroundServiceTypeException implements Parcelable {
+    /**
+     * Constructor.
+     */
+    public InvalidForegroundServiceTypeException(@NonNull String message) {
+        super(message);
+    }
+
+    InvalidForegroundServiceTypeException(@NonNull Parcel source) {
+        super(source.readString());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(getMessage());
+    }
+
+    public static final @NonNull Creator<android.app.InvalidForegroundServiceTypeException>
+            CREATOR = new Creator<android.app.InvalidForegroundServiceTypeException>() {
+                @NonNull
+                public android.app.InvalidForegroundServiceTypeException createFromParcel(
+                        Parcel source) {
+                    return new android.app.InvalidForegroundServiceTypeException(source);
+                }
+
+                @NonNull
+                public android.app.InvalidForegroundServiceTypeException[] newArray(int size) {
+                    return new android.app.InvalidForegroundServiceTypeException[size];
+                }
+            };
+}
diff --git a/core/java/android/app/MissingForegroundServiceTypeException.java b/core/java/android/app/MissingForegroundServiceTypeException.java
new file mode 100644
index 0000000..c9b2006
--- /dev/null
+++ b/core/java/android/app/MissingForegroundServiceTypeException.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.app;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Exception thrown when an app tries to start a foreground {@link Service} without a type.
+ */
+public final class MissingForegroundServiceTypeException
+        extends ForegroundServiceTypeException implements Parcelable {
+    /**
+     * Constructor.
+     */
+    public MissingForegroundServiceTypeException(@NonNull String message) {
+        super(message);
+    }
+
+    MissingForegroundServiceTypeException(@NonNull Parcel source) {
+        super(source.readString());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString(getMessage());
+    }
+
+    public static final @NonNull Creator<android.app.MissingForegroundServiceTypeException>
+            CREATOR = new Creator<android.app.MissingForegroundServiceTypeException>() {
+                @NonNull
+                public android.app.MissingForegroundServiceTypeException createFromParcel(
+                        Parcel source) {
+                    return new android.app.MissingForegroundServiceTypeException(source);
+                }
+
+                @NonNull
+                public android.app.MissingForegroundServiceTypeException[] newArray(int size) {
+                    return new android.app.MissingForegroundServiceTypeException[size];
+                }
+            };
+}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 291edbb..0ab96a9 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -748,7 +748,12 @@
      * If the app targeting API is
      * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
      * becoming foreground service due to background restriction.
-     * @throws ForegroundServiceTypeNotAllowedException
+     * @throws InvalidForegroundServiceTypeException
+     * If the app targeting API is
+     * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute
+     * {@link android.R.attr#foregroundServiceType} is set to invalid types(i.e.
+     * {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}).
+     * @throws MissingForegroundServiceTypeException
      * If the app targeting API is
      * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute
      * {@link android.R.attr#foregroundServiceType} is not set.
@@ -761,7 +766,7 @@
      * {@link NotificationManager#notify(int, Notification)
      * NotificationManager.notify(int, Notification)}; must not be 0.
      * @param notification The Notification to be displayed.
-     * 
+     *
      * @see #stopForeground(boolean)
      */
     public final void startForeground(int id, Notification notification) {
@@ -832,11 +837,16 @@
      * If the app targeting API is
      * {@link android.os.Build.VERSION_CODES#S} or later, and the service is restricted from
      * becoming foreground service due to background restriction.
-     * @throws ForegroundServiceTypeNotAllowedException
+     * @throws InvalidForegroundServiceTypeException
      * If the app targeting API is
      * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute
-     * {@link android.R.attr#foregroundServiceType} is not set, or the param
-     * {@code foregroundServiceType} is {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}.
+     * {@link android.R.attr#foregroundServiceType} or the param {@code foregroundServiceType}
+     * is set to invalid types(i.e.{@link ServiceInfo#FOREGROUND_SERVICE_TYPE_NONE}).
+     * @throws MissingForegroundServiceTypeException
+     * If the app targeting API is
+     * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later, and the manifest attribute
+     * {@link android.R.attr#foregroundServiceType} is not set and the param
+     * {@code foregroundServiceType} is set to {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_MANIFEST}.
      * @throws SecurityException If the app targeting API is
      * {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} or later and doesn't have the
      * permission to start the foreground service with the specified type in
@@ -1109,21 +1119,30 @@
 
     /** @hide */
     public final void callOnTimeout(int startId) {
-        // TODO(short-service): Do we need any check here, to avoid races?
-        // e.g. if the service is already stopped, but ActivityThread.handleTimeoutService() is
-        // already scheduled, then we'll call this method anyway. It should be doable to prevent
-        // that if we keep track of startForeground, stopForeground, and onDestroy.
+        // Note, because all the service callbacks (and other similar callbacks, e.g. activity
+        // callbacks) are delivered using the main handler, it's possible the service is already
+        // stopped when before this method is called, so we do a double check here.
+        if (mToken == null) {
+            Log.w(TAG, "Service already destroyed, skipping onTimeout()");
+            return;
+        }
+        try {
+            if (!mActivityManager.shouldServiceTimeOut(
+                    new ComponentName(this, mClassName), mToken)) {
+                Log.w(TAG, "Service no longer relevant, skipping onTimeout()");
+                return;
+            }
+        } catch (RemoteException ex) {
+        }
         onTimeout(startId);
     }
 
     /**
      * Callback called on timeout for {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+     * See {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE} for more details.
      *
-     * TODO Implement it
-     * TODO Javadoc
-     *
-     * @param startId
-     * @hide
+     * @param startId the startId passed to {@link #onStartCommand(Intent, int, int)} when
+     * the service started.
      */
     public void onTimeout(int startId) {
     }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 6857984..762ac23 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -58,6 +58,7 @@
 import android.companion.ICompanionDeviceManager;
 import android.companion.virtual.IVirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceManager;
+import android.compat.Compatibility;
 import android.content.ClipboardManager;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
@@ -210,6 +211,7 @@
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.service.vr.IVrManager;
+import android.system.virtualmachine.VirtualizationFrameworkInitializer;
 import android.telecom.TelecomManager;
 import android.telephony.MmsManager;
 import android.telephony.TelephonyFrameworkInitializer;
@@ -1091,7 +1093,10 @@
                 new CachedServiceFetcher<OverlayManager>() {
             @Override
             public OverlayManager createService(ContextImpl ctx) throws ServiceNotFoundException {
-                IBinder b = ServiceManager.getServiceOrThrow(Context.OVERLAY_SERVICE);
+                final IBinder b =
+                        (Compatibility.isChangeEnabled(OverlayManager.SELF_TARGETING_OVERLAY))
+                                ? ServiceManager.getService(Context.OVERLAY_SERVICE)
+                                : ServiceManager.getServiceOrThrow(Context.OVERLAY_SERVICE);
                 return new OverlayManager(ctx, IOverlayManager.Stub.asInterface(b));
             }});
 
@@ -1566,6 +1571,7 @@
             NearbyFrameworkInitializer.registerServiceWrappers();
             OnDevicePersonalizationFrameworkInitializer.registerServiceWrappers();
             DeviceLockFrameworkInitializer.registerServiceWrappers();
+            VirtualizationFrameworkInitializer.registerServiceWrappers();
         } finally {
             // If any of the above code throws, we're in a pretty bad shape and the process
             // will likely crash, but we'll reset it just in case there's an exception handler...
@@ -1611,6 +1617,7 @@
                 case Context.INCREMENTAL_SERVICE:
                 case Context.ETHERNET_SERVICE:
                 case Context.CONTEXTHUB_SERVICE:
+                case Context.VIRTUALIZATION_SERVICE:
                     return null;
             }
             Slog.wtf(TAG, "Manager wrapper not available: " + name);
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index ef10c0b..f133c8a 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -201,6 +201,23 @@
             "file_patterns": [
                 "(/|^)PropertyInvalidatedCache.java"
             ]
+        },
+        {
+            "name": "FrameworksCoreGameManagerTests",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                },
+                {
+                    "exclude-annotation": "org.junit.Ignore"
+                },
+                {
+                    "include-filter": "android.app"
+                }
+            ],
+            "file_patterns": [
+                "(/|^)GameManager[^/]*", "(/|^)GameMode[^/]*"
+            ]
         }
     ],
     "presubmit-large": [
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 2718054..814f38b 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -793,6 +793,24 @@
     }
 
     /**
+     * Injects an arbitrary {@link InputEvent} to the accessibility input filter, for use in testing
+     * the accessibility input filter.
+     *
+     * Events injected to the input subsystem using the standard {@link #injectInputEvent} method
+     * skip the accessibility input filter to avoid feedback loops.
+     *
+     * @hide
+     */
+    @TestApi
+    public void injectInputEventToInputFilter(@NonNull InputEvent event) {
+        try {
+            mUiAutomationConnection.injectInputEventToInputFilter(event);
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error while injecting input event to input filter", re);
+        }
+    }
+
+    /**
      * Sets the system settings values that control the scaling factor for animations. The scale
      * controls the animation playback speed for animations that respect these settings. Animations
      * that do not respect the settings values will not be affected by this function. A lower scale
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 0201c12..3e4e7cb 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -178,6 +178,11 @@
     }
 
     @Override
+    public void injectInputEventToInputFilter(InputEvent event) throws RemoteException {
+        mAccessibilityManager.injectInputEventToInputFilter(event);
+    }
+
+    @Override
     public void syncInputTransactions(boolean waitForAnimations) {
         synchronized (mLock) {
             throwIfCalledByNotTrustedUidLocked();
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index b9a7186..f5d657c 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -358,13 +358,37 @@
         }
     }
 
+    /**
+     * Convenience class representing a cached wallpaper bitmap and associated data.
+     */
+    private static class CachedWallpaper {
+        final Bitmap mCachedWallpaper;
+        final int mCachedWallpaperUserId;
+        @SetWallpaperFlags final int mWhich;
+
+        CachedWallpaper(Bitmap cachedWallpaper, int cachedWallpaperUserId,
+                @SetWallpaperFlags int which) {
+            mCachedWallpaper = cachedWallpaper;
+            mCachedWallpaperUserId = cachedWallpaperUserId;
+            mWhich = which;
+        }
+
+        /**
+         * Returns true if this object represents a valid cached bitmap for the given parameters,
+         * otherwise false.
+         */
+        boolean isValid(int userId, @SetWallpaperFlags int which) {
+            return userId == mCachedWallpaperUserId && which == mWhich
+                    && !mCachedWallpaper.isRecycled();
+        }
+    }
+
     private static class Globals extends IWallpaperManagerCallback.Stub {
         private final IWallpaperManager mService;
         private boolean mColorCallbackRegistered;
         private final ArrayList<Pair<OnColorsChangedListener, Handler>> mColorListeners =
                 new ArrayList<>();
-        private Bitmap mCachedWallpaper;
-        private int mCachedWallpaperUserId;
+        private CachedWallpaper mCachedWallpaper;
         private Bitmap mDefaultWallpaper;
         private Handler mMainLooperHandler;
         private ArrayMap<LocalWallpaperColorConsumer, ArraySet<RectF>> mLocalColorCallbackAreas =
@@ -536,6 +560,15 @@
                     false /* hardware */, cmProxy);
         }
 
+        /**
+         * Retrieves the current wallpaper Bitmap, caching the result. If this fails and
+         * `returnDefault` is set, returns the Bitmap for the default wallpaper; otherwise returns
+         * null.
+         *
+         * More sophisticated caching might a) store and compare the wallpaper ID so that
+         * consecutive calls for FLAG_SYSTEM and FLAG_LOCK could return the cached wallpaper if
+         * no lock screen wallpaper is set, or b) separately cache home and lock screen wallpaper.
+         */
         public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault,
                 @SetWallpaperFlags int which, int userId, boolean hardware,
                 ColorManagementProxy cmProxy) {
@@ -549,16 +582,14 @@
                 }
             }
             synchronized (this) {
-                if (mCachedWallpaper != null && mCachedWallpaperUserId == userId
-                        && !mCachedWallpaper.isRecycled()) {
-                    return mCachedWallpaper;
+                if (mCachedWallpaper != null && mCachedWallpaper.isValid(userId, which)) {
+                    return mCachedWallpaper.mCachedWallpaper;
                 }
                 mCachedWallpaper = null;
-                mCachedWallpaperUserId = 0;
+                Bitmap currentWallpaper = null;
                 try {
-                    mCachedWallpaper = getCurrentWallpaperLocked(
-                            context, userId, hardware, cmProxy);
-                    mCachedWallpaperUserId = userId;
+                    currentWallpaper = getCurrentWallpaperLocked(
+                            context, which, userId, hardware, cmProxy);
                 } catch (OutOfMemoryError e) {
                     Log.w(TAG, "Out of memory loading the current wallpaper: " + e);
                 } catch (SecurityException e) {
@@ -570,8 +601,9 @@
                         throw e;
                     }
                 }
-                if (mCachedWallpaper != null) {
-                    return mCachedWallpaper;
+                if (currentWallpaper != null) {
+                    mCachedWallpaper = new CachedWallpaper(currentWallpaper, userId, which);
+                    return currentWallpaper;
                 }
             }
             if (returnDefault) {
@@ -587,7 +619,9 @@
             return null;
         }
 
-        public Rect peekWallpaperDimensions(Context context, boolean returnDefault, int userId) {
+        @Nullable
+        public Rect peekWallpaperDimensions(Context context, boolean returnDefault,
+                @SetWallpaperFlags int which, int userId) {
             if (mService != null) {
                 try {
                     if (!mService.isWallpaperSupported(context.getOpPackageName())) {
@@ -600,11 +634,10 @@
 
             Rect dimensions = null;
             synchronized (this) {
-                ParcelFileDescriptor pfd = null;
-                try {
-                    Bundle params = new Bundle();
-                    pfd = mService.getWallpaperWithFeature(context.getOpPackageName(),
-                            context.getAttributionTag(), this, FLAG_SYSTEM, params, userId);
+                Bundle params = new Bundle();
+                try (ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
+                        context.getOpPackageName(), context.getAttributionTag(), this, which,
+                        params, userId)) {
                     // Let's peek user wallpaper first.
                     if (pfd != null) {
                         BitmapFactory.Options options = new BitmapFactory.Options();
@@ -614,19 +647,14 @@
                     }
                 } catch (RemoteException ex) {
                     Log.w(TAG, "peek wallpaper dimensions failed", ex);
-                } finally {
-                    if (pfd != null) {
-                        try {
-                            pfd.close();
-                        } catch (IOException ignored) {
-                        }
-                    }
+                } catch (IOException ignored) {
+                    // This is only thrown on close and can be safely ignored.
                 }
             }
             // If user wallpaper is unavailable, may be the default one instead.
             if ((dimensions == null || dimensions.width() == 0 || dimensions.height() == 0)
                     && returnDefault) {
-                InputStream is = openDefaultWallpaper(context, FLAG_SYSTEM);
+                InputStream is = openDefaultWallpaper(context, which);
                 if (is != null) {
                     try {
                         BitmapFactory.Options options = new BitmapFactory.Options();
@@ -644,13 +672,12 @@
         void forgetLoadedWallpaper() {
             synchronized (this) {
                 mCachedWallpaper = null;
-                mCachedWallpaperUserId = 0;
                 mDefaultWallpaper = null;
             }
         }
 
-        private Bitmap getCurrentWallpaperLocked(Context context, int userId, boolean hardware,
-                ColorManagementProxy cmProxy) {
+        private Bitmap getCurrentWallpaperLocked(Context context, @SetWallpaperFlags int which,
+                int userId, boolean hardware, ColorManagementProxy cmProxy) {
             if (mService == null) {
                 Log.w(TAG, "WallpaperService not running");
                 return null;
@@ -659,7 +686,7 @@
             try {
                 Bundle params = new Bundle();
                 ParcelFileDescriptor pfd = mService.getWallpaperWithFeature(
-                        context.getOpPackageName(), context.getAttributionTag(), this, FLAG_SYSTEM,
+                        context.getOpPackageName(), context.getAttributionTag(), this, which,
                         params, userId);
 
                 if (pfd != null) {
@@ -1148,9 +1175,26 @@
      * @return the dimensions of system wallpaper
      * @hide
      */
+    @TestApi
+    @Nullable
     public Rect peekBitmapDimensions() {
-        return sGlobals.peekWallpaperDimensions(
-                mContext, true /* returnDefault */, mContext.getUserId());
+        return peekBitmapDimensions(FLAG_SYSTEM);
+    }
+
+    /**
+     * Peek the dimensions of given wallpaper of the user without decoding it.
+     *
+     * @param which Wallpaper type. Must be either {@link #FLAG_SYSTEM} or
+     *     {@link #FLAG_LOCK}.
+     * @return the dimensions of system wallpaper
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    public Rect peekBitmapDimensions(@SetWallpaperFlags int which) {
+        checkExactlyOneWallpaperFlagSet(which);
+        return sGlobals.peekWallpaperDimensions(mContext, true /* returnDefault */, which,
+                mContext.getUserId());
     }
 
     /**
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index a4f612d..e323e89 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -20,7 +20,8 @@
 import android.annotation.Nullable;
 import android.app.IBackupAgent;
 import android.app.QueuedWork;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -137,7 +138,7 @@
 public abstract class BackupAgent extends ContextWrapper {
     private static final String TAG = "BackupAgent";
     private static final boolean DEBUG = false;
-    private static final int DEFAULT_OPERATION_TYPE = OperationType.BACKUP;
+    private static final int DEFAULT_BACKUP_DESTINATION = BackupDestination.CLOUD;
 
     /** @hide */
     public static final int RESULT_SUCCESS = 0;
@@ -207,7 +208,7 @@
     @Nullable private UserHandle mUser;
      // This field is written from the main thread (in onCreate), and read in a Binder thread (in
      // onFullBackup that is called from system_server via Binder).
-    @OperationType private volatile int mOperationType = DEFAULT_OPERATION_TYPE;
+    @BackupDestination private volatile int mBackupDestination = DEFAULT_BACKUP_DESTINATION;
 
     Handler getHandler() {
         if (mHandler == null) {
@@ -265,13 +266,6 @@
     }
 
     /**
-     * @hide
-     */
-    public void onCreate(UserHandle user) {
-        onCreate(user, DEFAULT_OPERATION_TYPE);
-    }
-
-    /**
      * Provided as a convenience for agent implementations that need an opportunity
      * to do one-time initialization before the actual backup or restore operation
      * is begun with information about the calling user.
@@ -279,14 +273,33 @@
      *
      * @hide
      */
-    public void onCreate(UserHandle user, @OperationType int operationType) {
-        // TODO: Instantiate with the correct type using a parameter.
-        mLogger = new BackupRestoreEventLogger(BackupRestoreEventLogger.OperationType.BACKUP);
-
+    public void onCreate(UserHandle user) {
         onCreate();
+    }
 
+    /**
+     * @deprecated Use {@link BackupAgent#onCreate(UserHandle, int, int)} instead.
+     *
+     * @hide
+     */
+    @Deprecated
+    public void onCreate(UserHandle user, @BackupDestination int backupDestination) {
         mUser = user;
-        mOperationType = operationType;
+        mBackupDestination = backupDestination;
+
+        onCreate(user);
+    }
+
+    /**
+    * @hide
+    */
+    public void onCreate(UserHandle user, @BackupDestination int backupDestination,
+            @OperationType int operationType) {
+        mUser = user;
+        mBackupDestination = backupDestination;
+        mLogger = new BackupRestoreEventLogger(operationType);
+
+        onCreate(user, backupDestination);
     }
 
     /**
@@ -433,7 +446,7 @@
      */
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
         FullBackup.BackupScheme backupScheme = FullBackup.getBackupScheme(this,
-                mOperationType);
+                mBackupDestination);
         if (!backupScheme.isFullBackupEnabled(data.getTransportFlags())) {
             return;
         }
@@ -643,7 +656,7 @@
         if (includeMap == null || includeMap.size() == 0) {
             // Do entire sub-tree for the provided token.
             fullBackupFileTree(packageName, domainToken,
-                    FullBackup.getBackupScheme(this, mOperationType)
+                    FullBackup.getBackupScheme(this, mBackupDestination)
                             .tokenToDirectoryPath(domainToken),
                     filterSet, traversalExcludeSet, data);
         } else if (includeMap.get(domainToken) != null) {
@@ -815,7 +828,7 @@
                                             ArraySet<String> systemExcludes,
             FullBackupDataOutput output) {
         // Pull out the domain and set it aside to use when making the tarball.
-        String domainPath = FullBackup.getBackupScheme(this, mOperationType)
+        String domainPath = FullBackup.getBackupScheme(this, mBackupDestination)
                 .tokenToDirectoryPath(domain);
         if (domainPath == null) {
             // Should never happen.
@@ -927,7 +940,7 @@
     }
 
     private boolean isFileEligibleForRestore(File destination) throws IOException {
-        FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mOperationType);
+        FullBackup.BackupScheme bs = FullBackup.getBackupScheme(this, mBackupDestination);
         if (!bs.isFullRestoreEnabled()) {
             if (Log.isLoggable(FullBackup.TAG_XML_PARSER, Log.VERBOSE)) {
                 Log.v(FullBackup.TAG_XML_PARSER,
@@ -1001,7 +1014,7 @@
                 + " domain=" + domain + " relpath=" + path + " mode=" + mode
                 + " mtime=" + mtime);
 
-        basePath = FullBackup.getBackupScheme(this, mOperationType).tokenToDirectoryPath(
+        basePath = FullBackup.getBackupScheme(this, mBackupDestination).tokenToDirectoryPath(
                 domain);
         if (domain.equals(FullBackup.MANAGED_EXTERNAL_TREE_TOKEN)) {
             mode = -1;  // < 0 is a token to skip attempting a chmod()
diff --git a/core/java/android/app/backup/BackupAnnotations.java b/core/java/android/app/backup/BackupAnnotations.java
new file mode 100644
index 0000000..d922861
--- /dev/null
+++ b/core/java/android/app/backup/BackupAnnotations.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.backup;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotations related to Android Backup&Restore.
+ *
+ * @hide
+ */
+public class BackupAnnotations {
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            OperationType.UNKNOWN,
+            OperationType.BACKUP,
+            OperationType.RESTORE,
+    })
+    public @interface OperationType {
+        int UNKNOWN = -1;
+        int BACKUP = 0;
+        int RESTORE = 1;
+    }
+
+    /**
+     * Denotes where the backup data is going (e.g. to the cloud or directly to the other device)
+     * during backup or where it is coming from during restore.
+     *
+     * @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            BackupDestination.CLOUD,
+            BackupDestination.DEVICE_TRANSFER,
+            BackupDestination.ADB_BACKUP
+    })
+    public @interface BackupDestination {
+        // A cloud backup.
+        int CLOUD = 0;
+        // A device to device migration.
+        int DEVICE_TRANSFER = 1;
+        // An adb backup.
+        int ADB_BACKUP = 2;
+    }
+}
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index d2c7972..7255c3e 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -200,22 +200,6 @@
     @SystemApi
     public static final int ERROR_TRANSPORT_INVALID = -2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-        OperationType.BACKUP,
-        OperationType.MIGRATION,
-        OperationType.ADB_BACKUP,
-    })
-    public @interface OperationType {
-        // A backup / restore to / from an off-device location, e.g. cloud.
-        int BACKUP = 0;
-        // A direct transfer to another device.
-        int MIGRATION = 1;
-        // Backup via adb, data saved on the host machine.
-        int ADB_BACKUP = 3;
-    }
-
     private Context mContext;
     @UnsupportedAppUsage
     private static IBackupManager sService;
@@ -1034,6 +1018,29 @@
         }
     }
 
+    /**
+     * Get an instance of {@link BackupRestoreEventLogger} to report B&R related events during an
+     * ongoing backup or restore operation.
+     *
+     * @param backupAgent the agent currently running a B&R operation.
+     *
+     * @return an instance of {@code BackupRestoreEventLogger} or {@code null} if the agent has not
+     *         finished initialisation, i.e. {@link BackupAgent#onCreate()} has not been called yet.
+     * @throws IllegalStateException if called before the agent has finished initialisation.
+     *
+     * @hide
+     */
+    @NonNull
+    @SystemApi
+    public BackupRestoreEventLogger getBackupRestoreEventLogger(@NonNull BackupAgent backupAgent) {
+        BackupRestoreEventLogger logger = backupAgent.getBackupRestoreEventLogger();
+        if (logger == null) {
+            throw new IllegalStateException("Attempting to get logger on an uninitialised "
+                    + "BackupAgent");
+        }
+        return backupAgent.getBackupRestoreEventLogger();
+    }
+
     /*
      * We wrap incoming binder calls with a private class implementation that
      * redirects them into main-thread actions.  This serializes the backup
diff --git a/core/java/android/app/backup/BackupRestoreEventLogger.java b/core/java/android/app/backup/BackupRestoreEventLogger.java
index 68740cb..5805826 100644
--- a/core/java/android/app/backup/BackupRestoreEventLogger.java
+++ b/core/java/android/app/backup/BackupRestoreEventLogger.java
@@ -16,13 +16,14 @@
 
 package android.app.backup;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArrayMap;
+import android.app.backup.BackupAnnotations.OperationType;
 import android.util.Slog;
 
 import java.lang.annotation.Retention;
@@ -35,7 +36,6 @@
 import java.util.List;
 import java.util.Map;
 
-// TODO(b/244436184): Make this @SystemApi
 /**
  * Class to log B&R stats for each data type that is backed up and restored by the calling app.
  *
@@ -46,29 +46,17 @@
  *
  * @hide
  */
+@SystemApi
 public class BackupRestoreEventLogger {
     private static final String TAG = "BackupRestoreEventLogger";
 
     /**
      * Max number of unique data types for which an instance of this logger can store info. Attempts
      * to use more distinct data type values will be rejected.
-     */
-    public static final int DATA_TYPES_ALLOWED = 15;
-
-    /**
-     * Operation types for which this logger can be used.
      *
      * @hide
      */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            OperationType.BACKUP,
-            OperationType.RESTORE
-    })
-    @interface OperationType {
-        int BACKUP = 1;
-        int RESTORE = 2;
-    }
+    public static final int DATA_TYPES_ALLOWED = 15;
 
     /**
      * Denotes that the annotated element identifies a data type as required by the logging methods
@@ -316,7 +304,7 @@
     /**
      * Encapsulate logging results for a single data type.
      */
-    public static class DataTypeResult implements Parcelable {
+    public static final class DataTypeResult implements Parcelable {
         @BackupRestoreDataType
         private final String mDataType;
         private int mSuccessCount;
@@ -324,7 +312,7 @@
         private final Map<String, Integer> mErrors = new HashMap<>();
         private byte[] mMetadataHash;
 
-        public DataTypeResult(String dataType) {
+        public DataTypeResult(@NonNull String dataType) {
             mDataType = dataType;
         }
 
@@ -373,7 +361,7 @@
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
             dest.writeString(mDataType);
 
             dest.writeInt(mSuccessCount);
@@ -389,6 +377,7 @@
             dest.writeByteArray(mMetadataHash);
         }
 
+        @NonNull
         public static final Parcelable.Creator<DataTypeResult> CREATOR =
                 new Parcelable.Creator<>() {
                     public DataTypeResult createFromParcel(Parcel in) {
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index bf9a9b0..6371871 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -16,10 +16,9 @@
 
 package android.app.backup;
 
-import static android.app.backup.BackupManager.OperationType;
-
 import android.annotation.Nullable;
 import android.annotation.StringDef;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
@@ -123,20 +122,20 @@
 
     /**
      * Identify {@link BackupScheme} object by package and operation type
-     * (see {@link OperationType}) it corresponds to.
+     * (see {@link BackupDestination}) it corresponds to.
      */
     private static class BackupSchemeId {
         final String mPackageName;
-        @OperationType final int mOperationType;
+        @BackupDestination final int mBackupDestination;
 
-        BackupSchemeId(String packageName, @OperationType int operationType) {
+        BackupSchemeId(String packageName, @BackupDestination int backupDestination) {
             mPackageName = packageName;
-            mOperationType = operationType;
+            mBackupDestination = backupDestination;
         }
 
         @Override
         public int hashCode() {
-            return Objects.hash(mPackageName, mOperationType);
+            return Objects.hash(mPackageName, mBackupDestination);
         }
 
         @Override
@@ -149,7 +148,7 @@
             }
             BackupSchemeId that = (BackupSchemeId) object;
             return Objects.equals(mPackageName, that.mPackageName) &&
-                    Objects.equals(mOperationType, that.mOperationType);
+                    Objects.equals(mBackupDestination, that.mBackupDestination);
         }
     }
 
@@ -164,19 +163,20 @@
             new ArrayMap<>();
 
     static synchronized BackupScheme getBackupScheme(Context context,
-            @OperationType int operationType) {
-        BackupSchemeId backupSchemeId = new BackupSchemeId(context.getPackageName(), operationType);
+            @BackupDestination int backupDestination) {
+        BackupSchemeId backupSchemeId = new BackupSchemeId(context.getPackageName(),
+                backupDestination);
         BackupScheme backupSchemeForPackage =
                 kPackageBackupSchemeMap.get(backupSchemeId);
         if (backupSchemeForPackage == null) {
-            backupSchemeForPackage = new BackupScheme(context, operationType);
+            backupSchemeForPackage = new BackupScheme(context, backupDestination);
             kPackageBackupSchemeMap.put(backupSchemeId, backupSchemeForPackage);
         }
         return backupSchemeForPackage;
     }
 
     public static BackupScheme getBackupSchemeForTest(Context context) {
-        BackupScheme testing = new BackupScheme(context, OperationType.BACKUP);
+        BackupScheme testing = new BackupScheme(context, BackupDestination.CLOUD);
         testing.mExcludes = new ArraySet();
         testing.mIncludes = new ArrayMap();
         return testing;
@@ -303,7 +303,7 @@
 
         final int mDataExtractionRules;
         final int mFullBackupContent;
-        @OperationType final int mOperationType;
+        @BackupDestination final int mBackupDestination;
         final PackageManager mPackageManager;
         final StorageManager mStorageManager;
         final String mPackageName;
@@ -426,12 +426,12 @@
          */
         ArraySet<PathWithRequiredFlags> mExcludes;
 
-        BackupScheme(Context context, @OperationType int operationType) {
+        BackupScheme(Context context, @BackupDestination int backupDestination) {
             ApplicationInfo applicationInfo = context.getApplicationInfo();
 
             mDataExtractionRules = applicationInfo.dataExtractionRulesRes;
             mFullBackupContent = applicationInfo.fullBackupContent;
-            mOperationType = operationType;
+            mBackupDestination = backupDestination;
             mStorageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
             mPackageManager = context.getPackageManager();
             mPackageName = context.getPackageName();
@@ -568,7 +568,7 @@
                 }
 
                 try {
-                    parseSchemeForOperationType(mOperationType);
+                    parseSchemeForBackupDestination(mBackupDestination);
                 } catch (PackageManager.NameNotFoundException e) {
                     // Throw it as an IOException
                     throw new IOException(e);
@@ -576,12 +576,12 @@
             }
         }
 
-        private void parseSchemeForOperationType(@OperationType int operationType)
+        private void parseSchemeForBackupDestination(@BackupDestination int backupDestination)
                 throws PackageManager.NameNotFoundException, IOException, XmlPullParserException {
-            String configSection = getConfigSectionForOperationType(operationType);
+            String configSection = getConfigSectionForBackupDestination(backupDestination);
             if (configSection == null) {
-                Slog.w(TAG, "Given operation type isn't supported by backup scheme: "
-                        + operationType);
+                Slog.w(TAG, "Given backup destination isn't supported by backup scheme: "
+                        + backupDestination);
                 return;
             }
 
@@ -600,7 +600,7 @@
                 }
             }
 
-            if (operationType == OperationType.MIGRATION
+            if (backupDestination == BackupDestination.DEVICE_TRANSFER
                     && CompatChanges.isChangeEnabled(IGNORE_FULL_BACKUP_CONTENT_IN_D2D)) {
                 mIsUsingNewScheme = true;
                 return;
@@ -615,11 +615,12 @@
         }
 
         @Nullable
-        private String getConfigSectionForOperationType(@OperationType int operationType)  {
-            switch (operationType) {
-                case OperationType.BACKUP:
+        private String getConfigSectionForBackupDestination(
+                @BackupDestination int backupDestination)  {
+            switch (backupDestination) {
+                case BackupDestination.CLOUD:
                     return ConfigSection.CLOUD_BACKUP;
-                case OperationType.MIGRATION:
+                case BackupDestination.DEVICE_TRANSFER:
                     return ConfigSection.DEVICE_TRANSFER;
                 default:
                     return null;
diff --git a/core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java b/core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java
index 710b8c4..6b5e667 100644
--- a/core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java
+++ b/core/java/android/app/time/LocationTimeZoneAlgorithmStatus.java
@@ -16,6 +16,8 @@
 
 package android.app.time;
 
+import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
+import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_UNKNOWN;
 import static android.app.time.DetectorStatusTypes.detectionAlgorithmStatusFromString;
@@ -86,12 +88,24 @@
     public static final @ProviderStatus int PROVIDER_STATUS_IS_UNCERTAIN = 4;
 
     /**
-     * An instance that provides no information about algorithm status because the algorithm has not
-     * yet reported. Effectively a "null" status placeholder.
+     * An instance used when the location algorithm is not supported by the device.
      */
-    @NonNull
-    public static final LocationTimeZoneAlgorithmStatus UNKNOWN =
-            new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_UNKNOWN,
+    public static final LocationTimeZoneAlgorithmStatus NOT_SUPPORTED =
+            new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED,
+                    PROVIDER_STATUS_NOT_PRESENT, null, PROVIDER_STATUS_NOT_PRESENT, null);
+
+    /**
+     * An instance used when the location algorithm is running, but has not reported an event.
+     */
+    public static final LocationTimeZoneAlgorithmStatus RUNNING_NOT_REPORTED =
+            new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
+                    PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
+
+    /**
+     * An instance used when the location algorithm is supported but not running.
+     */
+    public static final LocationTimeZoneAlgorithmStatus NOT_RUNNING =
+            new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
                     PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
 
     private final @DetectionAlgorithmStatus int mStatus;
@@ -306,6 +320,40 @@
                 mSecondaryProviderStatus, mSecondaryProviderReportedStatus);
     }
 
+    /**
+     * Returns {@code true} if the algorithm status could allow the time zone detector to enter
+     * telephony fallback mode.
+     */
+    public boolean couldEnableTelephonyFallback() {
+        if (mStatus == DETECTION_ALGORITHM_STATUS_UNKNOWN
+                || mStatus == DETECTION_ALGORITHM_STATUS_NOT_RUNNING
+                || mStatus == DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED) {
+            // This method is not expected to be called on objects with these statuses. Fallback
+            // should not be enabled if it is.
+            return false;
+        }
+
+        // mStatus == DETECTOR_STATUS_RUNNING.
+
+        boolean primarySuggestsFallback = false;
+        if (mPrimaryProviderStatus == PROVIDER_STATUS_NOT_PRESENT) {
+            primarySuggestsFallback = true;
+        } else if (mPrimaryProviderStatus == PROVIDER_STATUS_IS_UNCERTAIN
+                && mPrimaryProviderReportedStatus != null) {
+            primarySuggestsFallback = mPrimaryProviderReportedStatus.couldEnableTelephonyFallback();
+        }
+
+        boolean secondarySuggestsFallback = false;
+        if (mSecondaryProviderStatus == PROVIDER_STATUS_NOT_PRESENT) {
+            secondarySuggestsFallback = true;
+        } else if (mSecondaryProviderStatus == PROVIDER_STATUS_IS_UNCERTAIN
+                && mSecondaryProviderReportedStatus != null) {
+            secondarySuggestsFallback =
+                    mSecondaryProviderReportedStatus.couldEnableTelephonyFallback();
+        }
+        return primarySuggestsFallback && secondarySuggestsFallback;
+    }
+
     /** @hide */
     @VisibleForTesting
     @NonNull
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index 295d69d..5c47ea2 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -19,13 +19,20 @@
 import android.app.PendingIntent;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
+import android.companion.virtual.sensor.VirtualSensorConfig;
+import android.companion.virtual.sensor.VirtualSensorEvent;
 import android.graphics.Point;
 import android.graphics.PointF;
+import android.hardware.input.VirtualDpadConfig;
+import android.hardware.input.VirtualKeyboardConfig;
 import android.hardware.input.VirtualKeyEvent;
 import android.hardware.input.VirtualMouseButtonEvent;
+import android.hardware.input.VirtualMouseConfig;
 import android.hardware.input.VirtualMouseRelativeEvent;
 import android.hardware.input.VirtualMouseScrollEvent;
 import android.hardware.input.VirtualTouchEvent;
+import android.hardware.input.VirtualTouchscreenConfig;
 import android.os.ResultReceiver;
 
 /**
@@ -61,32 +68,22 @@
             IAudioConfigChangedCallback configChangedCallback);
 
     void onAudioSessionEnded();
-
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
     void createVirtualDpad(
-            int displayId,
-            String inputDeviceName,
-            int vendorId,
-            int productId,
+            in VirtualDpadConfig config,
             IBinder token);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
     void createVirtualKeyboard(
-            int displayId,
-            String inputDeviceName,
-            int vendorId,
-            int productId,
+            in VirtualKeyboardConfig config,
             IBinder token);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
     void createVirtualMouse(
-            int displayId,
-            String inputDeviceName,
-            int vendorId,
-            int productId,
+            in VirtualMouseConfig config,
             IBinder token);
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
     void createVirtualTouchscreen(
-            int displayId,
-            String inputDeviceName,
-            int vendorId,
-            int productId,
-            IBinder token,
-            in Point screenSize);
+            in VirtualTouchscreenConfig config,
+            IBinder token);
     void unregisterInputDevice(IBinder token);
     int getInputDeviceId(IBinder token);
     boolean sendDpadKeyEvent(IBinder token, in VirtualKeyEvent event);
@@ -97,6 +94,24 @@
     boolean sendTouchEvent(IBinder token, in VirtualTouchEvent event);
 
     /**
+     * Creates a virtual sensor, capable of injecting sensor events into the system.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
+    void createVirtualSensor(IBinder tokenm, in VirtualSensorConfig config);
+
+    /**
+     * Removes the sensor corresponding to the given token from the system.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
+    void unregisterSensor(IBinder token);
+
+    /**
+     * Sends an event to the virtual sensor corresponding to the given token.
+     */
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
+    boolean sendSensorEvent(IBinder token, in VirtualSensorEvent event);
+
+    /**
      * Launches a pending intent on the given display that is owned by this virtual device.
      */
     void launchPendingIntent(
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index c14bb1b..0e6cfb1 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -22,12 +22,15 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.app.PendingIntent;
 import android.companion.AssociationInfo;
 import android.companion.virtual.audio.VirtualAudioDevice;
 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback;
+import android.companion.virtual.sensor.VirtualSensor;
+import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.content.ComponentName;
 import android.content.Context;
 import android.graphics.Point;
@@ -38,9 +41,13 @@
 import android.hardware.display.VirtualDisplay;
 import android.hardware.display.VirtualDisplayConfig;
 import android.hardware.input.VirtualDpad;
+import android.hardware.input.VirtualDpadConfig;
 import android.hardware.input.VirtualKeyboard;
+import android.hardware.input.VirtualKeyboardConfig;
 import android.hardware.input.VirtualMouse;
+import android.hardware.input.VirtualMouseConfig;
 import android.hardware.input.VirtualTouchscreen;
+import android.hardware.input.VirtualTouchscreenConfig;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
@@ -58,6 +65,7 @@
 import java.lang.annotation.Target;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Objects;
 import java.util.concurrent.Executor;
 import java.util.function.IntConsumer;
 
@@ -67,7 +75,6 @@
 @SystemService(Context.VIRTUAL_DEVICE_SERVICE)
 public final class VirtualDeviceManager {
 
-    private static final boolean DEBUG = false;
     private static final String TAG = "VirtualDeviceManager";
 
     private static final int DEFAULT_VIRTUAL_DISPLAY_FLAGS =
@@ -76,7 +83,7 @@
                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL
                     | DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
-                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
+                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
 
     /**
      * The default device ID, which is the ID of the primary (non-virtual) device.
@@ -88,6 +95,26 @@
      */
     public static final int INVALID_DEVICE_ID = -1;
 
+    /**
+     * Broadcast Action: A Virtual Device was removed.
+     *
+     * <p class="note">This is a protected intent that can only be sent by the system.</p>
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_VIRTUAL_DEVICE_REMOVED =
+            "android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED";
+
+    /**
+     * Int intent extra to be used with {@link #ACTION_VIRTUAL_DEVICE_REMOVED}.
+     * Contains the identifier of the virtual device, which was removed.
+     *
+     * @hide
+     */
+    public static final String EXTRA_VIRTUAL_DEVICE_ID =
+            "android.companion.virtual.extra.VIRTUAL_DEVICE_ID";
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(
@@ -250,7 +277,10 @@
                 };
         @Nullable
         private VirtualAudioDevice mVirtualAudioDevice;
+        @NonNull
+        private List<VirtualSensor> mVirtualSensors = new ArrayList<>();
 
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         private VirtualDevice(
                 IVirtualDeviceManager service,
                 Context context,
@@ -264,6 +294,10 @@
                     associationId,
                     params,
                     mActivityListenerBinder);
+            final List<VirtualSensorConfig> virtualSensorConfigs = params.getVirtualSensorConfigs();
+            for (int i = 0; i < virtualSensorConfigs.size(); ++i) {
+                mVirtualSensors.add(createVirtualSensor(virtualSensorConfigs.get(i)));
+            }
         }
 
         /**
@@ -278,6 +312,35 @@
         }
 
         /**
+         * @return A new Context bound to this device. This is a convenience method equivalent to
+         * calling {@link Context#createDeviceContext(int)} with the device id of this device.
+         */
+        public @NonNull Context createContext() {
+            try {
+                return mContext.createDeviceContext(mVirtualDevice.getDeviceId());
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
+         * Returns this device's sensor with the given type and name, if any.
+         *
+         * @see VirtualDeviceParams.Builder#addVirtualSensorConfig
+         *
+         * @param type The type of the sensor.
+         * @param name The name of the sensor.
+         * @return The matching sensor if found, {@code null} otherwise.
+         */
+        @Nullable
+        public VirtualSensor getVirtualSensor(int type, @NonNull String name) {
+            return mVirtualSensors.stream()
+                    .filter(sensor -> sensor.getType() == type && sensor.getName().equals(name))
+                    .findAny()
+                    .orElse(null);
+        }
+
+        /**
          * Launches a given pending intent on the give display ID.
          *
          * @param displayId The display to launch the pending intent on. This display must be
@@ -350,14 +413,72 @@
                 @VirtualDisplayFlag int flags,
                 @Nullable @CallbackExecutor Executor executor,
                 @Nullable VirtualDisplay.Callback callback) {
-            // TODO(b/205343547): Handle display groups properly instead of creating a new display
-            //  group for every new virtual display created using this API.
-            // belongs to the same display group.
             VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
                     getVirtualDisplayName(), width, height, densityDpi)
                     .setSurface(surface)
                     .setFlags(getVirtualDisplayFlags(flags))
                     .build();
+            return createVirtualDisplayInternal(config, executor, callback);
+        }
+
+        /**
+         * Creates a virtual display for this virtual device. All displays created on the same
+         * device belongs to the same display group.
+         *
+         * @param width The width of the virtual display in pixels, must be greater than 0.
+         * @param height The height of the virtual display in pixels, must be greater than 0.
+         * @param densityDpi The density of the virtual display in dpi, must be greater than 0.
+         * @param displayCategories The categories of the virtual display, indicating the type of
+         * activities allowed to run on the display. Activities can declare their type using
+         * {@link android.content.pm.ActivityInfo#requiredDisplayCategory}.
+         * @param surface The surface to which the content of the virtual display should
+         * be rendered, or null if there is none initially. The surface can also be set later using
+         * {@link VirtualDisplay#setSurface(Surface)}.
+         * @param flags A combination of virtual display flags accepted by
+         * {@link DisplayManager#createVirtualDisplay}. In addition, the following flags are
+         * automatically set for all virtual devices:
+         * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_PUBLIC VIRTUAL_DISPLAY_FLAG_PUBLIC} and
+         * {@link DisplayManager#VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY
+         * VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY}.
+         * @param executor The executor on which {@code callback} will be invoked. This is ignored
+         * if {@code callback} is {@code null}. If {@code callback} is specified, this executor must
+         * not be null.
+         * @param callback Callback to call when the state of the {@link VirtualDisplay} changes
+         * @return The newly created virtual display, or {@code null} if the application could
+         * not create the virtual display.
+         *
+         * @see DisplayManager#createVirtualDisplay
+         */
+        @Nullable
+        public VirtualDisplay createVirtualDisplay(
+                @IntRange(from = 1) int width,
+                @IntRange(from = 1) int height,
+                @IntRange(from = 1) int densityDpi,
+                @NonNull List<String> displayCategories,
+                @Nullable Surface surface,
+                @VirtualDisplayFlag int flags,
+                @Nullable @CallbackExecutor Executor executor,
+                @Nullable VirtualDisplay.Callback callback) {
+            VirtualDisplayConfig config = new VirtualDisplayConfig.Builder(
+                    getVirtualDisplayName(), width, height, densityDpi)
+                    .setDisplayCategories(displayCategories)
+                    .setSurface(surface)
+                    .setFlags(getVirtualDisplayFlags(flags))
+                    .build();
+            return createVirtualDisplayInternal(config, executor, callback);
+        }
+
+        /**
+         * @hide
+         */
+        @Nullable
+        private VirtualDisplay createVirtualDisplayInternal(
+                @NonNull VirtualDisplayConfig config,
+                @Nullable @CallbackExecutor Executor executor,
+                @Nullable VirtualDisplay.Callback callback) {
+            // TODO(b/205343547): Handle display groups properly instead of creating a new display
+            //  group for every new virtual display created using this API.
+            // belongs to the same display group.
             IVirtualDisplayCallback callbackWrapper =
                     new DisplayManagerGlobal.VirtualDisplayCallback(callback, executor);
             final int displayId;
@@ -379,6 +500,7 @@
         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         public void close() {
             try {
+                // This also takes care of unregistering all virtual sensors.
                 mVirtualDevice.close();
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -392,23 +514,15 @@
         /**
          * Creates a virtual dpad.
          *
-         * @param display the display that the events inputted through this device should target
-         * @param inputDeviceName the name to call this input device
-         * @param vendorId the PCI vendor id
-         * @param productId the product id, as defined by the vendor
+         * @param config the configurations of the virtual Dpad.
          */
         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
-        public VirtualDpad createVirtualDpad(
-                @NonNull VirtualDisplay display,
-                @NonNull String inputDeviceName,
-                int vendorId,
-                int productId) {
+        public VirtualDpad createVirtualDpad(@NonNull VirtualDpadConfig config) {
             try {
                 final IBinder token = new Binder(
-                        "android.hardware.input.VirtualDpad:" + inputDeviceName);
-                mVirtualDevice.createVirtualDpad(display.getDisplay().getDisplayId(),
-                        inputDeviceName, vendorId, productId, token);
+                        "android.hardware.input.VirtualDpad:" + config.getInputDeviceName());
+                mVirtualDevice.createVirtualDpad(config, token);
                 return new VirtualDpad(mVirtualDevice, token);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -418,23 +532,15 @@
         /**
          * Creates a virtual keyboard.
          *
-         * @param display the display that the events inputted through this device should target
-         * @param inputDeviceName the name to call this input device
-         * @param vendorId the PCI vendor id
-         * @param productId the product id, as defined by the vendor
+         * @param config the configurations of the virtual keyboard.
          */
         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
-        public VirtualKeyboard createVirtualKeyboard(
-                @NonNull VirtualDisplay display,
-                @NonNull String inputDeviceName,
-                int vendorId,
-                int productId) {
+        public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualKeyboardConfig config) {
             try {
                 final IBinder token = new Binder(
-                        "android.hardware.input.VirtualKeyboard:" + inputDeviceName);
-                mVirtualDevice.createVirtualKeyboard(display.getDisplay().getDisplayId(),
-                        inputDeviceName, vendorId, productId, token);
+                        "android.hardware.input.VirtualKeyboard:" + config.getInputDeviceName());
+                mVirtualDevice.createVirtualKeyboard(config, token);
                 return new VirtualKeyboard(mVirtualDevice, token);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
@@ -442,26 +548,90 @@
         }
 
         /**
+         * Creates a virtual keyboard.
+         *
+         * @param display         the display that the events inputted through this device should
+         *                        target
+         * @param inputDeviceName the name to call this input device
+         * @param vendorId        the PCI vendor id
+         * @param productId       the product id, as defined by the vendor
+         * @see #createVirtualKeyboard(VirtualKeyboardConfig config)
+         * @deprecated Use {@link #createVirtualKeyboard(VirtualKeyboardConfig config)} instead
+         */
+        @Deprecated
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @NonNull
+        public VirtualKeyboard createVirtualKeyboard(@NonNull VirtualDisplay display,
+                @NonNull String inputDeviceName, int vendorId, int productId) {
+            VirtualKeyboardConfig keyboardConfig =
+                    new VirtualKeyboardConfig.Builder()
+                            .setVendorId(vendorId)
+                            .setProductId(productId)
+                            .setInputDeviceName(inputDeviceName)
+                            .setAssociatedDisplayId(display.getDisplay().getDisplayId())
+                            .build();
+            return createVirtualKeyboard(keyboardConfig);
+        }
+
+        /**
+         * Creates a virtual mouse.
+         *
+         * @param config the configurations of the virtual mouse.
+         */
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @NonNull
+        public VirtualMouse createVirtualMouse(@NonNull VirtualMouseConfig config) {
+            try {
+                final IBinder token = new Binder(
+                        "android.hardware.input.VirtualMouse:" + config.getInputDeviceName());
+                mVirtualDevice.createVirtualMouse(config, token);
+                return new VirtualMouse(mVirtualDevice, token);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Creates a virtual mouse.
          *
-         * @param display the display that the events inputted through this device should target
+         * @param display         the display that the events inputted through this device should
+         *                        target
          * @param inputDeviceName the name to call this input device
-         * @param vendorId the PCI vendor id
-         * @param productId the product id, as defined by the vendor
+         * @param vendorId        the PCI vendor id
+         * @param productId       the product id, as defined by the vendor
+         * @see #createVirtualMouse(VirtualMouseConfig config)
+         * @deprecated Use {@link #createVirtualMouse(VirtualMouseConfig config)} instead
+         * *
+         */
+        @Deprecated
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @NonNull
+        public VirtualMouse createVirtualMouse(@NonNull VirtualDisplay display,
+                @NonNull String inputDeviceName, int vendorId, int productId) {
+            VirtualMouseConfig mouseConfig =
+                    new VirtualMouseConfig.Builder()
+                            .setVendorId(vendorId)
+                            .setProductId(productId)
+                            .setInputDeviceName(inputDeviceName)
+                            .setAssociatedDisplayId(display.getDisplay().getDisplayId())
+                            .build();
+            return createVirtualMouse(mouseConfig);
+        }
+
+        /**
+         * Creates a virtual touchscreen.
+         *
+         * @param config the configurations of the virtual touchscreen.
          */
         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
-        public VirtualMouse createVirtualMouse(
-                @NonNull VirtualDisplay display,
-                @NonNull String inputDeviceName,
-                int vendorId,
-                int productId) {
+        public VirtualTouchscreen createVirtualTouchscreen(
+                @NonNull VirtualTouchscreenConfig config) {
             try {
                 final IBinder token = new Binder(
-                        "android.hardware.input.VirtualMouse:" + inputDeviceName);
-                mVirtualDevice.createVirtualMouse(display.getDisplay().getDisplayId(),
-                        inputDeviceName, vendorId, productId, token);
-                return new VirtualMouse(mVirtualDevice, token);
+                        "android.hardware.input.VirtualTouchscreen:" + config.getInputDeviceName());
+                mVirtualDevice.createVirtualTouchscreen(config, token);
+                return new VirtualTouchscreen(mVirtualDevice, token);
             } catch (RemoteException e) {
                 throw e.rethrowFromSystemServer();
             }
@@ -470,29 +640,32 @@
         /**
          * Creates a virtual touchscreen.
          *
-         * @param display the display that the events inputted through this device should target
+         * @param display         the display that the events inputted through this device should
+         *                        target
          * @param inputDeviceName the name to call this input device
-         * @param vendorId the PCI vendor id
-         * @param productId the product id, as defined by the vendor
+         * @param vendorId        the PCI vendor id
+         * @param productId       the product id, as defined by the vendor
+         * @see #createVirtualTouchscreen(VirtualTouchscreenConfig config)
+         * @deprecated Use {@link #createVirtualTouchscreen(VirtualTouchscreenConfig config)}
+         * instead
          */
+        @Deprecated
         @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
         @NonNull
-        public VirtualTouchscreen createVirtualTouchscreen(
-                @NonNull VirtualDisplay display,
-                @NonNull String inputDeviceName,
-                int vendorId,
-                int productId) {
-            try {
-                final IBinder token = new Binder(
-                        "android.hardware.input.VirtualTouchscreen:" + inputDeviceName);
-                final Point size = new Point();
-                display.getDisplay().getSize(size);
-                mVirtualDevice.createVirtualTouchscreen(display.getDisplay().getDisplayId(),
-                        inputDeviceName, vendorId, productId, token, size);
-                return new VirtualTouchscreen(mVirtualDevice, token);
-            } catch (RemoteException e) {
-                throw e.rethrowFromSystemServer();
-            }
+        public VirtualTouchscreen createVirtualTouchscreen(@NonNull VirtualDisplay display,
+                @NonNull String inputDeviceName, int vendorId, int productId) {
+            final Point size = new Point();
+            display.getDisplay().getSize(size);
+            VirtualTouchscreenConfig touchscreenConfig =
+                    new VirtualTouchscreenConfig.Builder()
+                            .setVendorId(vendorId)
+                            .setProductId(productId)
+                            .setInputDeviceName(inputDeviceName)
+                            .setAssociatedDisplayId(display.getDisplay().getDisplayId())
+                            .setWidthInPixels(size.x)
+                            .setHeightInPixels(size.y)
+                            .build();
+            return createVirtualTouchscreen(touchscreenConfig);
         }
 
         /**
@@ -564,6 +737,28 @@
         }
 
         /**
+         * Creates a virtual sensor, capable of injecting sensor events into the system. Only for
+         * internal use, since device sensors must remain valid for the entire lifetime of the
+         * device.
+         *
+         * @param config The configuration of the sensor.
+         * @hide
+         */
+        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+        @NonNull
+        public VirtualSensor createVirtualSensor(@NonNull VirtualSensorConfig config) {
+            Objects.requireNonNull(config);
+            try {
+                final IBinder token = new Binder(
+                        "android.hardware.sensor.VirtualSensor:" + config.getName());
+                mVirtualDevice.createVirtualSensor(token, config);
+                return new VirtualSensor(config.getType(), config.getName(), mVirtualDevice, token);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
+
+        /**
          * Adds an activity listener to listen for events such as top activity change or virtual
          * display task stack became empty.
          *
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index f8c2e34a..1cbe910 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -23,20 +23,22 @@
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
+import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.content.ComponentName;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.util.ArraySet;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 
-import com.android.internal.util.Preconditions;
-
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
 import java.util.Set;
 
@@ -158,6 +160,7 @@
     @Nullable private final String mName;
     // Mapping of @PolicyType to @DevicePolicy
     @NonNull private final SparseIntArray mDevicePolicies;
+    @NonNull private final List<VirtualSensorConfig> mVirtualSensorConfigs;
 
     private VirtualDeviceParams(
             @LockState int lockState,
@@ -169,24 +172,22 @@
             @NonNull Set<ComponentName> blockedActivities,
             @ActivityPolicy int defaultActivityPolicy,
             @Nullable String name,
-            @NonNull SparseIntArray devicePolicies) {
-        Preconditions.checkNotNull(usersWithMatchingAccounts);
-        Preconditions.checkNotNull(allowedCrossTaskNavigations);
-        Preconditions.checkNotNull(blockedCrossTaskNavigations);
-        Preconditions.checkNotNull(allowedActivities);
-        Preconditions.checkNotNull(blockedActivities);
-        Preconditions.checkNotNull(devicePolicies);
-
+            @NonNull SparseIntArray devicePolicies,
+            @NonNull List<VirtualSensorConfig> virtualSensorConfigs) {
         mLockState = lockState;
-        mUsersWithMatchingAccounts = new ArraySet<>(usersWithMatchingAccounts);
-        mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
-        mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
+        mUsersWithMatchingAccounts =
+                new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
+        mAllowedCrossTaskNavigations =
+                new ArraySet<>(Objects.requireNonNull(allowedCrossTaskNavigations));
+        mBlockedCrossTaskNavigations =
+                new ArraySet<>(Objects.requireNonNull(blockedCrossTaskNavigations));
         mDefaultNavigationPolicy = defaultNavigationPolicy;
-        mAllowedActivities = new ArraySet<>(allowedActivities);
-        mBlockedActivities = new ArraySet<>(blockedActivities);
+        mAllowedActivities = new ArraySet<>(Objects.requireNonNull(allowedActivities));
+        mBlockedActivities = new ArraySet<>(Objects.requireNonNull(blockedActivities));
         mDefaultActivityPolicy = defaultActivityPolicy;
         mName = name;
-        mDevicePolicies = devicePolicies;
+        mDevicePolicies = Objects.requireNonNull(devicePolicies);
+        mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
     }
 
     @SuppressWarnings("unchecked")
@@ -201,6 +202,8 @@
         mDefaultActivityPolicy = parcel.readInt();
         mName = parcel.readString8();
         mDevicePolicies = parcel.readSparseIntArray();
+        mVirtualSensorConfigs = new ArrayList<>();
+        parcel.readTypedList(mVirtualSensorConfigs, VirtualSensorConfig.CREATOR);
     }
 
     /**
@@ -310,12 +313,21 @@
      * Returns the policy specified for this policy type, or {@link #DEVICE_POLICY_DEFAULT} if no
      * policy for this type has been explicitly specified.
      *
-     * @see Builder#addDevicePolicy
+     * @see Builder#setDevicePolicy
      */
     public @DevicePolicy int getDevicePolicy(@PolicyType int policyType) {
         return mDevicePolicies.get(policyType, DEVICE_POLICY_DEFAULT);
     }
 
+    /**
+     * Returns the configurations for all sensors that should be created for this device.
+     *
+     * @see Builder#addVirtualSensorConfig
+     */
+    public @NonNull List<VirtualSensorConfig> getVirtualSensorConfigs() {
+        return mVirtualSensorConfigs;
+    }
+
     @Override
     public int describeContents() {
         return 0;
@@ -333,6 +345,7 @@
         dest.writeInt(mDefaultActivityPolicy);
         dest.writeString8(mName);
         dest.writeSparseIntArray(mDevicePolicies);
+        dest.writeTypedList(mVirtualSensorConfigs);
     }
 
     @Override
@@ -428,6 +441,7 @@
         private boolean mDefaultActivityPolicyConfigured = false;
         @Nullable private String mName;
         @NonNull private SparseIntArray mDevicePolicies = new SparseIntArray();
+        @NonNull private List<VirtualSensorConfig> mVirtualSensorConfigs = new ArrayList<>();
 
         /**
          * Sets the lock state of the device. The permission {@code ADD_ALWAYS_UNLOCKED_DISPLAY}
@@ -467,8 +481,7 @@
         @NonNull
         public Builder setUsersWithMatchingAccounts(
                 @NonNull Set<UserHandle> usersWithMatchingAccounts) {
-            Preconditions.checkNotNull(usersWithMatchingAccounts);
-            mUsersWithMatchingAccounts = usersWithMatchingAccounts;
+            mUsersWithMatchingAccounts = Objects.requireNonNull(usersWithMatchingAccounts);
             return this;
         }
 
@@ -491,7 +504,6 @@
         @NonNull
         public Builder setAllowedCrossTaskNavigations(
                 @NonNull Set<ComponentName> allowedCrossTaskNavigations) {
-            Preconditions.checkNotNull(allowedCrossTaskNavigations);
             if (mDefaultNavigationPolicyConfigured
                     && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
                 throw new IllegalArgumentException(
@@ -500,7 +512,7 @@
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
             mDefaultNavigationPolicyConfigured = true;
-            mAllowedCrossTaskNavigations = allowedCrossTaskNavigations;
+            mAllowedCrossTaskNavigations = Objects.requireNonNull(allowedCrossTaskNavigations);
             return this;
         }
 
@@ -523,7 +535,6 @@
         @NonNull
         public Builder setBlockedCrossTaskNavigations(
                 @NonNull Set<ComponentName> blockedCrossTaskNavigations) {
-            Preconditions.checkNotNull(blockedCrossTaskNavigations);
             if (mDefaultNavigationPolicyConfigured
                      && mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_ALLOWED) {
                 throw new IllegalArgumentException(
@@ -532,7 +543,7 @@
             }
             mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
             mDefaultNavigationPolicyConfigured = true;
-            mBlockedCrossTaskNavigations = blockedCrossTaskNavigations;
+            mBlockedCrossTaskNavigations = Objects.requireNonNull(blockedCrossTaskNavigations);
             return this;
         }
 
@@ -551,7 +562,6 @@
          */
         @NonNull
         public Builder setAllowedActivities(@NonNull Set<ComponentName> allowedActivities) {
-            Preconditions.checkNotNull(allowedActivities);
             if (mDefaultActivityPolicyConfigured
                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_BLOCKED) {
                 throw new IllegalArgumentException(
@@ -559,7 +569,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
             mDefaultActivityPolicyConfigured = true;
-            mAllowedActivities = allowedActivities;
+            mAllowedActivities = Objects.requireNonNull(allowedActivities);
             return this;
         }
 
@@ -578,7 +588,6 @@
          */
         @NonNull
         public Builder setBlockedActivities(@NonNull Set<ComponentName> blockedActivities) {
-            Preconditions.checkNotNull(blockedActivities);
             if (mDefaultActivityPolicyConfigured
                     && mDefaultActivityPolicy != ACTIVITY_POLICY_DEFAULT_ALLOWED) {
                 throw new IllegalArgumentException(
@@ -586,7 +595,7 @@
             }
             mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
             mDefaultActivityPolicyConfigured = true;
-            mBlockedActivities = blockedActivities;
+            mBlockedActivities = Objects.requireNonNull(blockedActivities);
             return this;
         }
 
@@ -606,25 +615,64 @@
         }
 
         /**
-         * Add a policy for this virtual device.
+         * Specifies a policy for this virtual device.
          *
-         * Policies define the system behavior that may be specific for this virtual device. A
+         * <p>Policies define the system behavior that may be specific for this virtual device. A
          * policy can be defined for each {@code PolicyType}, but they are all optional.
          *
          * @param policyType the type of policy, i.e. which behavior to specify a policy for.
          * @param devicePolicy the value of the policy, i.e. how to interpret the device behavior.
          */
         @NonNull
-        public Builder addDevicePolicy(@PolicyType int policyType, @DevicePolicy int devicePolicy) {
+        public Builder setDevicePolicy(@PolicyType int policyType, @DevicePolicy int devicePolicy) {
             mDevicePolicies.put(policyType, devicePolicy);
             return this;
         }
 
         /**
+         * Adds a configuration for a sensor that should be created for this virtual device.
+         *
+         * <p>Device sensors must remain valid for the entire lifetime of the device, hence they are
+         * created together with the device itself, and removed when the device is removed.
+         *
+         * <p>Requires {@link #DEVICE_POLICY_CUSTOM} to be set for {@link #POLICY_TYPE_SENSORS}.
+         *
+         * @see android.companion.virtual.sensor.VirtualSensor
+         * @see #setDevicePolicy
+         */
+        @NonNull
+        public Builder addVirtualSensorConfig(@NonNull VirtualSensorConfig virtualSensorConfig) {
+            mVirtualSensorConfigs.add(Objects.requireNonNull(virtualSensorConfig));
+            return this;
+        }
+
+        /**
          * Builds the {@link VirtualDeviceParams} instance.
+         *
+         * @throws IllegalArgumentException if there's mismatch between policy definition and
+         * the passed parameters or if there are sensor configs with the same type and name.
+         *
          */
         @NonNull
         public VirtualDeviceParams build() {
+            if (!mVirtualSensorConfigs.isEmpty()
+                    && (mDevicePolicies.get(POLICY_TYPE_SENSORS, DEVICE_POLICY_DEFAULT)
+                            != DEVICE_POLICY_CUSTOM)) {
+                throw new IllegalArgumentException(
+                        "DEVICE_POLICY_CUSTOM for POLICY_TYPE_SENSORS is required for creating "
+                                + "virtual sensors.");
+            }
+            SparseArray<Set<String>> sensorNameByType = new SparseArray();
+            for (int i = 0; i < mVirtualSensorConfigs.size(); ++i) {
+                VirtualSensorConfig config = mVirtualSensorConfigs.get(i);
+                Set<String> sensorNames = sensorNameByType.get(config.getType(), new ArraySet<>());
+                if (!sensorNames.add(config.getName())) {
+                    throw new IllegalArgumentException(
+                            "Sensor names must be unique for a particular sensor type.");
+                }
+                sensorNameByType.put(config.getType(), sensorNames);
+            }
+
             return new VirtualDeviceParams(
                     mLockState,
                     mUsersWithMatchingAccounts,
@@ -635,7 +683,8 @@
                     mBlockedActivities,
                     mDefaultActivityPolicy,
                     mName,
-                    mDevicePolicies);
+                    mDevicePolicies,
+                    mVirtualSensorConfigs);
         }
     }
 }
diff --git a/core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl b/core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl
new file mode 100644
index 0000000..b99cc7e
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/IVirtualSensorStateChangeCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+/**
+ * Interface for notification of listener registration changes for a virtual sensor.
+ *
+ * @hide
+ */
+oneway interface IVirtualSensorStateChangeCallback {
+
+    /**
+     * Called when the registered listeners to a virtual sensor have changed.
+     *
+     * @param enabled Whether the sensor is enabled.
+     * @param samplingPeriodMicros The requested sensor's sampling period in microseconds.
+     * @param batchReportingLatencyMicros The requested maximum time interval in microseconds
+     * between the delivery of two batches of sensor events.
+     */
+    void onStateChanged(boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros);
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensor.java b/core/java/android/companion/virtual/sensor/VirtualSensor.java
new file mode 100644
index 0000000..a184481
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensor.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.companion.virtual.IVirtualDevice;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+import java.time.Duration;
+
+/**
+ * Representation of a sensor on a remote device, capable of sending events, such as an
+ * accelerometer or a gyroscope.
+ *
+ * This registers the sensor device with the sensor framework as a runtime sensor.
+ *
+ * @hide
+ */
+@SystemApi
+public class VirtualSensor {
+
+    /**
+     * Interface for notification of listener registration changes for a virtual sensor.
+     */
+    public interface SensorStateChangeCallback {
+        /**
+         * Called when the registered listeners to a virtual sensor have changed.
+         *
+         * @param enabled Whether the sensor is enabled.
+         * @param samplingPeriod The requested sampling period of the sensor.
+         * @param batchReportLatency The requested maximum time interval between the delivery of two
+         * batches of sensor events.
+         */
+        void onStateChanged(boolean enabled, @NonNull Duration samplingPeriod,
+                @NonNull Duration batchReportLatency);
+    }
+
+    private final int mType;
+    private final String mName;
+    private final IVirtualDevice mVirtualDevice;
+    private final IBinder mToken;
+
+    /**
+     * @hide
+     */
+    public VirtualSensor(int type, String name, IVirtualDevice virtualDevice, IBinder token) {
+        mType = type;
+        mName = name;
+        mVirtualDevice = virtualDevice;
+        mToken = token;
+    }
+
+    /**
+     * Returns the
+     * <a href="https://source.android.com/devices/sensors/sensor-types">type</a> of the sensor.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the name of the sensor.
+     */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Send a sensor event to the system.
+     */
+    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
+    public void sendSensorEvent(@NonNull VirtualSensorEvent event) {
+        try {
+            mVirtualDevice.sendSensorEvent(mToken, event);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.aidl b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.aidl
new file mode 100644
index 0000000..48b463a
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+parcelable VirtualSensorConfig;
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
new file mode 100644
index 0000000..7982fa5
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorConfig.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+import static java.util.concurrent.TimeUnit.MICROSECONDS;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SuppressLint;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.time.Duration;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Configuration for creation of a virtual sensor.
+ * @see VirtualSensor
+ * @hide
+ */
+@SystemApi
+public final class VirtualSensorConfig implements Parcelable {
+
+    private final int mType;
+    @NonNull
+    private final String mName;
+    @Nullable
+    private final String mVendor;
+    @Nullable
+    private final IVirtualSensorStateChangeCallback mStateChangeCallback;
+
+    private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
+            @Nullable IVirtualSensorStateChangeCallback stateChangeCallback) {
+        mType = type;
+        mName = name;
+        mVendor = vendor;
+        mStateChangeCallback = stateChangeCallback;
+    }
+
+    private VirtualSensorConfig(@NonNull Parcel parcel) {
+        mType = parcel.readInt();
+        mName = parcel.readString8();
+        mVendor = parcel.readString8();
+        mStateChangeCallback =
+                IVirtualSensorStateChangeCallback.Stub.asInterface(parcel.readStrongBinder());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int flags) {
+        parcel.writeInt(mType);
+        parcel.writeString8(mName);
+        parcel.writeString8(mVendor);
+        parcel.writeStrongBinder(
+                mStateChangeCallback != null ? mStateChangeCallback.asBinder() : null);
+    }
+
+    /**
+     * Returns the
+     * <a href="https://source.android.com/devices/sensors/sensor-types">type</a> of the sensor.
+     */
+    public int getType() {
+        return mType;
+    }
+
+    /**
+     * Returns the name of the sensor, which must be unique per sensor type for each virtual device.
+     */
+    @NonNull
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Returns the vendor string of the sensor.
+     * @see Builder#setVendor
+     */
+    @Nullable
+    public String getVendor() {
+        return mVendor;
+    }
+
+    /**
+     * Returns the callback to get notified about changes in the sensor listeners.
+     * @hide
+     */
+    @Nullable
+    public IVirtualSensorStateChangeCallback getStateChangeCallback() {
+        return mStateChangeCallback;
+    }
+
+    /**
+     * Builder for {@link VirtualSensorConfig}.
+     */
+    public static final class Builder {
+
+        private final int mType;
+        @NonNull
+        private final String mName;
+        @Nullable
+        private String mVendor;
+        @Nullable
+        private IVirtualSensorStateChangeCallback mStateChangeCallback;
+
+        private static class SensorStateChangeCallbackDelegate
+                extends IVirtualSensorStateChangeCallback.Stub {
+            @NonNull
+            private final Executor mExecutor;
+            @NonNull
+            private final VirtualSensor.SensorStateChangeCallback mCallback;
+
+            SensorStateChangeCallbackDelegate(@NonNull @CallbackExecutor Executor executor,
+                    @NonNull VirtualSensor.SensorStateChangeCallback callback) {
+                mCallback = callback;
+                mExecutor = executor;
+            }
+            @Override
+            public void onStateChanged(boolean enabled, int samplingPeriodMicros,
+                    int batchReportLatencyMicros) {
+                final Duration samplingPeriod =
+                        Duration.ofNanos(MICROSECONDS.toNanos(samplingPeriodMicros));
+                final Duration batchReportingLatency =
+                        Duration.ofNanos(MICROSECONDS.toNanos(batchReportLatencyMicros));
+                mExecutor.execute(() -> mCallback.onStateChanged(
+                        enabled, samplingPeriod, batchReportingLatency));
+            }
+        }
+
+        /**
+         * Creates a new builder.
+         *
+         * @param type The
+         * <a href="https://source.android.com/devices/sensors/sensor-types">type</a> of the sensor.
+         * @param name The name of the sensor. Must be unique among all sensors with the same type
+         * that belong to the same virtual device.
+         */
+        public Builder(int type, @NonNull String name) {
+            mType = type;
+            mName = Objects.requireNonNull(name);
+        }
+
+        /**
+         * Creates a new {@link VirtualSensorConfig}.
+         */
+        @NonNull
+        public VirtualSensorConfig build() {
+            return new VirtualSensorConfig(mType, mName, mVendor, mStateChangeCallback);
+        }
+
+        /**
+         * Sets the vendor string of the sensor.
+         */
+        @NonNull
+        public VirtualSensorConfig.Builder setVendor(@Nullable String vendor) {
+            mVendor = vendor;
+            return this;
+        }
+
+        /**
+         * Sets the callback to get notified about changes in the sensor listeners.
+         *
+         * @param executor The executor where the callback is executed on.
+         * @param callback The callback to get notified when the state of the sensor
+         * listeners has changed, see {@link VirtualSensor.SensorStateChangeCallback}
+         */
+        @SuppressLint("MissingGetterMatchingBuilder")
+        @NonNull
+        public VirtualSensorConfig.Builder setStateChangeCallback(
+                @NonNull @CallbackExecutor Executor executor,
+                @NonNull VirtualSensor.SensorStateChangeCallback callback) {
+            mStateChangeCallback = new SensorStateChangeCallbackDelegate(
+                    Objects.requireNonNull(executor),
+                    Objects.requireNonNull(callback));
+            return this;
+        }
+    }
+
+    @NonNull
+    public static final Parcelable.Creator<VirtualSensorConfig> CREATOR =
+            new Parcelable.Creator<>() {
+                public VirtualSensorConfig createFromParcel(Parcel source) {
+                    return new VirtualSensorConfig(source);
+                }
+
+                public VirtualSensorConfig[] newArray(int size) {
+                    return new VirtualSensorConfig[size];
+                }
+            };
+}
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorEvent.aidl b/core/java/android/companion/virtual/sensor/VirtualSensorEvent.aidl
new file mode 100644
index 0000000..9943946
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+parcelable VirtualSensorEvent;
\ No newline at end of file
diff --git a/core/java/android/companion/virtual/sensor/VirtualSensorEvent.java b/core/java/android/companion/virtual/sensor/VirtualSensorEvent.java
new file mode 100644
index 0000000..8f8860e
--- /dev/null
+++ b/core/java/android/companion/virtual/sensor/VirtualSensorEvent.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.SystemClock;
+
+
+/**
+ * A sensor event that originated from a virtual device's sensor.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualSensorEvent implements Parcelable {
+
+    @NonNull
+    private float[] mValues;
+    private long mTimestampNanos;
+
+    private VirtualSensorEvent(@NonNull float[] values, long timestampNanos) {
+        mValues = values;
+        mTimestampNanos = timestampNanos;
+    }
+
+    private VirtualSensorEvent(@NonNull Parcel parcel) {
+        final int valuesLength = parcel.readInt();
+        mValues = new float[valuesLength];
+        parcel.readFloatArray(mValues);
+        mTimestampNanos = parcel.readLong();
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel parcel, int parcelableFlags) {
+        parcel.writeInt(mValues.length);
+        parcel.writeFloatArray(mValues);
+        parcel.writeLong(mTimestampNanos);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * Returns the values of this sensor event. The length and contents depend on the
+     * <a href="https://source.android.com/devices/sensors/sensor-types">sensor type</a>.
+     * @see android.hardware.SensorEvent#values
+     */
+    @NonNull
+    public float[] getValues() {
+        return mValues;
+    }
+
+    /**
+     * The time in nanoseconds at which the event happened. For a given sensor, each new sensor
+     * event should be monotonically increasing.
+     *
+     * @see Builder#setTimestampNanos(long)
+     */
+    public long getTimestampNanos() {
+        return mTimestampNanos;
+    }
+
+    /**
+     * Builder for {@link VirtualSensorEvent}.
+     */
+    public static final class Builder {
+
+        @NonNull
+        private float[] mValues;
+        private long mTimestampNanos = 0;
+
+        /**
+         * Creates a new builder.
+         * @param values the values of the sensor event. @see android.hardware.SensorEvent#values
+         */
+        public Builder(@NonNull float[] values) {
+            mValues = values;
+        }
+
+        /**
+         * Creates a new {@link VirtualSensorEvent}.
+         */
+        @NonNull
+        public VirtualSensorEvent build() {
+            if (mValues == null || mValues.length == 0) {
+                throw new IllegalArgumentException(
+                        "Cannot build virtual sensor event with no values.");
+            }
+            if (mTimestampNanos <= 0) {
+                mTimestampNanos = SystemClock.elapsedRealtimeNanos();
+            }
+            return new VirtualSensorEvent(mValues, mTimestampNanos);
+        }
+
+        /**
+         * Sets the timestamp of this event. For a given sensor, each new sensor event should be
+         * monotonically increasing using the same time base as
+         * {@link android.os.SystemClock#elapsedRealtimeNanos()}.
+         *
+         * If not explicitly set, the current timestamp is used for the sensor event.
+         *
+         * @see android.hardware.SensorEvent#timestamp
+         */
+        @NonNull
+        public Builder setTimestampNanos(long timestampNanos) {
+            mTimestampNanos = timestampNanos;
+            return this;
+        }
+    }
+
+    public static final @NonNull Parcelable.Creator<VirtualSensorEvent> CREATOR =
+            new Parcelable.Creator<>() {
+                public VirtualSensorEvent createFromParcel(Parcel source) {
+                    return new VirtualSensorEvent(source);
+                }
+
+                public VirtualSensorEvent[] newArray(int size) {
+                    return new VirtualSensorEvent[size];
+                }
+            };
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 0b20078..9f9fd3c 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3939,6 +3939,7 @@
             DISPLAY_HASH_SERVICE,
             CREDENTIAL_SERVICE,
             DEVICE_LOCK_SERVICE,
+            VIRTUALIZATION_SERVICE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ServiceName {}
@@ -6114,6 +6115,20 @@
     public static final String DEVICE_LOCK_SERVICE = "device_lock";
 
     /**
+     * Use with {@link #getSystemService(String)} to retrieve a
+     * {@link android.system.virtualmachine.VirtualMachineManager}.
+     *
+     * <p>On devices without {@link PackageManager#FEATURE_VIRTUALIZATION_FRAMEWORK} system feature
+     * the {@link #getSystemService(String)} will return {@code null}.
+     *
+     * @see #getSystemService(String)
+     * @see android.system.virtualmachine.VirtualMachineManager
+     * @hide
+     */
+    @SystemApi
+    public static final String VIRTUALIZATION_SERVICE = "virtualization";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
@@ -6186,7 +6201,7 @@
      */
     @CheckResult(suggest="#enforceCallingOrSelfPermission(String,String)")
     @PackageManager.PermissionResult
-    @PermissionMethod
+    @PermissionMethod(orSelf = true)
     public abstract int checkCallingOrSelfPermission(@NonNull @PermissionName String permission);
 
     /**
@@ -6254,7 +6269,7 @@
      *
      * @see #checkCallingOrSelfPermission(String)
      */
-    @PermissionMethod
+    @PermissionMethod(orSelf = true)
     public abstract void enforceCallingOrSelfPermission(
             @NonNull @PermissionName String permission, @Nullable String message);
 
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 9d82274..34c4ef3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3889,7 +3889,7 @@
             "android.intent.action.USER_INITIALIZE";
 
     /**
-     * Sent when a user switch is happening, causing the process's user to be
+     * Sent after a user switch is complete, if the switch caused the process's user to be
      * brought to the foreground.  This is only sent to receivers registered
      * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver}.  It is sent to the user that is going to the
@@ -3901,7 +3901,7 @@
             "android.intent.action.USER_FOREGROUND";
 
     /**
-     * Sent when a user switch is happening, causing the process's user to be
+     * Sent after a user switch is complete, if the switch caused the process's user to be
      * sent to the background.  This is only sent to receivers registered
      * through {@link Context#registerReceiver(BroadcastReceiver, IntentFilter)
      * Context.registerReceiver}.  It is sent to the user that is going to the
@@ -4042,6 +4042,11 @@
      * the current state of the user.
      * @hide
      */
+    /*
+     * This broadcast is sent after the user switch is complete. In case a task needs to be done
+     * while the switch is happening (i.e. while the screen is frozen to hide UI jank), please use
+     * ActivityManagerService.registerUserSwitchObserver method.
+     */
     @SystemApi
     public static final String ACTION_USER_SWITCHED =
             "android.intent.action.USER_SWITCHED";
@@ -6104,6 +6109,14 @@
     public static final String EXTRA_REPLACING = "android.intent.extra.REPLACING";
 
     /**
+     * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
+     * intents to indicate that this is a system update uninstall.
+     * @hide
+     */
+    public static final String EXTRA_SYSTEM_UPDATE_UNINSTALL =
+            "android.intent.extra.SYSTEM_UPDATE_UNINSTALL";
+
+    /**
      * Used as an int extra field in {@link android.app.AlarmManager} pending intents
      * to tell the application being invoked how many pending alarms are being
      * delivered with the intent.  For one-shot alarms this will always be 1.
diff --git a/core/java/android/content/om/FabricatedOverlay.java b/core/java/android/content/om/FabricatedOverlay.java
index cc7977a..99fc5a3 100644
--- a/core/java/android/content/om/FabricatedOverlay.java
+++ b/core/java/android/content/om/FabricatedOverlay.java
@@ -16,15 +16,21 @@
 
 package android.content.om;
 
+import android.annotation.IntDef;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.FabricatedOverlayInternal;
 import android.os.FabricatedOverlayInternalEntry;
 import android.os.ParcelFileDescriptor;
 import android.text.TextUtils;
+import android.util.TypedValue;
 
+import com.android.internal.content.om.OverlayManagerImpl;
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Objects;
 
@@ -82,8 +88,24 @@
         }
 
         /**
+         * Constructs a builder for building a fabricated overlay.
+         *
+         * @param name a name used to uniquely identify the fabricated overlay owned by the caller
+         *             itself.
+         * @param targetPackage the name of the package to overlay
+         */
+        public Builder(@NonNull String name, @NonNull String targetPackage) {
+            mName = OverlayManagerImpl.checkOverlayNameValid(name);
+            mTargetPackage =
+                    Preconditions.checkStringNotEmpty(
+                            targetPackage, "'targetPackage' must not be empty nor null");
+            mOwningPackage = ""; // The package name is filled in OverlayManager.commit
+        }
+
+        /**
          * Sets the name of the overlayable resources to overlay (can be null).
          */
+        @NonNull
         public Builder setTargetOverlayable(@Nullable String targetOverlayable) {
             mTargetOverlayable = TextUtils.emptyIfNull(targetOverlayable);
             return this;
@@ -111,45 +133,110 @@
         }
 
         /**
-         * Sets the value of the fabricated overlay
+         * Sets the value of the fabricated overlay for the integer-like types.
          *
          * @param resourceName name of the target resource to overlay (in the form
-         *                     [package]:type/entry)
+         *     [package]:type/entry)
          * @param dataType the data type of the new value
          * @param value the unsigned 32 bit integer representing the new value
-         *
+         * @return the builder itself
+         * @see #setResourceValue(String, int, int, String)
          * @see android.util.TypedValue#type
          */
-        public Builder setResourceValue(@NonNull String resourceName, int dataType, int value) {
+        @NonNull
+        public Builder setResourceValue(
+                @NonNull String resourceName,
+                @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT)
+                        int dataType,
+                int value) {
+            return setResourceValue(resourceName, dataType, value, null /* configuration */);
+        }
+
+        /**
+         * Sets the value of the fabricated overlay for the integer-like types with the
+         * configuration.
+         *
+         * @param resourceName name of the target resource to overlay (in the form
+         *     [package]:type/entry)
+         * @param dataType the data type of the new value
+         * @param value the unsigned 32 bit integer representing the new value
+         * @param configuration The string representation of the config this overlay is enabled for
+         * @see android.util.TypedValue#type
+         */
+        @NonNull
+        public Builder setResourceValue(
+                @NonNull String resourceName,
+                @IntRange(from = TypedValue.TYPE_FIRST_INT, to = TypedValue.TYPE_LAST_INT)
+                        int dataType,
+                int value,
+                @Nullable String configuration) {
             ensureValidResourceName(resourceName);
 
             final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
             entry.resourceName = resourceName;
-            entry.dataType = dataType;
+            entry.dataType =
+                    Preconditions.checkArgumentInRange(
+                            dataType,
+                            TypedValue.TYPE_FIRST_INT,
+                            TypedValue.TYPE_LAST_INT,
+                            "dataType");
             entry.data = value;
+            entry.configuration = configuration;
             mEntries.add(entry);
             return this;
         }
 
+        /** @hide */
+        @IntDef(
+                prefix = {"OVERLAY_TYPE"},
+                value = {
+                    TypedValue.TYPE_STRING,
+                })
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface StringTypeOverlayResource {}
+
         /**
-         * Sets the value of the fabricated overlay
+         * Sets the value of the fabricated overlay for the string-like type.
          *
          * @param resourceName name of the target resource to overlay (in the form
-         *                     [package]:type/entry)
+         *     [package]:type/entry)
          * @param dataType the data type of the new value
-         * @param value the unsigned 32 bit integer representing the new value
-         * @param configuration The string representation of the config this overlay is enabled for
-         *
+         * @param value the string representing the new value
+         * @return the builder itself
          * @see android.util.TypedValue#type
          */
-        public Builder setResourceValue(@NonNull String resourceName, int dataType, int value,
-                String configuration) {
+        @NonNull
+        public Builder setResourceValue(
+                @NonNull String resourceName,
+                @StringTypeOverlayResource int dataType,
+                @NonNull String value) {
+            return setResourceValue(resourceName, dataType, value, null /* configuration */);
+        }
+
+        /**
+         * Sets the value of the fabricated overlay for the string-like type with the configuration.
+         *
+         * @param resourceName name of the target resource to overlay (in the form
+         *     [package]:type/entry)
+         * @param dataType the data type of the new value
+         * @param value the string representing the new value
+         * @param configuration The string representation of the config this overlay is enabled for
+         * @see android.util.TypedValue#type
+         */
+        @NonNull
+        public Builder setResourceValue(
+                @NonNull String resourceName,
+                @StringTypeOverlayResource int dataType,
+                @NonNull String value,
+                @Nullable String configuration) {
             ensureValidResourceName(resourceName);
 
             final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
             entry.resourceName = resourceName;
-            entry.dataType = dataType;
-            entry.data = value;
+            entry.dataType =
+                    Preconditions.checkArgumentInRange(
+                            dataType, TypedValue.TYPE_STRING, TypedValue.TYPE_FRACTION, "dataType");
+            entry.stringData = Objects.requireNonNull(value);
             entry.configuration = configuration;
             mEntries.add(entry);
             return this;
@@ -159,68 +246,32 @@
          * Sets the value of the fabricated overlay
          *
          * @param resourceName name of the target resource to overlay (in the form
-         *                     [package]:type/entry)
-         * @param dataType the data type of the new value
-         * @param value the string representing the new value
-         *
-         * @see android.util.TypedValue#type
-         */
-        public Builder setResourceValue(@NonNull String resourceName, int dataType, String value) {
-            ensureValidResourceName(resourceName);
-
-            final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
-            entry.resourceName = resourceName;
-            entry.dataType = dataType;
-            entry.stringData = value;
-            mEntries.add(entry);
-            return this;
-        }
-
-        /**
-         * Sets the value of the fabricated overlay
-         *
-         * @param resourceName name of the target resource to overlay (in the form
-         *                     [package]:type/entry)
-         * @param dataType the data type of the new value
-         * @param value the string representing the new value
-         * @param configuration The string representation of the config this overlay is enabled for
-         *
-         * @see android.util.TypedValue#type
-         */
-        public Builder setResourceValue(@NonNull String resourceName, int dataType, String value,
-                String configuration) {
-            ensureValidResourceName(resourceName);
-
-            final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
-            entry.resourceName = resourceName;
-            entry.dataType = dataType;
-            entry.stringData = value;
-            entry.configuration = configuration;
-            mEntries.add(entry);
-            return this;
-        }
-
-        /**
-         * Sets the value of the fabricated overlay
-         *
-         * @param resourceName name of the target resource to overlay (in the form
-         *                     [package]:type/entry)
+         *     [package]:type/entry)
          * @param value the file descriptor whose contents are the value of the frro
          * @param configuration The string representation of the config this overlay is enabled for
+         * @return the builder itself
          */
-        public Builder setResourceValue(@NonNull String resourceName, ParcelFileDescriptor value,
-                String configuration) {
+        @NonNull
+        public Builder setResourceValue(
+                @NonNull String resourceName,
+                @NonNull ParcelFileDescriptor value,
+                @Nullable String configuration) {
             ensureValidResourceName(resourceName);
 
             final FabricatedOverlayInternalEntry entry = new FabricatedOverlayInternalEntry();
             entry.resourceName = resourceName;
-            entry.binaryData = value;
+            entry.binaryData = Objects.requireNonNull(value);
             entry.configuration = configuration;
             mEntries.add(entry);
             return this;
         }
 
-        /** Builds an immutable fabricated overlay. */
+        /**
+         * Builds an immutable fabricated overlay.
+         *
+         * @return the fabricated overlay
+         */
+        @NonNull
         public FabricatedOverlay build() {
             final FabricatedOverlayInternal overlay = new FabricatedOverlayInternal();
             overlay.packageName = mOwningPackage;
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index c66f49c..a470de2 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -51,6 +51,7 @@
             STATE_ENABLED_IMMUTABLE,
             // @Deprecated STATE_TARGET_IS_BEING_REPLACED,
             STATE_OVERLAY_IS_BEING_REPLACED,
+            STATE_SYSTEM_UPDATE_UNINSTALL,
     })
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
@@ -128,6 +129,14 @@
     public static final int STATE_ENABLED_IMMUTABLE = 6;
 
     /**
+     * The target package needs to be refreshed as a result of a system update uninstall, which
+     * must recalculate the state of overlays against the newly enabled system package, which may
+     * differ in resources/policy from the /data variant that was uninstalled.
+     * @hide
+     */
+    public static final int STATE_SYSTEM_UPDATE_UNINSTALL = 7;
+
+    /**
      * Overlay category: theme.
      * <p>
      * Change how Android (including the status bar, dialogs, ...) looks.
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 94275ae..ed1f6a2 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -17,6 +17,7 @@
 package android.content.om;
 
 import android.annotation.NonNull;
+import android.annotation.NonUiContext;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -25,12 +26,16 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 
+import com.android.internal.content.om.OverlayManagerImpl;
+
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -76,6 +81,7 @@
 
     private final IOverlayManager mService;
     private final Context mContext;
+    private final OverlayManagerImpl mOverlayManagerImpl;
 
     /**
      * Pre R a {@link java.lang.SecurityException} would only be thrown by setEnabled APIs (e
@@ -92,6 +98,21 @@
     private static final long THROW_SECURITY_EXCEPTIONS = 147340954;
 
     /**
+     * Applications can use OverlayManager to create overlays to overlay on itself resources. The
+     * overlay target is itself and the work range is only in caller application.
+     *
+     * <p>In {@link android.content.Context#getSystemService(String)}, it crashes because of {@link
+     * java.lang.NullPointerException} if the parameter is OverlayManager. if the self-targeting is
+     * enabled, the caller application can get the OverlayManager instance to use self-targeting
+     * functionality.
+     *
+     * @hide
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    public static final long SELF_TARGETING_OVERLAY = 205919743;
+
+    /**
      * Creates a new instance.
      *
      * @param context The current context in which to operate.
@@ -102,6 +123,7 @@
     public OverlayManager(Context context, IOverlayManager service) {
         mContext = context;
         mService = service;
+        mOverlayManagerImpl = new OverlayManagerImpl(context);
     }
 
     /** @hide */
@@ -286,6 +308,17 @@
      * @hide
      */
     public void commit(@NonNull final OverlayManagerTransaction transaction) {
+        if (transaction.isSelfTargetingTransaction()
+                || mService == null
+                || mService.asBinder() == null) {
+            try {
+                commitSelfTarget(transaction);
+            } catch (PackageManager.NameNotFoundException | IOException e) {
+                throw new RuntimeException(e);
+            }
+            return;
+        }
+
         try {
             mService.commit(transaction);
         } catch (RemoteException e) {
@@ -317,4 +350,48 @@
             throw e;
         }
     }
+
+    /**
+     * Get a OverlayManagerTransaction.Builder to build out a overlay manager transaction.
+     *
+     * @return a builder of the overlay manager transaction.
+     * @hide
+     */
+    @NonNull
+    public OverlayManagerTransaction.Builder beginTransaction() {
+        return new OverlayManagerTransaction.Builder(this);
+    }
+
+    /**
+     * Commit the self-targeting transaction to register or unregister overlays.
+     *
+     * <p>Applications can request OverlayManager to register overlays and unregister the registered
+     * overlays via {@link OverlayManagerTransaction}.
+     *
+     * @throws IOException if there is a file operation error.
+     * @throws PackageManager.NameNotFoundException if the package name is not found.
+     * @hide
+     */
+    @NonUiContext
+    void commitSelfTarget(@NonNull final OverlayManagerTransaction transaction)
+            throws PackageManager.NameNotFoundException, IOException {
+        synchronized (mOverlayManagerImpl) {
+            mOverlayManagerImpl.commit(transaction);
+        }
+    }
+
+    /**
+     * Get the related information of overlays for {@code targetPackageName}.
+     *
+     * @param targetPackageName the target package name
+     * @return a list of overlay information
+     * @hide
+     */
+    @NonNull
+    @NonUiContext
+    public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName) {
+        synchronized (mOverlayManagerImpl) {
+            return mOverlayManagerImpl.getOverlayInfosForTarget(targetPackageName);
+        }
+    }
 }
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
index 868dab2..42b3ef3 100644
--- a/core/java/android/content/om/OverlayManagerTransaction.java
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -20,19 +20,22 @@
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.NonUiContext;
 import android.annotation.Nullable;
-import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
 
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Objects;
 
 /**
  * Container for a batch of requests to the OverlayManagerService.
@@ -53,13 +56,16 @@
     // TODO: remove @hide from this class when OverlayManager is added to the
     // SDK, but keep OverlayManagerTransaction.Request @hidden
     private final List<Request> mRequests;
+    private final OverlayManager mOverlayManager;
 
-    OverlayManagerTransaction(@NonNull final List<Request> requests) {
+    OverlayManagerTransaction(
+            @NonNull final List<Request> requests, @Nullable OverlayManager overlayManager) {
         checkNotNull(requests);
         if (requests.contains(null)) {
             throw new IllegalArgumentException("null request");
         }
         mRequests = requests;
+        mOverlayManager = overlayManager;
     }
 
     private OverlayManagerTransaction(@NonNull final Parcel source) {
@@ -72,6 +78,7 @@
             final Bundle extras = source.readBundle(null);
             mRequests.add(new Request(request, overlay, userId, extras));
         }
+        mOverlayManager = null;
     }
 
     @Override
@@ -156,6 +163,20 @@
      */
     public static class Builder {
         private final List<Request> mRequests = new ArrayList<>();
+        @Nullable private final OverlayManager mOverlayManager;
+
+        public Builder() {
+            mOverlayManager = null;
+        }
+
+        /**
+         * The transaction builder for self-targeting.
+         *
+         * @param overlayManager is not null if the transaction is for self-targeting.
+         */
+        Builder(@NonNull OverlayManager overlayManager) {
+            mOverlayManager = Objects.requireNonNull(overlayManager);
+        }
 
         /**
          * Request that an overlay package be enabled and change its loading
@@ -205,7 +226,10 @@
          *
          * @hide
          */
+        @NonNull
         public Builder registerFabricatedOverlay(@NonNull FabricatedOverlay overlay) {
+            Objects.requireNonNull(overlay);
+
             final Bundle extras = new Bundle();
             extras.putParcelable(Request.BUNDLE_FABRICATED_OVERLAY, overlay.mOverlay);
             mRequests.add(new Request(Request.TYPE_REGISTER_FABRICATED, overlay.getIdentifier(),
@@ -220,7 +244,10 @@
          *
          * @hide
          */
+        @NonNull
         public Builder unregisterFabricatedOverlay(@NonNull OverlayIdentifier overlay) {
+            Objects.requireNonNull(overlay);
+
             mRequests.add(new Request(Request.TYPE_UNREGISTER_FABRICATED, overlay,
                     UserHandle.USER_ALL));
             return this;
@@ -233,8 +260,9 @@
          * @see OverlayManager#commit
          * @return a new transaction
          */
+        @NonNull
         public OverlayManagerTransaction build() {
-            return new OverlayManagerTransaction(mRequests);
+            return new OverlayManagerTransaction(mRequests, mOverlayManager);
         }
     }
 
@@ -269,4 +297,23 @@
             return new OverlayManagerTransaction[size];
         }
     };
+
+    /**
+     * Commit the overlay manager transaction to register or unregister overlays for self-targeting.
+     *
+     * <p>Applications can register overlays and unregister the registered overlays via {@link
+     * OverlayManagerTransaction}.
+     *
+     * @throws IOException if there is a file operation error.
+     * @throws PackageManager.NameNotFoundException if the package name is not found.
+     * @hide
+     */
+    @NonUiContext
+    public void commit() throws PackageManager.NameNotFoundException, IOException {
+        mOverlayManager.commitSelfTarget(this);
+    }
+
+    boolean isSelfTargetingTransaction() {
+        return mOverlayManager != null;
+    }
 }
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index fda4119..dab57fd 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -221,21 +221,20 @@
     public String launchToken;
 
     /**
-     * Specifies the category of the target display the activity is expected to run on. Set from
-     * the {@link android.R.attr#targetDisplayCategory} attribute. Upon creation, a virtual display
-     * can specify which display categories it supports and one of the category must be present in
-     * the activity's manifest to allow this activity to run. The default value is {@code null},
-     * which indicates the activity does not belong to a restricted display category and thus can
-     * only run on a display that didn't specify any display categories. Each activity can only
-     * specify one category it targets to but a virtual display can support multiple restricted
-     * categories.
-     *
+     * Specifies the required display category of the activity. Set from the
+     * {@link android.R.attr#requiredDisplayCategory} attribute. Upon creation, a display can
+     * specify which display categories it supports and one of the category must be present
+     * in the {@code <activity>} element to allow this activity to run. The default value is
+     * {@code null}, which indicates the activity does not have a required display category and
+     * thus can only run on a display that didn't specify any display categories. Each activity
+     * can only specify one required category but a display can support multiple display categories.
+     * <p>
      * This field should be formatted as a Java-language-style free form string(for example,
      * com.google.automotive_entertainment), which may contain uppercase or lowercase letters ('A'
      * through 'Z'), numbers, and underscores ('_') but may only start with letters.
      */
     @Nullable
-    public String targetDisplayCategory;
+    public String requiredDisplayCategory;
 
     /**
      * Activity can not be resized and always occupies the fullscreen area with all windows fully
@@ -1330,7 +1329,7 @@
         mMaxAspectRatio = orig.mMaxAspectRatio;
         mMinAspectRatio = orig.mMinAspectRatio;
         supportsSizeChanges = orig.supportsSizeChanges;
-        targetDisplayCategory = orig.targetDisplayCategory;
+        requiredDisplayCategory = orig.requiredDisplayCategory;
     }
 
     /**
@@ -1669,8 +1668,8 @@
         if (mKnownActivityEmbeddingCerts != null) {
             pw.println(prefix + "knownActivityEmbeddingCerts=" + mKnownActivityEmbeddingCerts);
         }
-        if (targetDisplayCategory != null) {
-            pw.println(prefix + "targetDisplayCategory=" + targetDisplayCategory);
+        if (requiredDisplayCategory != null) {
+            pw.println(prefix + "requiredDisplayCategory=" + requiredDisplayCategory);
         }
         super.dumpBack(pw, prefix, dumpFlags);
     }
@@ -1718,7 +1717,7 @@
         dest.writeFloat(mMinAspectRatio);
         dest.writeBoolean(supportsSizeChanges);
         sForStringSet.parcel(mKnownActivityEmbeddingCerts, dest, flags);
-        dest.writeString8(targetDisplayCategory);
+        dest.writeString8(requiredDisplayCategory);
     }
 
     /**
@@ -1844,7 +1843,7 @@
         if (mKnownActivityEmbeddingCerts.isEmpty()) {
             mKnownActivityEmbeddingCerts = null;
         }
-        targetDisplayCategory = source.readString8();
+        requiredDisplayCategory = source.readString8();
     }
 
     /**
diff --git a/core/java/android/content/pm/IPackageInstaller.aidl b/core/java/android/content/pm/IPackageInstaller.aidl
index 12911d6..1e928bd 100644
--- a/core/java/android/content/pm/IPackageInstaller.aidl
+++ b/core/java/android/content/pm/IPackageInstaller.aidl
@@ -23,6 +23,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.pm.VersionedPackage;
 import android.content.IntentSender;
+import android.os.RemoteCallback;
 
 import android.graphics.Bitmap;
 
@@ -66,4 +67,6 @@
 
     void setAllowUnlimitedSilentUpdates(String installerPackageName);
     void setSilentUpdatesThrottleTime(long throttleTimeInSeconds);
+    void checkInstallConstraints(String installerPackageName, in List<String> packageNames,
+            in PackageInstaller.InstallConstraints constraints, in RemoteCallback callback);
 }
diff --git a/core/java/android/content/pm/IPackageInstallerSession.aidl b/core/java/android/content/pm/IPackageInstallerSession.aidl
index 1fc6bda..7d9c64a 100644
--- a/core/java/android/content/pm/IPackageInstallerSession.aidl
+++ b/core/java/android/content/pm/IPackageInstallerSession.aidl
@@ -61,4 +61,6 @@
     int getInstallFlags();
 
     void requestUserPreapproval(in PackageInstaller.PreapprovalDetails details, in IntentSender statusReceiver);
+
+    boolean isKeepApplicationEnabledSetting();
 }
diff --git a/core/java/android/content/pm/PackageInstaller.aidl b/core/java/android/content/pm/PackageInstaller.aidl
index 833919e..ab9d4f3 100644
--- a/core/java/android/content/pm/PackageInstaller.aidl
+++ b/core/java/android/content/pm/PackageInstaller.aidl
@@ -16,6 +16,7 @@
 
 package android.content.pm;
 
+parcelable PackageInstaller.InstallConstraints;
 parcelable PackageInstaller.SessionParams;
 parcelable PackageInstaller.SessionInfo;
 parcelable PackageInstaller.PreapprovalDetails;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d7686e2..c79f99d 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -36,6 +36,7 @@
 import android.annotation.RequiresPermission;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.app.ActivityManager;
@@ -57,6 +58,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
 import android.os.ParcelableException;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
@@ -89,6 +91,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.concurrent.Executor;
+import java.util.function.Consumer;
 
 /**
  * Offers the ability to install, upgrade, and remove applications on the
@@ -854,6 +857,29 @@
     }
 
     /**
+     * Check if install constraints are satisfied for the given packages.
+     *
+     * Note this query result is just a hint and subject to race because system states could
+     * change anytime in-between this query and committing the session.
+     *
+     * The result is returned by a callback because some constraints might take a long time
+     * to evaluate.
+     */
+    public void checkInstallConstraints(@NonNull List<String> packageNames,
+            @NonNull InstallConstraints constraints,
+            @NonNull Consumer<InstallConstraintsResult> callback) {
+        try {
+            var remoteCallback = new RemoteCallback(b -> {
+                callback.accept(b.getParcelable("result", InstallConstraintsResult.class));
+            });
+            mInstaller.checkInstallConstraints(
+                    mInstallerPackageName, packageNames, constraints, remoteCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Events for observing session lifecycle.
      * <p>
      * A typical session lifecycle looks like this:
@@ -1717,6 +1743,18 @@
                 e.rethrowFromSystemServer();
             }
         }
+
+        /**
+         * @return {@code true} if this session will keep the existing application enabled setting
+         * after installation.
+         */
+        public boolean isKeepApplicationEnabledSetting() {
+            try {
+                return mSession.isKeepApplicationEnabledSetting();
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        }
     }
 
     /**
@@ -1855,6 +1893,8 @@
         public boolean forceQueryableOverride;
         /** {@hide} */
         public int requireUserAction = USER_ACTION_UNSPECIFIED;
+        /** {@hide} */
+        public boolean keepApplicationEnabledSetting = false;
 
         /**
          * Construct parameters for a new package install session.
@@ -1899,6 +1939,7 @@
             rollbackDataPolicy = source.readInt();
             requireUserAction = source.readInt();
             packageSource = source.readInt();
+            keepApplicationEnabledSetting = source.readBoolean();
         }
 
         /** {@hide} */
@@ -1929,6 +1970,7 @@
             ret.rollbackDataPolicy = rollbackDataPolicy;
             ret.requireUserAction = requireUserAction;
             ret.packageSource = packageSource;
+            ret.keepApplicationEnabledSetting = keepApplicationEnabledSetting;
             return ret;
         }
 
@@ -2415,6 +2457,14 @@
             this.installScenario = installScenario;
         }
 
+        /**
+         * Request to keep the original application enabled setting. This will prevent the
+         * application from being enabled if it was previously in a disabled state.
+         */
+        public void setKeepApplicationEnabledSetting() {
+            this.keepApplicationEnabledSetting = true;
+        }
+
         /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
@@ -2443,6 +2493,7 @@
             pw.printPair("requiredInstalledVersionCode", requiredInstalledVersionCode);
             pw.printPair("dataLoaderParams", dataLoaderParams);
             pw.printPair("rollbackDataPolicy", rollbackDataPolicy);
+            pw.printPair("keepApplicationEnabledSetting", keepApplicationEnabledSetting);
             pw.println();
         }
 
@@ -2483,6 +2534,7 @@
             dest.writeInt(rollbackDataPolicy);
             dest.writeInt(requireUserAction);
             dest.writeInt(packageSource);
+            dest.writeBoolean(keepApplicationEnabledSetting);
         }
 
         public static final Parcelable.Creator<SessionParams>
@@ -2684,6 +2736,9 @@
         /** @hide */
         public boolean isPreapprovalRequested;
 
+        /** @hide */
+        public boolean keepApplicationEnabledSetting;
+
         /** {@hide} */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public SessionInfo() {
@@ -2737,6 +2792,7 @@
             requireUserAction = source.readInt();
             installerUid = source.readInt();
             packageSource = source.readInt();
+            keepApplicationEnabledSetting = source.readBoolean();
         }
 
         /**
@@ -3268,6 +3324,14 @@
             return installerUid;
         }
 
+        /**
+         * Returns {@code true} if this session will keep the existing application enabled setting
+         * after installation.
+         */
+        public boolean isKeepApplicationEnabledSetting() {
+            return keepApplicationEnabledSetting;
+        }
+
         @Override
         public int describeContents() {
             return 0;
@@ -3317,6 +3381,7 @@
             dest.writeInt(requireUserAction);
             dest.writeInt(installerUid);
             dest.writeInt(packageSource);
+            dest.writeBoolean(keepApplicationEnabledSetting);
         }
 
         public static final Parcelable.Creator<SessionInfo>
@@ -3608,4 +3673,362 @@
         // End of generated code
 
     }
+
+    /**
+     * The callback result of {@link #checkInstallConstraints(List, InstallConstraints, Consumer)}.
+     */
+    @DataClass(genParcelable = true, genHiddenConstructor = true)
+    public static final class InstallConstraintsResult implements Parcelable {
+        /**
+         * True if all constraints are satisfied.
+         */
+        private boolean mAllConstraintsSatisfied;
+
+
+
+        // Code below generated by codegen v1.0.23.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new InstallConstraintsResult.
+         *
+         * @param allConstraintsSatisfied
+         *   True if all constraints are satisfied.
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public InstallConstraintsResult(
+                boolean allConstraintsSatisfied) {
+            this.mAllConstraintsSatisfied = allConstraintsSatisfied;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        /**
+         * True if all constraints are satisfied.
+         */
+        @DataClass.Generated.Member
+        public boolean isAllConstraintsSatisfied() {
+            return mAllConstraintsSatisfied;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (mAllConstraintsSatisfied) flg |= 0x1;
+            dest.writeByte(flg);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ InstallConstraintsResult(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            boolean allConstraintsSatisfied = (flg & 0x1) != 0;
+
+            this.mAllConstraintsSatisfied = allConstraintsSatisfied;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<InstallConstraintsResult> CREATOR
+                = new Parcelable.Creator<InstallConstraintsResult>() {
+            @Override
+            public InstallConstraintsResult[] newArray(int size) {
+                return new InstallConstraintsResult[size];
+            }
+
+            @Override
+            public InstallConstraintsResult createFromParcel(@NonNull Parcel in) {
+                return new InstallConstraintsResult(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1668650523745L,
+                codegenVersion = "1.0.23",
+                sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
+                inputSignatures = "private  boolean mAllConstraintsSatisfied\nclass InstallConstraintsResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
+    /**
+     * A class to encapsulate constraints for installation.
+     *
+     * When used with {@link #checkInstallConstraints(List, InstallConstraints, Consumer)}, it
+     * specifies the conditions to check against for the packages in question. This can be used
+     * by app stores to deliver auto updates without disrupting the user experience (referred as
+     * gentle update) - for example, an app store might hold off updates when it find out the
+     * app to update is interacting with the user.
+     *
+     * Use {@link Builder} to create a new instance and call mutator methods to add constraints.
+     * If no mutators were called, default constraints will be generated which implies no
+     * constraints. It is recommended to use preset constraints which are useful in most
+     * cases.
+     *
+     * For the purpose of gentle update, it is recommended to always use {@link #GENTLE_UPDATE}
+     * for the system knows best how to do it. It will also benefits the installer as the
+     * platform evolves and add more constraints to improve the accuracy and efficiency of
+     * gentle update.
+     *
+     * Note the constraints are applied transitively. If app Foo is used by app Bar (via shared
+     * library or bounded service), the constraints will also be applied to Bar.
+     */
+    @DataClass(genParcelable = true, genHiddenConstructor = true)
+    public static final class InstallConstraints implements Parcelable {
+        /**
+         * Preset constraints suitable for gentle update.
+         */
+        @NonNull
+        public static final InstallConstraints GENTLE_UPDATE =
+                new Builder().requireAppNotInteracting().build();
+
+        private final boolean mRequireDeviceIdle;
+        private final boolean mRequireAppNotForeground;
+        private final boolean mRequireAppNotInteracting;
+        private final boolean mRequireAppNotTopVisible;
+        private final boolean mRequireNotInCall;
+
+        /**
+         * Builder class for constructing {@link InstallConstraints}.
+         */
+        public static final class Builder {
+            private boolean mRequireDeviceIdle;
+            private boolean mRequireAppNotForeground;
+            private boolean mRequireAppNotInteracting;
+            private boolean mRequireAppNotTopVisible;
+            private boolean mRequireNotInCall;
+
+            /**
+             * This constraint requires the device is idle.
+             */
+            @SuppressLint("BuilderSetStyle")
+            @NonNull
+            public Builder requireDeviceIdle() {
+                mRequireDeviceIdle = true;
+                return this;
+            }
+
+            /**
+             * This constraint requires the app in question is not in the foreground.
+             */
+            @SuppressLint("BuilderSetStyle")
+            @NonNull
+            public Builder requireAppNotForeground() {
+                mRequireAppNotForeground = true;
+                return this;
+            }
+
+            /**
+             * This constraint requires the app in question is not interacting with the user.
+             * User interaction includes:
+             * <ul>
+             *     <li>playing or recording audio/video</li>
+             *     <li>sending or receiving network data</li>
+             *     <li>being visible to the user</li>
+             * </ul>
+             */
+            @SuppressLint("BuilderSetStyle")
+            @NonNull
+            public Builder requireAppNotInteracting() {
+                mRequireAppNotInteracting = true;
+                return this;
+            }
+
+            /**
+             * This constraint requires the app in question is not top-visible to the user.
+             * A top-visible app is showing UI at the top of the screen that the user is
+             * interacting with.
+             *
+             * Note this constraint is a subset of {@link #requireAppNotForeground()}
+             * because a top-visible app is also a foreground app. This is also a subset
+             * of {@link #requireAppNotInteracting()} because a top-visible app is interacting
+             * with the user.
+             */
+            @SuppressLint("BuilderSetStyle")
+            @NonNull
+            public Builder requireAppNotTopVisible() {
+                mRequireAppNotTopVisible = true;
+                return this;
+            }
+
+            /**
+             * This constraint requires there is no ongoing call in the device.
+             */
+            @SuppressLint("BuilderSetStyle")
+            @NonNull
+            public Builder requireNotInCall() {
+                mRequireNotInCall = true;
+                return this;
+            }
+
+            /**
+             * Builds a new {@link InstallConstraints} instance.
+             */
+            @NonNull
+            public InstallConstraints build() {
+                return new InstallConstraints(mRequireDeviceIdle, mRequireAppNotForeground,
+                        mRequireAppNotInteracting, mRequireAppNotTopVisible, mRequireNotInCall);
+            }
+        }
+
+
+
+        // Code below generated by codegen v1.0.23.
+        //
+        // DO NOT MODIFY!
+        // CHECKSTYLE:OFF Generated code
+        //
+        // To regenerate run:
+        // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/PackageInstaller.java
+        //
+        // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+        //   Settings > Editor > Code Style > Formatter Control
+        //@formatter:off
+
+
+        /**
+         * Creates a new InstallConstraints.
+         *
+         * @hide
+         */
+        @DataClass.Generated.Member
+        public InstallConstraints(
+                boolean requireDeviceIdle,
+                boolean requireAppNotForeground,
+                boolean requireAppNotInteracting,
+                boolean requireAppNotTopVisible,
+                boolean requireNotInCall) {
+            this.mRequireDeviceIdle = requireDeviceIdle;
+            this.mRequireAppNotForeground = requireAppNotForeground;
+            this.mRequireAppNotInteracting = requireAppNotInteracting;
+            this.mRequireAppNotTopVisible = requireAppNotTopVisible;
+            this.mRequireNotInCall = requireNotInCall;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public boolean isRequireDeviceIdle() {
+            return mRequireDeviceIdle;
+        }
+
+        @DataClass.Generated.Member
+        public boolean isRequireAppNotForeground() {
+            return mRequireAppNotForeground;
+        }
+
+        @DataClass.Generated.Member
+        public boolean isRequireAppNotInteracting() {
+            return mRequireAppNotInteracting;
+        }
+
+        @DataClass.Generated.Member
+        public boolean isRequireAppNotTopVisible() {
+            return mRequireAppNotTopVisible;
+        }
+
+        @DataClass.Generated.Member
+        public boolean isRequireNotInCall() {
+            return mRequireNotInCall;
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            // You can override field parcelling by defining methods like:
+            // void parcelFieldName(Parcel dest, int flags) { ... }
+
+            byte flg = 0;
+            if (mRequireDeviceIdle) flg |= 0x1;
+            if (mRequireAppNotForeground) flg |= 0x2;
+            if (mRequireAppNotInteracting) flg |= 0x4;
+            if (mRequireAppNotTopVisible) flg |= 0x8;
+            if (mRequireNotInCall) flg |= 0x10;
+            dest.writeByte(flg);
+        }
+
+        @Override
+        @DataClass.Generated.Member
+        public int describeContents() { return 0; }
+
+        /** @hide */
+        @SuppressWarnings({"unchecked", "RedundantCast"})
+        @DataClass.Generated.Member
+        /* package-private */ InstallConstraints(@NonNull Parcel in) {
+            // You can override field unparcelling by defining methods like:
+            // static FieldType unparcelFieldName(Parcel in) { ... }
+
+            byte flg = in.readByte();
+            boolean requireDeviceIdle = (flg & 0x1) != 0;
+            boolean requireAppNotForeground = (flg & 0x2) != 0;
+            boolean requireAppNotInteracting = (flg & 0x4) != 0;
+            boolean requireAppNotTopVisible = (flg & 0x8) != 0;
+            boolean requireNotInCall = (flg & 0x10) != 0;
+
+            this.mRequireDeviceIdle = requireDeviceIdle;
+            this.mRequireAppNotForeground = requireAppNotForeground;
+            this.mRequireAppNotInteracting = requireAppNotInteracting;
+            this.mRequireAppNotTopVisible = requireAppNotTopVisible;
+            this.mRequireNotInCall = requireNotInCall;
+
+            // onConstructed(); // You can define this method to get a callback
+        }
+
+        @DataClass.Generated.Member
+        public static final @NonNull Parcelable.Creator<InstallConstraints> CREATOR
+                = new Parcelable.Creator<InstallConstraints>() {
+            @Override
+            public InstallConstraints[] newArray(int size) {
+                return new InstallConstraints[size];
+            }
+
+            @Override
+            public InstallConstraints createFromParcel(@NonNull Parcel in) {
+                return new InstallConstraints(in);
+            }
+        };
+
+        @DataClass.Generated(
+                time = 1668650523752L,
+                codegenVersion = "1.0.23",
+                sourceFile = "frameworks/base/core/java/android/content/pm/PackageInstaller.java",
+                inputSignatures = "public static final @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints GENTLE_UPDATE\nprivate final  boolean mRequireDeviceIdle\nprivate final  boolean mRequireAppNotForeground\nprivate final  boolean mRequireAppNotInteracting\nprivate final  boolean mRequireAppNotTopVisible\nprivate final  boolean mRequireNotInCall\nclass InstallConstraints extends java.lang.Object implements [android.os.Parcelable]\nprivate  boolean mRequireDeviceIdle\nprivate  boolean mRequireAppNotForeground\nprivate  boolean mRequireAppNotInteracting\nprivate  boolean mRequireAppNotTopVisible\nprivate  boolean mRequireNotInCall\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder requireDeviceIdle()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotForeground()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotInteracting()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder requireAppNotTopVisible()\npublic @android.annotation.SuppressLint @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints.Builder requireNotInCall()\npublic @android.annotation.NonNull android.content.pm.PackageInstaller.InstallConstraints build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genParcelable=true, genHiddenConstructor=true)")
+        @Deprecated
+        private void __metadata() {}
+
+
+        //@formatter:on
+        // End of generated code
+
+    }
+
 }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 485d04d..88b5e02 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1959,6 +1959,14 @@
     public static final int INSTALL_FAILED_MISSING_SPLIT = -28;
 
     /**
+     * Installation return code: this is passed in the {@link PackageInstaller#EXTRA_LEGACY_STATUS}
+     * if the new package targets a deprecated SDK version.
+     *
+     * @hide
+     */
+    public static final int INSTALL_FAILED_DEPRECATED_SDK_VERSION = -29;
+
+    /**
      * Installation parse return code: this is passed in the
      * {@link PackageInstaller#EXTRA_LEGACY_STATUS} if the parser was given a path that is not a
      * file, or does not end with the expected '.apk' extension.
@@ -9618,6 +9626,7 @@
             case INSTALL_FAILED_ABORTED: return "INSTALL_FAILED_ABORTED";
             case INSTALL_FAILED_BAD_DEX_METADATA: return "INSTALL_FAILED_BAD_DEX_METADATA";
             case INSTALL_FAILED_MISSING_SPLIT: return "INSTALL_FAILED_MISSING_SPLIT";
+            case INSTALL_FAILED_DEPRECATED_SDK_VERSION: return "INSTALL_FAILED_DEPRECATED_SDK_VERSION";
             case INSTALL_FAILED_BAD_SIGNATURE: return "INSTALL_FAILED_BAD_SIGNATURE";
             case INSTALL_FAILED_WRONG_INSTALLED_VERSION: return "INSTALL_FAILED_WRONG_INSTALLED_VERSION";
             case INSTALL_FAILED_PROCESS_NOT_DEFINED: return "INSTALL_FAILED_PROCESS_NOT_DEFINED";
@@ -9675,6 +9684,7 @@
             case INSTALL_FAILED_ABORTED: return PackageInstaller.STATUS_FAILURE_ABORTED;
             case INSTALL_FAILED_MISSING_SPLIT: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
             case INSTALL_FAILED_PRE_APPROVAL_NOT_AVAILABLE: return PackageInstaller.STATUS_FAILURE_BLOCKED;
+            case INSTALL_FAILED_DEPRECATED_SDK_VERSION: return PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;
             default: return PackageInstaller.STATUS_FAILURE;
         }
     }
diff --git a/core/java/android/content/pm/PermissionMethod.java b/core/java/android/content/pm/PermissionMethod.java
index ba97342..647c696 100644
--- a/core/java/android/content/pm/PermissionMethod.java
+++ b/core/java/android/content/pm/PermissionMethod.java
@@ -33,4 +33,20 @@
  */
 @Retention(CLASS)
 @Target({METHOD})
-public @interface PermissionMethod {}
+public @interface PermissionMethod {
+    /**
+     * Hard-coded list of permissions checked by this method
+     */
+    @PermissionName String[] value() default {};
+    /**
+     * If true, the check passes if the caller
+     * has any ONE of the supplied permissions
+     */
+    boolean anyOf() default false;
+    /**
+     * Signifies that the permission check passes if
+     * the calling process OR the current process has
+     * the permission
+     */
+    boolean orSelf() default false;
+}
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 14f03ea..fc2c532 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -106,7 +106,7 @@
      * <p>Apps targeting API level {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} and
      * later should NOT use this type,
      * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
-     * this type will get a {@link android.app.ForegroundServiceTypeNotAllowedException}.</p>
+     * this type will get a {@link android.app.InvalidForegroundServiceTypeException}.</p>
      *
      * @deprecated Do not use.
      */
@@ -124,7 +124,7 @@
      * calling {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
      * this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE} is still
      * allowed, but calling it with this type on devices running future platform releases may get a
-     * {@link android.app.ForegroundServiceTypeNotAllowedException}.</p>
+     * {@link android.app.InvalidForegroundServiceTypeException}.</p>
      *
      * @deprecated Use {@link android.app.job.JobInfo.Builder} data transfer APIs instead.
      */
@@ -308,7 +308,9 @@
      * permissions:
      * {@link android.Manifest.permission#ACTIVITY_RECOGNITION},
      * {@link android.Manifest.permission#BODY_SENSORS},
-     * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS}.
+     * {@link android.Manifest.permission#HIGH_SAMPLING_RATE_SENSORS},
+     * or one of the {@code "android.permission.health.*"} permissions defined in the
+     * {@link android.healthconnect.HealthPermissions}.
      */
     @RequiresPermission(
             allOf = {
@@ -329,8 +331,7 @@
      * Messaging use cases which host local server to relay messages across devices.
      */
     @RequiresPermission(
-            value = Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING,
-            conditional = true
+            value = Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING
     )
     public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 1 << 9;
 
@@ -358,34 +359,68 @@
      * </p>
      */
     @RequiresPermission(
-            value = Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED,
-            conditional = true
+            value = Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED
     )
     public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1 << 10;
 
     /**
-     * Foreground service type corresponding to {@code shortService} in
-     * the {@link android.R.attr#foregroundServiceType} attribute.
+     * A foreground service type for "short-lived" services, which corresponds to
+     * {@code shortService} in the {@link android.R.attr#foregroundServiceType} attribute in the
+     * manifest.
      *
-     * TODO Implement it
+     * <p>Unlike other foreground service types, this type is not associated with a specific use
+     * case, and it will not require any special permissions
+     * (besides {@link Manifest.permission#FOREGROUND_SERVICE}).
      *
-     * TODO Expand the javadoc
+     * However, this type has the following restrictions.
      *
-     * This type is not associated with specific use cases unlike other types, but this has
-     * unique restrictions.
      * <ul>
-     *     <li>Has a timeout
-     *     <li>Cannot start other foreground services from this
      *     <li>
+     *         The type has a 1 minute timeout.
+     *         A foreground service of this type must be stopped within the timeout by
+     *         {@link android.app.Service#stopSelf),
+     *         or {@link android.content.Context#stopService).
+     *         {@link android.app.Service#stopForeground) will also work, which will demote the
+     *         service to a "background" service, which will soon be stopped by the system.
+     *
+     *         <p>The system will <em>not</em> automatically stop it.
+     *
+     *         <p>If the service isn't stopped within the timeout,
+     *         {@link android.app.Service#onTimeout(int)} will be called.
+     *         If the service is still not stopped after the callback,
+     *         the app will be declared an ANR.
+     *
+     *     <li>
+     *         A foreground service of this type cannot be made "sticky"
+     *         (see {@link android.app.Service#START_STICKY}). That is, if an app is killed
+     *         due to a crash or out-of memory while it's running a short foregorund-service,
+     *         the system will not restart the service.
+     *     <li>
+     *         Other foreground services cannot be started from short foreground services.
+     *         Unlike other foreground service types, when an app is running in the background
+     *         while only having a "short" foreground service, it's not allowed to start
+     *         other foreground services, due to the restriction describe here:
+     *         <a href="/guide/components/foreground-services#background-start-restrictions>
+     *             Restrictions on background starts
+     *         </a>
      * </ul>
      *
-     * @see Service#onTimeout
-     *
-     * @hide
+     * @see android.app.Service#onTimeout(int)
      */
     public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 1 << 11;
 
     /**
+     * Constant corresponding to {@code fileManagement} in
+     * the {@link android.R.attr#foregroundServiceType} attribute.
+     * The file management use case which manages files/directories, often involving file I/O
+     * across the file system.
+     */
+    @RequiresPermission(
+            value = Manifest.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT
+    )
+    public static final int FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT = 1 << 12;
+
+    /**
      * Constant corresponding to {@code specialUse} in
      * the {@link android.R.attr#foregroundServiceType} attribute.
      * Use cases that can't be categorized into any other foreground service types, but also
@@ -424,15 +459,14 @@
      *      android:name=".MySpecialForegroundService"
      *      android:foregroundServiceType="specialUse|foo"&gt;
      *      &lt;property
-     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE""
+     *          android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
      *          android:value="foo"
      *      /&gt;
      * &lt;/service&gt;
      * </pre>
      */
     @RequiresPermission(
-            value = Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE,
-            conditional = true
+            value = Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE
     )
     public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1 << 30;
 
@@ -469,7 +503,8 @@
             FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING,
             FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED,
             FOREGROUND_SERVICE_TYPE_SHORT_SERVICE,
-            FOREGROUND_SERVICE_TYPE_SPECIAL_USE
+            FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT,
+            FOREGROUND_SERVICE_TYPE_SPECIAL_USE,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ForegroundServiceType {}
@@ -553,6 +588,8 @@
                 return "systemExempted";
             case FOREGROUND_SERVICE_TYPE_SHORT_SERVICE:
                 return "shortService";
+            case FOREGROUND_SERVICE_TYPE_FILE_MANAGEMENT:
+                return "fileManagement";
             case FOREGROUND_SERVICE_TYPE_SPECIAL_USE:
                 return "specialUse";
             default:
diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING
index 1c1f58a..45e0efb 100644
--- a/core/java/android/content/pm/TEST_MAPPING
+++ b/core/java/android/content/pm/TEST_MAPPING
@@ -43,6 +43,36 @@
       "name": "ApkVerityTest"
     },
     {
+      "name": "CtsAppFgsTestCases",
+      "file_patterns": ["(/|^)ServiceInfo[^/]*"],
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsShortFgsTestCases",
+      "file_patterns": ["(/|^)ServiceInfo[^/]*"],
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
       "name": "CtsIncrementalInstallHostTestCases",
       "options": [
         {
diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java
index 7a5ac8e..143c00d 100644
--- a/core/java/android/content/res/ApkAssets.java
+++ b/core/java/android/content/res/ApkAssets.java
@@ -26,6 +26,8 @@
 
 import com.android.internal.annotations.GuardedBy;
 
+import dalvik.annotation.optimization.CriticalNative;
+
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -459,7 +461,7 @@
     private static native @NonNull String nativeGetAssetPath(long ptr);
     private static native @NonNull String nativeGetDebugName(long ptr);
     private static native long nativeGetStringBlock(long ptr);
-    private static native boolean nativeIsUpToDate(long ptr);
+    @CriticalNative private static native boolean nativeIsUpToDate(long ptr);
     private static native long nativeOpenXml(long ptr, @NonNull String fileName) throws IOException;
     private static native @Nullable OverlayableInfo nativeGetOverlayableInfo(long ptr,
             String overlayableName) throws IOException;
diff --git a/core/java/android/content/res/CompatibilityInfo.java b/core/java/android/content/res/CompatibilityInfo.java
index 6ce2242..ce6e1c7 100644
--- a/core/java/android/content/res/CompatibilityInfo.java
+++ b/core/java/android/content/res/CompatibilityInfo.java
@@ -563,6 +563,9 @@
         if (applyToSize) {
             inoutDm.widthPixels = (int) (inoutDm.widthPixels * invertedRatio + 0.5f);
             inoutDm.heightPixels = (int) (inoutDm.heightPixels * invertedRatio + 0.5f);
+
+            float fontScale = inoutDm.scaledDensity / inoutDm.density;
+            inoutDm.fontScaleConverter = FontScaleConverterFactory.forScale(fontScale);
         }
     }
 
diff --git a/core/java/android/content/res/FontScaleConverter.java b/core/java/android/content/res/FontScaleConverter.java
new file mode 100644
index 0000000..457225d
--- /dev/null
+++ b/core/java/android/content/res/FontScaleConverter.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.res;
+
+import android.annotation.NonNull;
+import android.util.MathUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * A lookup table for non-linear font scaling. Converts font sizes given in "sp" dimensions to a
+ * "dp" dimension according to a non-linear curve.
+ *
+ * <p>This is meant to improve readability at larger font scales: larger fonts will scale up more
+ * slowly than smaller fonts, so we don't get ridiculously huge fonts that don't fit on the screen.
+ *
+ * <p>The thinking here is that large fonts are already big enough to read, but we still want to
+ * scale them slightly to preserve the visual hierarchy when compared to smaller fonts.
+ *
+ * @hide
+ */
+public class FontScaleConverter {
+
+    @VisibleForTesting
+    final float[] mFromSpValues;
+    @VisibleForTesting
+    final float[] mToDpValues;
+
+    /**
+     * Creates a lookup table for the given conversions.
+     *
+     * <p>Any "sp" value not in the lookup table will be derived via linear interpolation.
+     *
+     * <p>The arrays must be sorted ascending and monotonically increasing.
+     *
+     * @param fromSp array of dimensions in SP
+     * @param toDp array of dimensions in DP that correspond to an SP value in fromSp
+     *
+     * @throws IllegalArgumentException if the array lengths don't match or are empty
+     * @hide
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    public FontScaleConverter(@NonNull float[] fromSp, @NonNull float[] toDp) {
+        if (fromSp.length != toDp.length || fromSp.length == 0) {
+            throw new IllegalArgumentException("Array lengths must match and be nonzero");
+        }
+
+        mFromSpValues = fromSp;
+        mToDpValues = toDp;
+    }
+
+    /**
+     * Convert a dimension in "sp" to "dp" using the lookup table.
+     *
+     * @hide
+     */
+    public float convertSpToDp(float sp) {
+        final float spPositive = Math.abs(sp);
+        // TODO(b/247861374): find a match at a higher index?
+        final float sign = Math.signum(sp);
+        // We search for exact matches only, even if it's just a little off. The interpolation will
+        // handle any non-exact matches.
+        final int index = Arrays.binarySearch(mFromSpValues, spPositive);
+        if (index >= 0) {
+            // exact match, return the matching dp
+            return sign * mToDpValues[index];
+        } else {
+            // must be a value in between index and index + 1: interpolate.
+            final int lowerIndex = -(index + 1) - 1;
+
+            final float startSp;
+            final float endSp;
+            final float startDp;
+            final float endDp;
+
+            if (lowerIndex >= mFromSpValues.length - 1) {
+                // It's past our lookup table. Determine the last elements' scaling factor and use.
+                startSp = mFromSpValues[mFromSpValues.length - 1];
+                startDp = mToDpValues[mFromSpValues.length - 1];
+
+                if (startSp == 0) return 0;
+
+                final float scalingFactor = startDp / startSp;
+                return sp * scalingFactor;
+            } else if (lowerIndex == -1) {
+                // It's smaller than the smallest value in our table. Interpolate from 0.
+                startSp = 0;
+                startDp = 0;
+                endSp = mFromSpValues[0];
+                endDp = mToDpValues[0];
+            } else {
+                startSp = mFromSpValues[lowerIndex];
+                endSp = mFromSpValues[lowerIndex + 1];
+                startDp = mToDpValues[lowerIndex];
+                endDp = mToDpValues[lowerIndex + 1];
+            }
+
+            return sign * MathUtils.constrainedMap(startDp, endDp, startSp, endSp, spPositive);
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null) return false;
+        if (!(o instanceof FontScaleConverter)) return false;
+        FontScaleConverter that = (FontScaleConverter) o;
+        return Arrays.equals(mFromSpValues, that.mFromSpValues)
+                && Arrays.equals(mToDpValues, that.mToDpValues);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Arrays.hashCode(mFromSpValues);
+        result = 31 * result + Arrays.hashCode(mToDpValues);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "FontScaleConverter{"
+                + "fromSpValues="
+                + Arrays.toString(mFromSpValues)
+                + ", toDpValues="
+                + Arrays.toString(mToDpValues)
+                + '}';
+    }
+}
diff --git a/core/java/android/content/res/FontScaleConverterFactory.java b/core/java/android/content/res/FontScaleConverterFactory.java
new file mode 100644
index 0000000..c77a372
--- /dev/null
+++ b/core/java/android/content/res/FontScaleConverterFactory.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.res;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * Stores lookup tables for creating {@link FontScaleConverter}s at various scales.
+ *
+ * @hide
+ */
+public class FontScaleConverterFactory {
+    private static final float SCALE_KEY_MULTIPLIER = 100f;
+
+    @VisibleForTesting
+    static final SparseArray<FontScaleConverter> LOOKUP_TABLES = new SparseArray<>();
+
+    static {
+        // These were generated by frameworks/base/tools/fonts/font-scaling-array-generator.js and
+        // manually tweaked for optimum readability.
+        put(
+                /* scaleKey= */ 1.15f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                        /* toDp=   */
+                        new float[] { 9.2f, 11.5f, 13.8f, 16.1f, 20.7f,   23f, 27.6f, 34.5f,  115})
+        );
+
+        put(
+                /* scaleKey= */ 1.3f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                        /* toDp=   */
+                        new float[] {10.4f,   13f, 15.6f, 18.2f, 23.4f,   26f, 31.2f,   39f,  130})
+        );
+
+        put(
+                /* scaleKey= */ 1.5f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                        /* toDp=   */
+                        new float[] {  12f,   15f,   18f,   21f,   27f,   30f,   36f,   45f,  150})
+        );
+
+        put(
+                /* scaleKey= */ 1.8f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                        /* toDp=   */
+                        new float[] {14.4f,   18f, 21.6f, 25.2f, 32.4f,   36f, 43.2f,   54f,  180})
+        );
+
+        put(
+                /* scaleKey= */ 2f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {   8f,   10f,   12f,   14f,   18f,   20f,   24f,   30f,  100},
+                        /* toDp=   */
+                        new float[] {  16f,   20f,   24f,   28f,   36f,   40f,   48f,   60f,  200})
+        );
+
+    }
+
+    private FontScaleConverterFactory() {}
+
+    /**
+     * Finds a matching FontScaleConverter for the given fontScale factor.
+     *
+     * @param fontScale the scale factor, usually from {@link Configuration#fontScale}.
+     *
+     * @return a converter for the given scale, or null if non-linear scaling should not be used.
+     *
+     * @hide
+     */
+    @Nullable
+    public static FontScaleConverter forScale(float fontScale) {
+        if (fontScale <= 1) {
+            // We don't need non-linear curves for shrinking text or for 100%.
+            // Also, fontScale==0 should not have a curve either
+            return null;
+        }
+
+        FontScaleConverter lookupTable = get(fontScale);
+        // TODO(b/247861716): interpolate between two tables when null
+
+        return lookupTable;
+    }
+
+    private static void put(float scaleKey, @NonNull FontScaleConverter fontScaleConverter) {
+        LOOKUP_TABLES.put((int) (scaleKey * SCALE_KEY_MULTIPLIER), fontScaleConverter);
+    }
+
+    @Nullable
+    private static FontScaleConverter get(float scaleKey) {
+        return LOOKUP_TABLES.get((int) (scaleKey * SCALE_KEY_MULTIPLIER));
+    }
+}
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 09d24d4..c2b3769 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -434,6 +434,8 @@
                 // Protect against an unset fontScale.
                 mMetrics.scaledDensity = mMetrics.density *
                         (mConfiguration.fontScale != 0 ? mConfiguration.fontScale : 1.0f);
+                mMetrics.fontScaleConverter =
+                        FontScaleConverterFactory.forScale(mConfiguration.fontScale);
 
                 final int width, height;
                 if (mMetrics.widthPixels >= mMetrics.heightPixels) {
diff --git a/core/java/android/content/res/loader/ResourcesProvider.java b/core/java/android/content/res/loader/ResourcesProvider.java
index 463dcac..a5a1fa689 100644
--- a/core/java/android/content/res/loader/ResourcesProvider.java
+++ b/core/java/android/content/res/loader/ResourcesProvider.java
@@ -18,7 +18,10 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.content.Context;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManager;
 import android.content.pm.ApplicationInfo;
 import android.content.res.ApkAssets;
 import android.content.res.AssetFileDescriptor;
@@ -27,11 +30,17 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.content.om.OverlayManagerImpl;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
 
 import java.io.Closeable;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Objects;
 
 /**
  * Provides methods to load resources data from APKs ({@code .apk}) and resources tables
@@ -63,6 +72,48 @@
     }
 
     /**
+     * Creates a ResourcesProvider instance from the specified overlay information.
+     *
+     * <p>In order to enable the registered overlays, an application can create a {@link
+     * ResourcesProvider} instance according to the specified {@link OverlayInfo} instance and put
+     * them into a {@link ResourcesLoader} instance. The application calls {@link
+     * android.content.res.Resources#addLoaders(ResourcesLoader...)} to load the overlays.
+     *
+     * @param overlayInfo is the information about the specified overlay
+     * @return the resources provider instance for the {@code overlayInfo}
+     * @throws IOException when the files can't be loaded.
+     * @see OverlayManager#getOverlayInfosForTarget(String) to get the list of overlay info.
+     * @hide
+     */
+    @SuppressLint("WrongConstant") // TODO(b/238713267): ApkAssets blocks PROPERTY_LOADER
+    @NonNull
+    public static ResourcesProvider loadOverlay(@NonNull OverlayInfo overlayInfo)
+            throws IOException {
+        Objects.requireNonNull(overlayInfo);
+        Preconditions.checkArgument(overlayInfo.isFabricated(), "Not accepted overlay");
+        Preconditions.checkStringNotEmpty(
+                overlayInfo.getTargetOverlayableName(), "Without overlayable name");
+        final String overlayName =
+                OverlayManagerImpl.checkOverlayNameValid(overlayInfo.getOverlayName());
+        final String path =
+                Preconditions.checkStringNotEmpty(
+                        overlayInfo.getBaseCodePath(), "Invalid base path");
+
+        final Path frroPath = Path.of(path);
+        if (!Files.isRegularFile(frroPath)) {
+            throw new FileNotFoundException("The frro file not found");
+        }
+        final Path idmapPath = frroPath.getParent().resolve(overlayName + ".idmap");
+        if (!Files.isRegularFile(idmapPath)) {
+            throw new FileNotFoundException("The idmap file not found");
+        }
+
+        return new ResourcesProvider(
+                ApkAssets.loadOverlayFromPath(
+                        idmapPath.toString(), 0 /* flags: self targeting overlay */));
+    }
+
+    /**
      * Creates a ResourcesProvider from an APK ({@code .apk}) file descriptor.
      *
      * <p>The file descriptor is duplicated and the original may be closed by the application at any
diff --git a/core/java/android/credentials/ClearCredentialStateRequest.aidl b/core/java/android/credentials/ClearCredentialStateRequest.aidl
new file mode 100644
index 0000000..2679ee4
--- /dev/null
+++ b/core/java/android/credentials/ClearCredentialStateRequest.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+parcelable ClearCredentialStateRequest;
\ No newline at end of file
diff --git a/core/java/android/credentials/ClearCredentialStateRequest.java b/core/java/android/credentials/ClearCredentialStateRequest.java
new file mode 100644
index 0000000..33afbed
--- /dev/null
+++ b/core/java/android/credentials/ClearCredentialStateRequest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import static java.util.Objects.requireNonNull;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.AnnotationValidations;
+
+/**
+ * A request class for clearing a user's credential state from the credential providers.
+ */
+public final class ClearCredentialStateRequest implements Parcelable {
+
+    /** The request data. */
+    @NonNull
+    private final Bundle mData;
+
+    /** Returns the request data. */
+    @NonNull
+    public Bundle getData() {
+        return mData;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeBundle(mData);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public String toString() {
+        return "ClearCredentialStateRequest {data=" + mData + "}";
+    }
+
+    /**
+     * Constructs a {@link ClearCredentialStateRequest}.
+     *
+     * @param data the request data
+     */
+    public ClearCredentialStateRequest(@NonNull Bundle data) {
+        mData = requireNonNull(data, "data must not be null");
+    }
+
+    private ClearCredentialStateRequest(@NonNull Parcel in) {
+        Bundle data = in.readBundle();
+        mData = data;
+        AnnotationValidations.validate(NonNull.class, null, mData);
+    }
+
+    public static final @NonNull Creator<ClearCredentialStateRequest> CREATOR =
+            new Creator<ClearCredentialStateRequest>() {
+        @Override
+        public ClearCredentialStateRequest[] newArray(int size) {
+            return new ClearCredentialStateRequest[size];
+        }
+
+        @Override
+        public ClearCredentialStateRequest createFromParcel(@NonNull Parcel in) {
+            return new ClearCredentialStateRequest(in);
+        }
+    };
+}
diff --git a/core/java/android/credentials/CreateCredentialRequest.java b/core/java/android/credentials/CreateCredentialRequest.java
index 22ef230..4589039 100644
--- a/core/java/android/credentials/CreateCredentialRequest.java
+++ b/core/java/android/credentials/CreateCredentialRequest.java
@@ -39,10 +39,17 @@
     private final String mType;
 
     /**
-     * The request data.
+     * The full credential creation request data.
      */
     @NonNull
-    private final Bundle mData;
+    private final Bundle mCredentialData;
+
+    /**
+     * The partial request data that will be sent to the provider during the initial creation
+     * candidate query stage.
+     */
+    @NonNull
+    private final Bundle mCandidateQueryData;
 
     /**
      * Determines whether or not the request must only be fulfilled by a system provider.
@@ -58,18 +65,39 @@
     }
 
     /**
-     * Returns the request data.
+     * Returns the full credential creation request data.
+     *
+     * For security reason, a provider will receive the request data in two stages. First it gets
+     * a partial request, {@link #getCandidateQueryData()} that do not contain sensitive user
+     * information; it uses this information to provide credential creation candidates that the
+     * [@code CredentialManager] will show to the user. Next, this full request data will be sent to
+     * a provider only if the user further grants the consent by choosing a candidate from the
+     * provider.
      */
     @NonNull
-    public Bundle getData() {
-        return mData;
+    public Bundle getCredentialData() {
+        return mCredentialData;
+    }
+
+    /**
+     * Returns the partial request data that will be sent to the provider during the initial
+     * creation candidate query stage.
+     *
+     * For security reason, a provider will receive the request data in two stages. First it gets
+     * this partial request that do not contain sensitive user information; it uses this information
+     * to provide credential creation candidates that the [@code CredentialManager] will show to
+     * the user. Next, the full request data, {@link #getCredentialData()}, will be sent to a
+     * provider only if the user further grants the consent by choosing a candidate from the
+     * provider.
+     */
+    @NonNull
+    public Bundle getCandidateQueryData() {
+        return mCandidateQueryData;
     }
 
     /**
      * Returns true if the request must only be fulfilled by a system provider, and false
      * otherwise.
-     *
-     * @hide
      */
     public boolean requireSystemProvider() {
         return mRequireSystemProvider;
@@ -78,7 +106,8 @@
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeString8(mType);
-        dest.writeBundle(mData);
+        dest.writeBundle(mCredentialData);
+        dest.writeBundle(mCandidateQueryData);
         dest.writeBoolean(mRequireSystemProvider);
     }
 
@@ -91,7 +120,8 @@
     public String toString() {
         return "CreateCredentialRequest {"
                 + "type=" + mType
-                + ", data=" + mData
+                + ", credentialData=" + mCredentialData
+                + ", candidateQueryData=" + mCandidateQueryData
                 + ", requireSystemProvider=" + mRequireSystemProvider
                 + "}";
     }
@@ -100,44 +130,37 @@
      * Constructs a {@link CreateCredentialRequest}.
      *
      * @param type the requested credential type
-     * @param data the request data
-     *
-     * @throws IllegalArgumentException If type is empty
-     */
-    public CreateCredentialRequest(@NonNull String type, @NonNull Bundle data) {
-        this(type, data, /*requireSystemProvider=*/ false);
-    }
-
-    /**
-     * Constructs a {@link CreateCredentialRequest}.
-     *
-     * @param type the requested credential type
-     * @param data the request data
-     * @param requireSystemProvider whether or not the request must only be fulfilled by a system
-     *                              provider
+     * @param credentialData the full credential creation request data
+     * @param candidateQueryData the partial request data that will be sent to the provider
+     *                           during the initial creation candidate query stage
+     * @param requireSystemProvider whether the request must only be fulfilled by a system provider
      *
      * @throws IllegalArgumentException If type is empty.
-     *
-     * @hide
      */
     public CreateCredentialRequest(
             @NonNull String type,
-            @NonNull Bundle data,
+            @NonNull Bundle credentialData,
+            @NonNull Bundle candidateQueryData,
             boolean requireSystemProvider) {
         mType = Preconditions.checkStringNotEmpty(type, "type must not be empty");
-        mData = requireNonNull(data, "data must not be null");
+        mCredentialData = requireNonNull(credentialData, "credentialData must not be null");
+        mCandidateQueryData = requireNonNull(candidateQueryData,
+                "candidateQueryData must not be null");
         mRequireSystemProvider = requireSystemProvider;
     }
 
     private CreateCredentialRequest(@NonNull Parcel in) {
         String type = in.readString8();
-        Bundle data = in.readBundle();
+        Bundle credentialData = in.readBundle();
+        Bundle candidateQueryData = in.readBundle();
         boolean requireSystemProvider = in.readBoolean();
 
         mType = type;
         AnnotationValidations.validate(NonNull.class, null, mType);
-        mData = data;
-        AnnotationValidations.validate(NonNull.class, null, mData);
+        mCredentialData = credentialData;
+        AnnotationValidations.validate(NonNull.class, null, mCredentialData);
+        mCandidateQueryData = candidateQueryData;
+        AnnotationValidations.validate(NonNull.class, null, mCandidateQueryData);
         mRequireSystemProvider = requireSystemProvider;
     }
 
diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java
index 04d57ad..1efac6c 100644
--- a/core/java/android/credentials/CredentialManager.java
+++ b/core/java/android/credentials/CredentialManager.java
@@ -22,6 +22,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemService;
+import android.app.Activity;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.IntentSender;
@@ -65,17 +66,20 @@
      * credential, display a picker when multiple credentials exist, etc.
      *
      * @param request the request specifying type(s) of credentials to get from the user
+     * @param activity the activity used to launch any UI needed
      * @param cancellationSignal an optional signal that allows for cancelling this call
      * @param executor the callback will take place on this {@link Executor}
      * @param callback the callback invoked when the request succeeds or fails
      */
     public void executeGetCredential(
             @NonNull GetCredentialRequest request,
+            @NonNull Activity activity,
             @Nullable CancellationSignal cancellationSignal,
             @CallbackExecutor @NonNull Executor executor,
             @NonNull OutcomeReceiver<
                     GetCredentialResponse, CredentialManagerException> callback) {
         requireNonNull(request, "request must not be null");
+        requireNonNull(activity, "activity must not be null");
         requireNonNull(executor, "executor must not be null");
         requireNonNull(callback, "callback must not be null");
 
@@ -88,8 +92,7 @@
         try {
             cancelRemote = mService.executeGetCredential(
                     request,
-                    // TODO: use a real activity instead of context.
-                    new GetCredentialTransport(mContext, executor, callback),
+                    new GetCredentialTransport(activity, executor, callback),
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
@@ -107,17 +110,20 @@
      * or storing the new credential, etc.
      *
      * @param request the request specifying type(s) of credentials to get from the user
+     * @param activity the activity used to launch any UI needed
      * @param cancellationSignal an optional signal that allows for cancelling this call
      * @param executor the callback will take place on this {@link Executor}
      * @param callback the callback invoked when the request succeeds or fails
      */
     public void executeCreateCredential(
             @NonNull CreateCredentialRequest request,
+            @NonNull Activity activity,
             @Nullable CancellationSignal cancellationSignal,
             @CallbackExecutor @NonNull Executor executor,
             @NonNull OutcomeReceiver<
                     CreateCredentialResponse, CredentialManagerException> callback) {
         requireNonNull(request, "request must not be null");
+        requireNonNull(activity, "activity must not be null");
         requireNonNull(executor, "executor must not be null");
         requireNonNull(callback, "callback must not be null");
 
@@ -129,8 +135,7 @@
         ICancellationSignal cancelRemote = null;
         try {
             cancelRemote = mService.executeCreateCredential(request,
-                    // TODO: use a real activity instead of context.
-                    new CreateCredentialTransport(mContext, executor, callback),
+                    new CreateCredentialTransport(activity, executor, callback),
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
@@ -142,18 +147,24 @@
     }
 
     /**
-     * Clears the current user credential session from all credential providers.
+     * Clears the current user credential state from all credential providers.
      *
-     * <p>Usually invoked after your user signs out of your app so that they will not be
-     * automatically signed in the next time.
+     * You should invoked this api after your user signs out of your app to notify all credential
+     * providers that any stored credential session for the given app should be cleared.
      *
+     * A credential provider may have stored an active credential session and use it to limit
+     * sign-in options for future get-credential calls. For example, it may prioritize the active
+     * credential over any other available credential. When your user explicitly signs out of your
+     * app and in order to get the holistic sign-in options the next time, you should call this API
+     * to let the provider clear any stored credential session.
+     *
+     * @param request the request data
      * @param cancellationSignal an optional signal that allows for cancelling this call
      * @param executor the callback will take place on this {@link Executor}
      * @param callback the callback invoked when the request succeeds or fails
-     *
-     * @hide
      */
-    public void clearCredentialSession(
+    public void clearCredentialState(
+            @NonNull ClearCredentialStateRequest request,
             @Nullable CancellationSignal cancellationSignal,
             @CallbackExecutor @NonNull Executor executor,
             @NonNull OutcomeReceiver<Void, CredentialManagerException> callback) {
@@ -167,8 +178,8 @@
 
         ICancellationSignal cancelRemote = null;
         try {
-            cancelRemote = mService.clearCredentialSession(
-                    new ClearCredentialSessionTransport(executor, callback),
+            cancelRemote = mService.clearCredentialState(request,
+                    new ClearCredentialStateTransport(executor, callback),
                     mContext.getOpPackageName());
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
@@ -182,14 +193,14 @@
     private static class GetCredentialTransport extends IGetCredentialCallback.Stub {
         // TODO: listen for cancellation to release callback.
 
-        private final Context mActivityContext;
+        private final Activity mActivity;
         private final Executor mExecutor;
         private final OutcomeReceiver<
                 GetCredentialResponse, CredentialManagerException> mCallback;
 
-        private GetCredentialTransport(Context activityContext, Executor executor,
+        private GetCredentialTransport(Activity activity, Executor executor,
                 OutcomeReceiver<GetCredentialResponse, CredentialManagerException> callback) {
-            mActivityContext = activityContext;
+            mActivity = activity;
             mExecutor = executor;
             mCallback = callback;
         }
@@ -197,7 +208,7 @@
         @Override
         public void onPendingIntent(PendingIntent pendingIntent) {
             try {
-                mActivityContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
+                mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
             } catch (IntentSender.SendIntentException e) {
                 Log.e(TAG, "startIntentSender() failed for intent:"
                         + pendingIntent.getIntentSender(), e);
@@ -220,14 +231,14 @@
     private static class CreateCredentialTransport extends ICreateCredentialCallback.Stub {
         // TODO: listen for cancellation to release callback.
 
-        private final Context mActivityContext;
+        private final Activity mActivity;
         private final Executor mExecutor;
         private final OutcomeReceiver<
                 CreateCredentialResponse, CredentialManagerException> mCallback;
 
-        private CreateCredentialTransport(Context activityContext, Executor executor,
+        private CreateCredentialTransport(Activity activity, Executor executor,
                 OutcomeReceiver<CreateCredentialResponse, CredentialManagerException> callback) {
-            mActivityContext = activityContext;
+            mActivity = activity;
             mExecutor = executor;
             mCallback = callback;
         }
@@ -235,7 +246,7 @@
         @Override
         public void onPendingIntent(PendingIntent pendingIntent) {
             try {
-                mActivityContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
+                mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0);
             } catch (IntentSender.SendIntentException e) {
                 Log.e(TAG, "startIntentSender() failed for intent:"
                         + pendingIntent.getIntentSender(), e);
@@ -255,14 +266,14 @@
         }
     }
 
-    private static class ClearCredentialSessionTransport
-            extends IClearCredentialSessionCallback.Stub {
+    private static class ClearCredentialStateTransport
+            extends IClearCredentialStateCallback.Stub {
         // TODO: listen for cancellation to release callback.
 
         private final Executor mExecutor;
         private final OutcomeReceiver<Void, CredentialManagerException> mCallback;
 
-        private ClearCredentialSessionTransport(Executor executor,
+        private ClearCredentialStateTransport(Executor executor,
                 OutcomeReceiver<Void, CredentialManagerException> callback) {
             mExecutor = executor;
             mCallback = callback;
diff --git a/core/java/android/credentials/GetCredentialOption.java b/core/java/android/credentials/GetCredentialOption.java
index a0d3c0b..ed93dae 100644
--- a/core/java/android/credentials/GetCredentialOption.java
+++ b/core/java/android/credentials/GetCredentialOption.java
@@ -67,8 +67,6 @@
     /**
      * Returns true if the request must only be fulfilled by a system provider, and false
      * otherwise.
-     *
-     * @hide
      */
     public boolean requireSystemProvider() {
         return mRequireSystemProvider;
@@ -100,24 +98,10 @@
      *
      * @param type the requested credential type
      * @param data the request data
-     *
-     * @throws IllegalArgumentException If type is empty
-     */
-    public GetCredentialOption(@NonNull String type, @NonNull Bundle data) {
-        this(type, data, /*requireSystemProvider=*/ false);
-    }
-
-    /**
-     * Constructs a {@link GetCredentialOption}.
-     *
-     * @param type the requested credential type
-     * @param data the request data
      * @param requireSystemProvider whether or not the request must only be fulfilled by a system
      *                              provider
      *
      * @throws IllegalArgumentException If type is empty.
-     *
-     * @hide
      */
     public GetCredentialOption(
             @NonNull String type,
diff --git a/core/java/android/credentials/IClearCredentialSessionCallback.aidl b/core/java/android/credentials/IClearCredentialSessionCallback.aidl
deleted file mode 100644
index 903e7f5..0000000
--- a/core/java/android/credentials/IClearCredentialSessionCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.credentials;
-
-/**
- * Listener for clearCredentialSession request.
- *
- * @hide
- */
-interface IClearCredentialSessionCallback {
-    oneway void onSuccess();
-    oneway void onError(int errorCode, String message);
-}
\ No newline at end of file
diff --git a/core/java/android/credentials/IClearCredentialStateCallback.aidl b/core/java/android/credentials/IClearCredentialStateCallback.aidl
new file mode 100644
index 0000000..f8b7ae44
--- /dev/null
+++ b/core/java/android/credentials/IClearCredentialStateCallback.aidl
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+/**
+ * Listener for clearCredentialState request.
+ *
+ * @hide
+ */
+interface IClearCredentialStateCallback {
+    oneway void onSuccess();
+    oneway void onError(int errorCode, String message);
+}
\ No newline at end of file
diff --git a/core/java/android/credentials/ICredentialManager.aidl b/core/java/android/credentials/ICredentialManager.aidl
index 35688d7..c5497bd 100644
--- a/core/java/android/credentials/ICredentialManager.aidl
+++ b/core/java/android/credentials/ICredentialManager.aidl
@@ -16,9 +16,10 @@
 
 package android.credentials;
 
+import android.credentials.ClearCredentialStateRequest;
 import android.credentials.CreateCredentialRequest;
 import android.credentials.GetCredentialRequest;
-import android.credentials.IClearCredentialSessionCallback;
+import android.credentials.IClearCredentialStateCallback;
 import android.credentials.ICreateCredentialCallback;
 import android.credentials.IGetCredentialCallback;
 import android.os.ICancellationSignal;
@@ -34,5 +35,5 @@
 
     @nullable ICancellationSignal executeCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback, String callingPackage);
 
-    @nullable ICancellationSignal clearCredentialSession(in IClearCredentialSessionCallback callback, String callingPackage);
+    @nullable ICancellationSignal clearCredentialState(in ClearCredentialStateRequest request, in IClearCredentialStateCallback callback, String callingPackage);
 }
diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java
index 1c4898a..18118f5 100644
--- a/core/java/android/hardware/SystemSensorManager.java
+++ b/core/java/android/hardware/SystemSensorManager.java
@@ -16,8 +16,14 @@
 
 package android.hardware;
 
+import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED;
+import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID;
+import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
+import android.companion.virtual.VirtualDeviceManager;
 import android.compat.Compatibility;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledAfter;
@@ -45,6 +51,7 @@
 import java.io.UncheckedIOException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -80,6 +87,8 @@
     private static native boolean nativeGetSensorAtIndex(long nativeInstance,
             Sensor sensor, int index);
     private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
+    private static native void nativeGetRuntimeSensors(
+            long nativeInstance, int deviceId, List<Sensor> list);
     private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
 
     private static native int nativeCreateDirectChannel(
@@ -100,6 +109,10 @@
 
     private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();
     private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
+    private final SparseArray<List<Sensor>> mFullRuntimeSensorListByDevice = new SparseArray<>();
+    private final SparseArray<SparseArray<List<Sensor>>> mRuntimeSensorListByDeviceByType =
+            new SparseArray<>();
+
     private boolean mDynamicSensorListDirty = true;
 
     private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
@@ -114,6 +127,7 @@
     private HashMap<DynamicSensorCallback, Handler>
             mDynamicSensorCallbacks = new HashMap<>();
     private BroadcastReceiver mDynamicSensorBroadcastReceiver;
+    private BroadcastReceiver mRuntimeSensorBroadcastReceiver;
 
     // Looper associated with the context in which this instance was created.
     private final Looper mMainLooper;
@@ -121,6 +135,7 @@
     private final boolean mIsPackageDebuggable;
     private final Context mContext;
     private final long mNativeInstance;
+    private final VirtualDeviceManager mVdm;
 
     private Optional<Boolean> mHasHighSamplingRateSensorsPermission = Optional.empty();
 
@@ -139,6 +154,7 @@
         mContext = context;
         mNativeInstance = nativeCreate(context.getOpPackageName());
         mIsPackageDebuggable = (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
+        mVdm = mContext.getSystemService(VirtualDeviceManager.class);
 
         // initialize the sensor list
         for (int index = 0;; ++index) {
@@ -147,12 +163,63 @@
             mFullSensorsList.add(sensor);
             mHandleToSensor.put(sensor.getHandle(), sensor);
         }
+
+    }
+
+    /** @hide */
+    @Override
+    public List<Sensor> getSensorList(int type) {
+        final int deviceId = mContext.getDeviceId();
+        if (deviceId == DEFAULT_DEVICE_ID || mVdm == null
+                || mVdm.getDevicePolicy(deviceId, POLICY_TYPE_SENSORS) == DEVICE_POLICY_DEFAULT) {
+            return super.getSensorList(type);
+        }
+
+        // Cache the per-device lists on demand.
+        List<Sensor> list;
+        synchronized (mFullRuntimeSensorListByDevice) {
+            List<Sensor> fullList = mFullRuntimeSensorListByDevice.get(deviceId);
+            if (fullList == null) {
+                fullList = createRuntimeSensorListLocked(deviceId);
+            }
+            SparseArray<List<Sensor>> deviceSensorListByType =
+                    mRuntimeSensorListByDeviceByType.get(deviceId);
+            list = deviceSensorListByType.get(type);
+            if (list == null) {
+                if (type == Sensor.TYPE_ALL) {
+                    list = fullList;
+                } else {
+                    list = new ArrayList<>();
+                    for (Sensor i : fullList) {
+                        if (i.getType() == type) {
+                            list.add(i);
+                        }
+                    }
+                }
+                list = Collections.unmodifiableList(list);
+                deviceSensorListByType.append(type, list);
+            }
+        }
+        return list;
     }
 
     /** @hide */
     @Override
     protected List<Sensor> getFullSensorList() {
-        return mFullSensorsList;
+        final int deviceId = mContext.getDeviceId();
+        if (deviceId == DEFAULT_DEVICE_ID || mVdm == null
+                || mVdm.getDevicePolicy(deviceId, POLICY_TYPE_SENSORS) == DEVICE_POLICY_DEFAULT) {
+            return mFullSensorsList;
+        }
+
+        List<Sensor> fullList;
+        synchronized (mFullRuntimeSensorListByDevice) {
+            fullList = mFullRuntimeSensorListByDevice.get(deviceId);
+            if (fullList == null) {
+                fullList = createRuntimeSensorListLocked(deviceId);
+            }
+        }
+        return fullList;
     }
 
     /** @hide */
@@ -446,12 +513,53 @@
         }
     }
 
+    private List<Sensor> createRuntimeSensorListLocked(int deviceId) {
+        setupRuntimeSensorBroadcastReceiver();
+        List<Sensor> list = new ArrayList<>();
+        nativeGetRuntimeSensors(mNativeInstance, deviceId, list);
+        mFullRuntimeSensorListByDevice.put(deviceId, list);
+        mRuntimeSensorListByDeviceByType.put(deviceId, new SparseArray<>());
+        for (Sensor s : list) {
+            mHandleToSensor.put(s.getHandle(), s);
+        }
+        return list;
+    }
+
+    private void setupRuntimeSensorBroadcastReceiver() {
+        if (mRuntimeSensorBroadcastReceiver == null) {
+            mRuntimeSensorBroadcastReceiver = new BroadcastReceiver() {
+                @Override
+                public void onReceive(Context context, Intent intent) {
+                    if (intent.getAction().equals(ACTION_VIRTUAL_DEVICE_REMOVED)) {
+                        synchronized (mFullRuntimeSensorListByDevice) {
+                            final int deviceId = intent.getIntExtra(
+                                    EXTRA_VIRTUAL_DEVICE_ID, DEFAULT_DEVICE_ID);
+                            List<Sensor> removedSensors =
+                                    mFullRuntimeSensorListByDevice.removeReturnOld(deviceId);
+                            if (removedSensors != null) {
+                                for (Sensor s : removedSensors) {
+                                    cleanupSensorConnection(s);
+                                }
+                            }
+                            mRuntimeSensorListByDeviceByType.remove(deviceId);
+                        }
+                    }
+                }
+            };
+
+            IntentFilter filter = new IntentFilter("virtual_device_removed");
+            filter.addAction(ACTION_VIRTUAL_DEVICE_REMOVED);
+            mContext.registerReceiver(mRuntimeSensorBroadcastReceiver, filter,
+                    Context.RECEIVER_NOT_EXPORTED);
+        }
+    }
+
     private void setupDynamicSensorBroadcastReceiver() {
         if (mDynamicSensorBroadcastReceiver == null) {
             mDynamicSensorBroadcastReceiver = new BroadcastReceiver() {
                 @Override
                 public void onReceive(Context context, Intent intent) {
-                    if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) {
+                    if (intent.getAction().equals(Intent.ACTION_DYNAMIC_SENSOR_CHANGED)) {
                         if (DEBUG_DYNAMIC_SENSOR) {
                             Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast");
                         }
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 50551fee..f858227 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -245,11 +245,13 @@
      * applications is not guaranteed to be supported, however.</p>
      *
      * <p>For concurrent operation, in chronological order :
-     * - Applications must first close any open cameras that have sessions configured, using
-     *   {@link CameraDevice#close}.
-     * - All camera devices intended to be operated concurrently, must be opened using
-     *   {@link #openCamera}, before configuring sessions on any of the camera devices.</p>
-     *
+     * <ul>
+     * <li> Applications must first close any open cameras that have sessions configured, using
+     *   {@link CameraDevice#close}. </li>
+     * <li> All camera devices intended to be operated concurrently, must be opened using
+     *   {@link #openCamera}, before configuring sessions on any of the camera devices.</li>
+     *</ul>
+     *</p>
      * <p>Each device in a combination, is guaranteed to support stream combinations which may be
      * obtained by querying {@link #getCameraCharacteristics} for the key
      * {@link android.hardware.camera2.CameraCharacteristics#SCALER_MANDATORY_CONCURRENT_STREAM_COMBINATIONS}.</p>
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 9b07d3a..23d108f 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -137,7 +137,8 @@
             VIRTUAL_DISPLAY_FLAG_TRUSTED,
             VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP,
             VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED,
-            VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED
+            VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED,
+            VIRTUAL_DISPLAY_FLAG_OWN_FOCUS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface VirtualDisplayFlag {}
@@ -403,6 +404,31 @@
      */
     public static final int VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 13;
 
+    /**
+     * Virtual display flags: Indicates that the display maintains its own focus and touch mode.
+     *
+     * This flag is similar to {@link com.android.internal.R.bool.config_perDisplayFocusEnabled} in
+     * behavior, but only applies to the specific display instead of system-wide to all displays.
+     *
+     * Note: The display must be trusted in order to have its own focus.
+     *
+     * @see #createVirtualDisplay
+     * @see #VIRTUAL_DISPLAY_FLAG_TRUSTED
+     * @hide
+     */
+    @TestApi
+    public static final int VIRTUAL_DISPLAY_FLAG_OWN_FOCUS = 1 << 14;
+
+    /**
+     * Virtual display flags: Indicates that the display should not be a part of the default
+     * DisplayGroup and instead be part of a DisplayGroup associated with its virtual device.
+     *
+     * @see #createVirtualDisplay
+     * @hide
+     */
+    public static final int VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP = 1 << 15;
+
+
     /** @hide */
     @IntDef(prefix = {"MATCH_CONTENT_FRAMERATE_"}, value = {
             MATCH_CONTENT_FRAMERATE_UNKNOWN,
@@ -571,18 +597,20 @@
      * @see #DISPLAY_CATEGORY_PRESENTATION
      */
     public Display[] getDisplays(String category) {
-        final int[] displayIds = mGlobal.getDisplayIds();
+        boolean includeDisabled = (category != null
+                && category.equals(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED));
+        final int[] displayIds = mGlobal.getDisplayIds(includeDisabled);
         synchronized (mLock) {
             try {
-                if (category == null
-                        || DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
-                    addAllDisplaysLocked(mTempDisplays, displayIds);
-                } else if (category.equals(DISPLAY_CATEGORY_PRESENTATION)) {
+                if (DISPLAY_CATEGORY_PRESENTATION.equals(category)) {
                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_WIFI);
                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_EXTERNAL);
                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_OVERLAY);
                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_VIRTUAL);
                     addPresentationDisplaysLocked(mTempDisplays, displayIds, Display.TYPE_INTERNAL);
+                } else if (category == null
+                        || DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED.equals(category)) {
+                    addAllDisplaysLocked(mTempDisplays, displayIds);
                 }
                 return mTempDisplays.toArray(new Display[mTempDisplays.size()]);
             } finally {
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index cc397d5..f038c66 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -212,6 +212,16 @@
      */
     @UnsupportedAppUsage
     public int[] getDisplayIds() {
+        return getDisplayIds(/* includeDisabled= */ false);
+    }
+
+    /**
+     * Gets all currently valid logical display ids.
+     *
+     * @param includeDisabled True if the returned list of displays includes disabled displays.
+     * @return An array containing all display ids.
+     */
+    public int[] getDisplayIds(boolean includeDisabled) {
         try {
             synchronized (mLock) {
                 if (USE_CACHE) {
@@ -220,7 +230,7 @@
                     }
                 }
 
-                int[] displayIds = mDm.getDisplayIds();
+                int[] displayIds = mDm.getDisplayIds(includeDisabled);
                 if (USE_CACHE) {
                     mDisplayIdCache = displayIds;
                 }
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 1c2c895..829908f 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -423,8 +423,6 @@
         public static final int POLICY_DIM = 2;
         // Policy: Make the screen bright as usual.
         public static final int POLICY_BRIGHT = 3;
-        // Policy: Keep the screen and display optimized for VR mode.
-        public static final int POLICY_VR = 4;
 
         // The basic overall policy to apply: off, doze, dim or bright.
         public int policy;
@@ -489,10 +487,6 @@
             return policy == POLICY_BRIGHT || policy == POLICY_DIM;
         }
 
-        public boolean isVr() {
-            return policy == POLICY_VR;
-        }
-
         public void copyFrom(DisplayPowerRequest other) {
             policy = other.policy;
             useProximitySensor = other.useProximitySensor;
@@ -566,8 +560,6 @@
                     return "DIM";
                 case POLICY_BRIGHT:
                     return "BRIGHT";
-                case POLICY_VR:
-                    return "VR";
                 default:
                     return Integer.toString(policy);
             }
diff --git a/core/java/android/hardware/display/IDisplayManager.aidl b/core/java/android/hardware/display/IDisplayManager.aidl
index 6b5594b..28bb35f 100644
--- a/core/java/android/hardware/display/IDisplayManager.aidl
+++ b/core/java/android/hardware/display/IDisplayManager.aidl
@@ -37,7 +37,7 @@
 interface IDisplayManager {
     @UnsupportedAppUsage
     DisplayInfo getDisplayInfo(int displayId);
-    int[] getDisplayIds();
+    int[] getDisplayIds(boolean includeDisabled);
 
     boolean isUidPresentOnDisplay(int uid, int displayId);
 
diff --git a/core/java/android/hardware/display/VirtualDisplayConfig.java b/core/java/android/hardware/display/VirtualDisplayConfig.java
index b76b98d..891ba36 100644
--- a/core/java/android/hardware/display/VirtualDisplayConfig.java
+++ b/core/java/android/hardware/display/VirtualDisplayConfig.java
@@ -30,6 +30,9 @@
 
 import com.android.internal.util.DataClass;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Holds configuration used to create {@link VirtualDisplay} instances. See
  * {@link MediaProjection#createVirtualDisplay(VirtualDisplayConfig, VirtualDisplay.Callback, Handler)}.
@@ -99,6 +102,13 @@
      */
     private boolean mWindowManagerMirroring = false;
 
+    /**
+     * The display categories. If set, only corresponding activities from the same category can be
+     * shown on the display.
+     */
+    @DataClass.PluralOf("displayCategory")
+    @NonNull private List<String> mDisplayCategories = new ArrayList<>();
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -124,7 +134,8 @@
             @Nullable Surface surface,
             @Nullable String uniqueId,
             int displayIdToMirror,
-            boolean windowManagerMirroring) {
+            boolean windowManagerMirroring,
+            @NonNull List<String> displayCategories) {
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
                 NonNull.class, null, mName);
@@ -147,6 +158,9 @@
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
         this.mWindowManagerMirroring = windowManagerMirroring;
+        this.mDisplayCategories = displayCategories;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDisplayCategories);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -233,6 +247,15 @@
         return mWindowManagerMirroring;
     }
 
+    /**
+     * The display categories. If set, only corresponding activities from the same category can be
+     * shown on the display.
+     */
+    @DataClass.Generated.Member
+    public @NonNull List<String> getDisplayCategories() {
+        return mDisplayCategories;
+    }
+
     @Override
     @DataClass.Generated.Member
     public void writeToParcel(@NonNull Parcel dest, int flags) {
@@ -252,6 +275,7 @@
         if (mSurface != null) dest.writeTypedObject(mSurface, flags);
         if (mUniqueId != null) dest.writeString(mUniqueId);
         dest.writeInt(mDisplayIdToMirror);
+        dest.writeStringList(mDisplayCategories);
     }
 
     @Override
@@ -275,6 +299,8 @@
         Surface surface = (flg & 0x20) == 0 ? null : (Surface) in.readTypedObject(Surface.CREATOR);
         String uniqueId = (flg & 0x40) == 0 ? null : in.readString();
         int displayIdToMirror = in.readInt();
+        List<String> displayCategories = new ArrayList<>();
+        in.readStringList(displayCategories);
 
         this.mName = name;
         com.android.internal.util.AnnotationValidations.validate(
@@ -298,6 +324,9 @@
         this.mUniqueId = uniqueId;
         this.mDisplayIdToMirror = displayIdToMirror;
         this.mWindowManagerMirroring = windowManagerMirroring;
+        this.mDisplayCategories = displayCategories;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mDisplayCategories);
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -332,6 +361,7 @@
         private @Nullable String mUniqueId;
         private int mDisplayIdToMirror;
         private boolean mWindowManagerMirroring;
+        private @NonNull List<String> mDisplayCategories;
 
         private long mBuilderFieldsSet = 0L;
 
@@ -478,10 +508,30 @@
             return this;
         }
 
+        /**
+         * The display categories. If set, only corresponding activities from the same category can be
+         * shown on the display.
+         */
+        @DataClass.Generated.Member
+        public @NonNull Builder setDisplayCategories(@NonNull List<String> value) {
+            checkNotUsed();
+            mBuilderFieldsSet |= 0x200;
+            mDisplayCategories = value;
+            return this;
+        }
+
+        /** @see #setDisplayCategories */
+        @DataClass.Generated.Member
+        public @NonNull Builder addDisplayCategory(@NonNull String value) {
+            if (mDisplayCategories == null) setDisplayCategories(new ArrayList<>());
+            mDisplayCategories.add(value);
+            return this;
+        }
+
         /** Builds the instance. This builder should not be touched after calling this! */
         public @NonNull VirtualDisplayConfig build() {
             checkNotUsed();
-            mBuilderFieldsSet |= 0x200; // Mark builder used
+            mBuilderFieldsSet |= 0x400; // Mark builder used
 
             if ((mBuilderFieldsSet & 0x10) == 0) {
                 mFlags = 0;
@@ -498,6 +548,9 @@
             if ((mBuilderFieldsSet & 0x100) == 0) {
                 mWindowManagerMirroring = false;
             }
+            if ((mBuilderFieldsSet & 0x200) == 0) {
+                mDisplayCategories = new ArrayList<>();
+            }
             VirtualDisplayConfig o = new VirtualDisplayConfig(
                     mName,
                     mWidth,
@@ -507,12 +560,13 @@
                     mSurface,
                     mUniqueId,
                     mDisplayIdToMirror,
-                    mWindowManagerMirroring);
+                    mWindowManagerMirroring,
+                    mDisplayCategories);
             return o;
         }
 
         private void checkNotUsed() {
-            if ((mBuilderFieldsSet & 0x200) != 0) {
+            if ((mBuilderFieldsSet & 0x400) != 0) {
                 throw new IllegalStateException(
                         "This Builder should not be reused. Use a new Builder instance instead");
             }
@@ -520,10 +574,10 @@
     }
 
     @DataClass.Generated(
-            time = 1646227247934L,
+            time = 1668534501320L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/hardware/display/VirtualDisplayConfig.java",
-            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate  boolean mWindowManagerMirroring\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
+            inputSignatures = "private @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.IntRange int mWidth\nprivate @android.annotation.IntRange int mHeight\nprivate @android.annotation.IntRange int mDensityDpi\nprivate @android.hardware.display.DisplayManager.VirtualDisplayFlag int mFlags\nprivate @android.annotation.Nullable android.view.Surface mSurface\nprivate @android.annotation.Nullable java.lang.String mUniqueId\nprivate  int mDisplayIdToMirror\nprivate  boolean mWindowManagerMirroring\nprivate @com.android.internal.util.DataClass.PluralOf(\"displayCategory\") @android.annotation.NonNull java.util.List<java.lang.String> mDisplayCategories\nclass VirtualDisplayConfig extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genParcelable=true, genAidl=true, genBuilder=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index fb5ac5a..a748b60 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -956,7 +956,7 @@
     public void onPointerDown(long requestId, int sensorId, int x, int y,
             float minor, float major) {
         if (mService == null) {
-            Slog.w(TAG, "onFingerDown: no fingerprint service");
+            Slog.w(TAG, "onPointerDown: no fingerprint service");
             return;
         }
 
@@ -979,7 +979,7 @@
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
     public void onPointerUp(long requestId, int sensorId) {
         if (mService == null) {
-            Slog.w(TAG, "onFingerDown: no fingerprint service");
+            Slog.w(TAG, "onPointerUp: no fingerprint service");
             return;
         }
 
@@ -993,6 +993,86 @@
     }
 
     /**
+     * TODO(b/218388821): The parameter list should be replaced with PointerContext.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void onPointerDown(
+            long requestId,
+            int sensorId,
+            int pointerId,
+            float x,
+            float y,
+            float minor,
+            float major,
+            float orientation,
+            long time,
+            long gestureStart,
+            boolean isAod) {
+        if (mService == null) {
+            Slog.w(TAG, "onPointerDown: no fingerprint service");
+            return;
+        }
+
+        final PointerContext pc = new PointerContext();
+        pc.pointerId = pointerId;
+        pc.x = x;
+        pc.y = y;
+        pc.minor = minor;
+        pc.major = major;
+        pc.orientation = orientation;
+        pc.time = time;
+        pc.gestureStart = gestureStart;
+        pc.isAod = isAod;
+
+        try {
+            mService.onPointerDown(requestId, sensorId, pc);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * TODO(b/218388821): The parameter list should be replaced with PointerContext.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void onPointerUp(
+            long requestId,
+            int sensorId,
+            int pointerId,
+            float x,
+            float y,
+            float minor,
+            float major,
+            float orientation,
+            long time,
+            long gestureStart,
+            boolean isAod) {
+        if (mService == null) {
+            Slog.w(TAG, "onPointerUp: no fingerprint service");
+            return;
+        }
+
+        final PointerContext pc = new PointerContext();
+        pc.pointerId = pointerId;
+        pc.x = x;
+        pc.y = y;
+        pc.minor = minor;
+        pc.major = major;
+        pc.orientation = orientation;
+        pc.time = time;
+        pc.gestureStart = gestureStart;
+        pc.isAod = isAod;
+
+        try {
+            mService.onPointerUp(requestId, sensorId, pc);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * @hide
      */
     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 3e509e4..b0b7a41 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -50,7 +50,7 @@
 
 /**
  * The {@link HdmiControlManager} class is used to send HDMI control messages
- * to attached CEC devices.
+ * to attached CEC devices. It also allows to control the eARC feature.
  *
  * <p>Provides various HDMI client instances that represent HDMI-CEC logical devices
  * hosted in the system. {@link #getTvClient()}, for instance will return an
@@ -398,6 +398,30 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface RoutingControl {}
 
+    // -- Whether the Soundbar mode feature is enabled or disabled.
+    /**
+     * Soundbar mode feature enabled.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE
+     */
+    public static final int SOUNDBAR_MODE_ENABLED = 1;
+    /**
+     * Soundbar mode feature disabled.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE
+     */
+    public static final int SOUNDBAR_MODE_DISABLED = 0;
+    /**
+     * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE
+     * @hide
+     */
+    @IntDef(prefix = { "SOUNDBAR_MODE" }, value = {
+            SOUNDBAR_MODE_ENABLED,
+            SOUNDBAR_MODE_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface SoundbarMode {}
+
     // -- Scope of CEC power control messages sent by a playback device.
     /**
      * Send CEC power control messages to TV only:
@@ -775,6 +799,31 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface SadPresenceInQuery {}
 
+    // -- Whether eARC is enabled or disabled.
+    /**
+     * eARC enabled.
+     *
+     * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED
+     */
+    public static final int EARC_FEATURE_ENABLED = 1;
+    /**
+     * eARC disabled.
+     *
+     * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED
+     */
+    public static final int EARC_FEATURE_DISABLED = 0;
+    /**
+     * @hide
+     *
+     * @see HdmiControlManager#SETTING_NAME_EARC_ENABLED
+     */
+    @IntDef(prefix = { "EARC_FEATURE" }, value = {
+            EARC_FEATURE_ENABLED,
+            EARC_FEATURE_DISABLED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface EarcFeature {}
+
     // -- Settings available in the CEC Configuration.
     /**
      * Name of a setting deciding whether the CEC is enabled.
@@ -795,6 +844,14 @@
      */
     public static final String CEC_SETTING_NAME_ROUTING_CONTROL = "routing_control";
     /**
+     * Name of a setting deciding whether the Soundbar mode feature is enabled.
+     * Before exposing this setting make sure the hardware supports it, otherwise, you may
+     * experience multiple issues.
+     *
+     * @see HdmiControlManager#setSoundbarMode(int)
+     */
+    public static final String CEC_SETTING_NAME_SOUNDBAR_MODE = "soundbar_mode";
+    /**
      * Name of a setting deciding on the power control mode.
      *
      * @see HdmiControlManager#setPowerControlMode(String)
@@ -1032,11 +1089,21 @@
      */
     public static final String CEC_SETTING_NAME_QUERY_SAD_MAX = "query_sad_max";
     /**
+     * Name of a setting representing whether eARC is enabled or not.
+     *
+     * @see HdmiControlManager#setEarcEnabled(int)
+     */
+    public static final String SETTING_NAME_EARC_ENABLED = "earc_enabled";
+    /**
      * @hide
      */
-    @StringDef(prefix = { "CEC_SETTING_NAME_" }, value = {
+    // TODO(b/240379115): change names of CEC settings so that their prefix matches with the other
+    // HDMI control settings.
+    @StringDef(value = {
         CEC_SETTING_NAME_HDMI_CEC_ENABLED,
         CEC_SETTING_NAME_HDMI_CEC_VERSION,
+        CEC_SETTING_NAME_ROUTING_CONTROL,
+        CEC_SETTING_NAME_SOUNDBAR_MODE,
         CEC_SETTING_NAME_POWER_CONTROL_MODE,
         CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
         CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
@@ -1066,8 +1133,9 @@
         CEC_SETTING_NAME_QUERY_SAD_DST,
         CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
         CEC_SETTING_NAME_QUERY_SAD_MAX,
+        SETTING_NAME_EARC_ENABLED,
     })
-    public @interface CecSettingName {}
+    public @interface SettingName {}
 
     /**
      * @hide
@@ -1188,7 +1256,16 @@
             case HdmiDeviceInfo.DEVICE_PLAYBACK:
                 return mHasPlaybackDevice ? new HdmiPlaybackClient(mService) : null;
             case HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM:
-                return mHasAudioSystemDevice ? new HdmiAudioSystemClient(mService) : null;
+                try {
+                    if ((mService.getCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE)
+                            == SOUNDBAR_MODE_ENABLED && mHasPlaybackDevice)
+                            || mHasAudioSystemDevice) {
+                        return new HdmiAudioSystemClient(mService);
+                    }
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
+                return null;
             case HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH:
                 return (mHasSwitchDevice || mIsSwitchDevice)
                     ? new HdmiSwitchClient(mService) : null;
@@ -1291,6 +1368,22 @@
     }
 
     /**
+     * Get the list of the HDMI ports configuration.
+     *
+     * <p>This returns an empty list when the current device does not have HDMI ports.
+     *
+     * @return a list of {@link HdmiPortInfo}
+     */
+    @NonNull
+    public List<HdmiPortInfo> getPortInfo() {
+        try {
+            return mService.getPortInfo();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Power off the target device by sending CEC commands. Note that this device can't be the
      * current device itself.
      *
@@ -1685,7 +1778,7 @@
     public void addHotplugEventListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull HotplugEventListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "addHotplugEventListener: HdmiControlService is not available");
             return;
         }
         if (mHotplugEventListeners.containsKey(listener)) {
@@ -1710,7 +1803,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void removeHotplugEventListener(HotplugEventListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "removeHotplugEventListener: HdmiControlService is not available");
             return;
         }
         IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener);
@@ -1778,7 +1871,7 @@
     public void addHdmiControlStatusChangeListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull HdmiControlStatusChangeListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "addHdmiControlStatusChangeListener: HdmiControlService is not available");
             return;
         }
         if (mHdmiControlStatusChangeListeners.containsKey(listener)) {
@@ -1805,7 +1898,8 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void removeHdmiControlStatusChangeListener(HdmiControlStatusChangeListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG,
+                    "removeHdmiControlStatusChangeListener: HdmiControlService is not available");
             return;
         }
         IHdmiControlStatusChangeListener wrappedListener =
@@ -1854,7 +1948,8 @@
     public void addHdmiCecVolumeControlFeatureListener(@NonNull @CallbackExecutor Executor executor,
             @NonNull HdmiCecVolumeControlFeatureListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG,
+                    "addHdmiCecVolumeControlFeatureListener: HdmiControlService is not available");
             return;
         }
         if (mHdmiCecVolumeControlFeatureListeners.containsKey(listener)) {
@@ -1882,7 +1977,9 @@
     public void removeHdmiCecVolumeControlFeatureListener(
             HdmiCecVolumeControlFeatureListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG,
+                    "removeHdmiCecVolumeControlFeatureListener: HdmiControlService is not "
+                            + "available");
             return;
         }
         IHdmiCecVolumeControlFeatureListener wrappedListener =
@@ -1922,7 +2019,7 @@
          *
          * @param setting name of a CEC setting that changed
          */
-        void onChange(@NonNull @CecSettingName String setting);
+        void onChange(@NonNull @SettingName String setting);
     }
 
     private final ArrayMap<String,
@@ -1930,11 +2027,11 @@
                     mCecSettingChangeListeners = new ArrayMap<>();
 
     private void addCecSettingChangeListener(
-            @NonNull @CecSettingName String setting,
+            @NonNull @SettingName String setting,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull CecSettingChangeListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "addCecSettingChangeListener: HdmiControlService is not available");
             return;
         }
         if (mCecSettingChangeListeners.containsKey(setting)
@@ -1956,10 +2053,10 @@
     }
 
     private void removeCecSettingChangeListener(
-            @NonNull @CecSettingName String setting,
+            @NonNull @SettingName String setting,
             @NonNull CecSettingChangeListener listener) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "removeCecSettingChangeListener: HdmiControlService is not available");
             return;
         }
         IHdmiCecSettingChangeListener wrappedListener =
@@ -1992,17 +2089,20 @@
     }
 
     /**
-     * Get a set of user-modifiable settings.
+     * Get a set of user-modifiable HDMI control settings.
+     * This applies to CEC settings and eARC settings.
      *
      * @return a set of user-modifiable settings.
      * @throws RuntimeException when the HdmiControlService is not available.
      */
+    // TODO(b/240379115): rename this API to represent that this applies to all HDMI control
+    // settings and not just CEC settings.
     @NonNull
-    @CecSettingName
+    @SettingName
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public List<String> getUserCecSettings() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getUserCecSettings: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2013,7 +2113,9 @@
     }
 
     /**
-     * Get a set of allowed values for a setting (string value-type).
+     * Get a set of allowed values for an HDMI control setting (string value-type).
+     * This applies to CEC settings and eARC settings.
+     *
      *
      * @param name name of the setting
      * @return a set of allowed values for a settings. {@code null} on failure.
@@ -2021,11 +2123,13 @@
      * @throws IllegalArgumentException when setting {@code name} value type is invalid.
      * @throws RuntimeException when the HdmiControlService is not available.
      */
+    // TODO(b/240379115): rename this API to represent that this applies to all HDMI control
+    // settings and not just CEC settings.
     @NonNull
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
-    public List<String> getAllowedCecSettingStringValues(@NonNull @CecSettingName String name) {
+    public List<String> getAllowedCecSettingStringValues(@NonNull @SettingName String name) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getAllowedCecSettingStringValues: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2036,7 +2140,8 @@
     }
 
     /**
-     * Get a set of allowed values for a setting (int value-type).
+     * Get a set of allowed values for an HDMI control setting (int value-type).
+     * This applies to CEC settings and eARC settings.
      *
      * @param name name of the setting
      * @return a set of allowed values for a settings. {@code null} on failure.
@@ -2044,11 +2149,13 @@
      * @throws IllegalArgumentException when setting {@code name} value type is invalid.
      * @throws RuntimeException when the HdmiControlService is not available.
      */
+    // TODO(b/240379115): rename this API to represent that this applies to all HDMI control
+    // settings and not just CEC settings.
     @NonNull
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
-    public List<Integer> getAllowedCecSettingIntValues(@NonNull @CecSettingName String name) {
+    public List<Integer> getAllowedCecSettingIntValues(@NonNull @SettingName String name) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getAllowedCecSettingIntValues: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2067,7 +2174,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setHdmiCecEnabled(@NonNull @HdmiCecControl int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setHdmiCecEnabled: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2087,7 +2194,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getHdmiCecEnabled() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getHdmiCecEnabled: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2145,7 +2252,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setHdmiCecVersion(@NonNull @HdmiCecVersion int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setHdmiCecVersion: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2167,7 +2274,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getHdmiCecVersion() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getHdmiCecVersion: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2190,7 +2297,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setRoutingControl(@NonNull @RoutingControl int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setRoutingControl: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2215,7 +2322,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getRoutingControl() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getRoutingControl: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2226,6 +2333,54 @@
     }
 
     /**
+     * Set the status of Soundbar mode feature.
+     *
+     * <p>This allows to enable/disable Soundbar mode on the playback device.
+     * The setting's effect will be available on devices where the hardware supports this feature.
+     * If enabled, an audio system local device will be allocated and try to establish an ARC
+     * connection with the TV. If disabled, the ARC connection will be terminated and the audio
+     * system local device will be removed from the network.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE
+     */
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void setSoundbarMode(@SoundbarMode int value) {
+        if (mService == null) {
+            Log.e(TAG, "setSoundbarMode: HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            mService.setCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE, value);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the current status of Soundbar mode feature.
+     *
+     * <p>Reflects whether Soundbar mode is currently enabled on the playback device.
+     * If enabled, an audio system local device will be allocated and try to establish an ARC
+     * connection with the TV. If disabled, the ARC connection will be terminated and the audio
+     * system local device will be removed from the network.
+     *
+     * @see HdmiControlManager#CEC_SETTING_NAME_SOUNDBAR_MODE
+     */
+    @SoundbarMode
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public int getSoundbarMode() {
+        if (mService == null) {
+            Log.e(TAG, "getSoundbarMode: HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            return mService.getCecSettingIntValue(CEC_SETTING_NAME_SOUNDBAR_MODE);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Set the status of Power Control.
      *
      * <p>Specifies to which devices Power Control messages should be sent:
@@ -2236,7 +2391,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setPowerControlMode(@NonNull @PowerControlMode String value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setPowerControlMode: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2259,7 +2414,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public String getPowerControlMode() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getPowerControlMode: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2280,7 +2435,8 @@
     public void setPowerStateChangeOnActiveSourceLost(
             @NonNull @ActiveSourceLostBehavior String value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG,
+                    "setPowerStateChangeOnActiveSourceLost: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2303,7 +2459,8 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public String getPowerStateChangeOnActiveSourceLost() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG,
+                    "getPowerStateChangeOnActiveSourceLost: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2328,7 +2485,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setSystemAudioControl(@NonNull @SystemAudioControl int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setSystemAudioControl: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2354,7 +2511,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getSystemAudioControl() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getSystemAudioControl: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2374,7 +2531,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setSystemAudioModeMuting(@NonNull @SystemAudioModeMuting int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setSystemAudioModeMuting: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2396,7 +2553,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getSystemAudioModeMuting() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getSystemAudioModeMuting: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2417,7 +2574,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setTvWakeOnOneTouchPlay(@NonNull @TvWakeOnOneTouchPlay int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setTvWakeOnOneTouchPlay: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2440,7 +2597,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getTvWakeOnOneTouchPlay() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getTvWakeOnOneTouchPlay: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2461,7 +2618,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public void setTvSendStandbyOnSleep(@NonNull @TvSendStandbyOnSleep int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setTvSendStandbyOnSleep: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2484,7 +2641,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getTvSendStandbyOnSleep() {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getTvSendStandbyOnSleep: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2516,7 +2673,7 @@
     public void setSadPresenceInQuery(@NonNull @CecSettingSad String setting,
             @SadPresenceInQuery int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setSadPresenceInQuery: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2550,7 +2707,7 @@
     public void setSadsPresenceInQuery(@NonNull @CecSettingSad List<String> settings,
             @SadPresenceInQuery int value) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "setSadsPresenceInQuery: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2582,7 +2739,7 @@
     @RequiresPermission(android.Manifest.permission.HDMI_CEC)
     public int getSadPresenceInQuery(@NonNull @CecSettingSad String setting) {
         if (mService == null) {
-            Log.e(TAG, "HdmiControlService is not available");
+            Log.e(TAG, "getSadPresenceInQuery: HdmiControlService is not available");
             throw new RuntimeException("HdmiControlService is not available");
         }
         try {
@@ -2591,4 +2748,44 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Set the global status of eARC.
+     *
+     * <p>This allows to enable/disable the eARC feature on the device. If the feature is enabled
+     * and the hardware supports eARC as well, the device can attempt to establish an eARC
+     * connection.
+     */
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public void setEarcEnabled(@NonNull @EarcFeature int value) {
+        if (mService == null) {
+            Log.e(TAG, "setEarcEnabled: HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            mService.setCecSettingIntValue(SETTING_NAME_EARC_ENABLED, value);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Get the current global status of eARC.
+     *
+     * <p>Reflects whether the eARC feature is currently enabled on the device.
+     */
+    @NonNull
+    @EarcFeature
+    @RequiresPermission(android.Manifest.permission.HDMI_CEC)
+    public int getEarcEnabled() {
+        if (mService == null) {
+            Log.e(TAG, "getEarcEnabled: HdmiControlService is not available");
+            throw new RuntimeException("HdmiControlService is not available");
+        }
+        try {
+            return mService.getCecSettingIntValue(SETTING_NAME_EARC_ENABLED);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
 }
diff --git a/core/java/android/hardware/hdmi/HdmiSwitchClient.java b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
index 0fb5894..8aaeec3 100644
--- a/core/java/android/hardware/hdmi/HdmiSwitchClient.java
+++ b/core/java/android/hardware/hdmi/HdmiSwitchClient.java
@@ -184,7 +184,10 @@
      * <p>This returns an empty list when the current device does not have HDMI input.
      *
      * @return a list of {@link HdmiPortInfo}
+     *
+     * @deprecated Please use {@link HdmiControlManager#getPortInfo()} instead.
      */
+    @Deprecated
     @NonNull
     public List<HdmiPortInfo> getPortInfo() {
         try {
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index fd3d1ac..b26c0a2 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -32,6 +32,8 @@
 import android.os.IBinder;
 import android.os.IVibratorStateListener;
 import android.os.VibrationEffect;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 import android.view.InputDevice;
 import android.view.InputEvent;
 import android.view.InputMonitor;
@@ -80,17 +82,47 @@
 
     // Keyboard layouts configuration.
     KeyboardLayout[] getKeyboardLayouts();
+
     KeyboardLayout[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
+
     KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor);
+
     String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier);
+
+    @EnforcePermission("SET_KEYBOARD_LAYOUT")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
     void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
+
     String[] getEnabledKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier);
+
+    @EnforcePermission("SET_KEYBOARD_LAYOUT")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
     void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
+
+    @EnforcePermission("SET_KEYBOARD_LAYOUT")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
     void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor);
 
+    // New Keyboard layout config APIs
+    String getKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, int userId,
+            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
+
+    @EnforcePermission("SET_KEYBOARD_LAYOUT")
+    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = "
+            + "android.Manifest.permission.SET_KEYBOARD_LAYOUT)")
+    void setKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, int userId,
+            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype,
+            String keyboardLayoutDescriptor);
+
+    String[] getKeyboardLayoutListForInputDevice(in InputDeviceIdentifier identifier, int userId,
+            in InputMethodInfo imeInfo, in InputMethodSubtype imeSubtype);
+
     // Registers an input devices changed listener.
     void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index a157a8f..cea3fa1 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -26,6 +26,7 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.annotation.UserIdInt;
 import android.app.ActivityThread;
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -66,6 +67,8 @@
 import android.view.PointerIcon;
 import android.view.VerifiedInputEvent;
 import android.view.WindowManager.LayoutParams;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -889,6 +892,91 @@
     }
 
     /**
+     * Gets the keyboard layout descriptor for the specified input device, userId, imeInfo and
+     * imeSubtype.
+     *
+     * @param identifier Identifier for the input device
+     * @param userId user profile ID
+     * @param imeInfo contains IME information like imeId, etc.
+     * @param imeSubtype contains IME subtype information like input languageTag, layoutType, etc.
+     * @return The keyboard layout descriptor, or null if no keyboard layout has been set.
+     *
+     * @hide
+     */
+    @Nullable
+    public String getKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        try {
+            return mIm.getKeyboardLayoutForInputDevice(identifier, userId, imeInfo, imeSubtype);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Sets the keyboard layout descriptor for the specified input device, userId, imeInfo and
+     * imeSubtype.
+     *
+     * <p>
+     * This method may have the side-effect of causing the input device in question to be
+     * reconfigured.
+     * </p>
+     *
+     * @param identifier The identifier for the input device.
+     * @param userId user profile ID
+     * @param imeInfo contains IME information like imeId, etc.
+     * @param imeSubtype contains IME subtype information like input languageTag, layoutType, etc.
+     * @param keyboardLayoutDescriptor The keyboard layout descriptor to use, must not be null.
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
+    public void setKeyboardLayoutForInputDevice(@NonNull InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype, @NonNull String keyboardLayoutDescriptor) {
+        if (identifier == null) {
+            throw new IllegalArgumentException("identifier must not be null");
+        }
+        if (keyboardLayoutDescriptor == null) {
+            throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
+        }
+
+        try {
+            mIm.setKeyboardLayoutForInputDevice(identifier, userId, imeInfo, imeSubtype,
+                    keyboardLayoutDescriptor);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Gets all keyboard layout descriptors that are enabled for the specified input device, userId,
+     * imeInfo and imeSubtype.
+     *
+     * @param identifier The identifier for the input device.
+     * @param userId user profile ID
+     * @param imeInfo contains IME information like imeId, etc.
+     * @param imeSubtype contains IME subtype information like input languageTag, layoutType, etc.
+     * @return The keyboard layout descriptors.
+     *
+     * @hide
+     */
+    public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        if (identifier == null) {
+            throw new IllegalArgumentException("inputDeviceDescriptor must not be null");
+        }
+
+        try {
+            return mIm.getKeyboardLayoutListForInputDevice(identifier, userId, imeInfo, imeSubtype);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the mouse pointer speed.
      * <p>
      * Only returns the permanent mouse pointer speed.  Ignores any temporary pointer
diff --git a/core/java/android/hardware/input/VirtualDpadConfig.aidl b/core/java/android/hardware/input/VirtualDpadConfig.aidl
new file mode 100644
index 0000000..fac90f4
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualDpadConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+parcelable VirtualDpadConfig;
diff --git a/core/java/android/hardware/input/VirtualDpadConfig.java b/core/java/android/hardware/input/VirtualDpadConfig.java
new file mode 100644
index 0000000..d888dc0
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualDpadConfig.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Configurations to create virtual Dpad.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualDpadConfig extends VirtualInputDeviceConfig implements Parcelable {
+    @NonNull
+    public static final Creator<VirtualDpadConfig> CREATOR = new Creator<VirtualDpadConfig>() {
+        @Override
+        public VirtualDpadConfig createFromParcel(Parcel in) {
+            return new VirtualDpadConfig(in);
+        }
+
+        @Override
+        public VirtualDpadConfig[] newArray(int size) {
+            return new VirtualDpadConfig[size];
+        }
+    };
+
+    private VirtualDpadConfig(@NonNull VirtualDpadConfig.Builder builder) {
+        super(builder);
+    }
+
+    private VirtualDpadConfig(@NonNull Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Builder for creating a {@link VirtualDpadConfig}.
+     */
+    public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
+
+        /**
+         * Builds the {@link VirtualDpadConfig} instance.
+         */
+        @NonNull
+        public VirtualDpadConfig build() {
+            return new VirtualDpadConfig(this);
+        }
+    }
+}
diff --git a/core/java/android/hardware/input/VirtualInputDeviceConfig.java b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
new file mode 100644
index 0000000..d3dacc9
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualInputDeviceConfig.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+
+/**
+ * Common configurations to create virtual input devices.
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class VirtualInputDeviceConfig {
+    /** The vendor id uniquely identifies the company who manufactured the device. */
+    private final int mVendorId;
+    /**
+     * The product id uniquely identifies which product within the address space of a given vendor,
+     * identified by the device's vendor id.
+     */
+    private final int mProductId;
+    /** The associated display ID of the virtual input device. */
+    private final int mAssociatedDisplayId;
+    /** The name of the virtual input device. */
+    @NonNull
+    private final String mInputDeviceName;
+
+    protected VirtualInputDeviceConfig(@NonNull Builder<? extends Builder<?>> builder) {
+        mVendorId = builder.mVendorId;
+        mProductId = builder.mProductId;
+        mAssociatedDisplayId = builder.mAssociatedDisplayId;
+        mInputDeviceName = builder.mInputDeviceName;
+    }
+
+    protected VirtualInputDeviceConfig(@NonNull Parcel in) {
+        mVendorId = in.readInt();
+        mProductId = in.readInt();
+        mAssociatedDisplayId = in.readInt();
+        mInputDeviceName = in.readString8();
+    }
+
+    /**
+     * The vendor id uniquely identifies the company who manufactured the device.
+     */
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    /**
+     * The product id uniquely identifies which product within the address space of a given vendor,
+     * identified by the device's vendor id.
+     */
+    public int getProductId() {
+        return mProductId;
+    }
+
+    /**
+     * The associated display ID of the virtual input device.
+     */
+    public int getAssociatedDisplayId() {
+        return mAssociatedDisplayId;
+    }
+
+    /**
+     * The name of the virtual input device.
+     */
+    @NonNull
+    public String getInputDeviceName() {
+        return mInputDeviceName;
+    }
+
+    void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeInt(mVendorId);
+        dest.writeInt(mProductId);
+        dest.writeInt(mAssociatedDisplayId);
+        dest.writeString8(mInputDeviceName);
+    }
+
+    /**
+     * A builder for {@link VirtualInputDeviceConfig}
+     *
+     * @param <T> The subclass to be built.
+     */
+    @SuppressWarnings({"StaticFinalBuilder", "MissingBuildMethod"})
+    public abstract static class Builder<T extends Builder<T>> {
+
+        private int mVendorId;
+        private int mProductId;
+        private int mAssociatedDisplayId;
+        @NonNull
+        private String mInputDeviceName;
+
+        /** @see VirtualInputDeviceConfig#getVendorId(). */
+        @NonNull
+        public T setVendorId(int vendorId) {
+            mVendorId = vendorId;
+            return self();
+        }
+
+
+        /** @see VirtualInputDeviceConfig#getProductId(). */
+        @NonNull
+        public T setProductId(int productId) {
+            mProductId = productId;
+            return self();
+        }
+
+        /** @see VirtualInputDeviceConfig#getAssociatedDisplayId(). */
+        @NonNull
+        public T setAssociatedDisplayId(int displayId) {
+            mAssociatedDisplayId = displayId;
+            return self();
+        }
+
+        /** @see VirtualInputDeviceConfig#getInputDeviceName(). */
+        @NonNull
+        public T setInputDeviceName(@NonNull String deviceName) {
+            mInputDeviceName = deviceName;
+            return self();
+        }
+
+        /**
+         * Each subclass should return itself to allow the builder to chain properly
+         */
+        T self() {
+            return (T) this;
+        }
+    }
+}
diff --git a/core/java/android/hardware/input/VirtualKeyboardConfig.aidl b/core/java/android/hardware/input/VirtualKeyboardConfig.aidl
new file mode 100644
index 0000000..8772e23
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualKeyboardConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+parcelable VirtualKeyboardConfig;
diff --git a/core/java/android/hardware/input/VirtualKeyboardConfig.java b/core/java/android/hardware/input/VirtualKeyboardConfig.java
new file mode 100644
index 0000000..9463857
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualKeyboardConfig.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+
+/**
+ * Configurations to create virtual keyboard.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualKeyboardConfig extends VirtualInputDeviceConfig implements Parcelable {
+
+    @NonNull
+    public static final Creator<VirtualKeyboardConfig> CREATOR =
+            new Creator<VirtualKeyboardConfig>() {
+                @Override
+                public VirtualKeyboardConfig createFromParcel(Parcel in) {
+                    return new VirtualKeyboardConfig(in);
+                }
+
+                @Override
+                public VirtualKeyboardConfig[] newArray(int size) {
+                    return new VirtualKeyboardConfig[size];
+                }
+            };
+
+    private VirtualKeyboardConfig(@NonNull Builder builder) {
+        super(builder);
+    }
+
+    private VirtualKeyboardConfig(@NonNull Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Builder for creating a {@link VirtualKeyboardConfig}.
+     */
+    public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
+        /**
+         * Builds the {@link VirtualKeyboardConfig} instance.
+         */
+        @NonNull
+        public VirtualKeyboardConfig build() {
+            return new VirtualKeyboardConfig(this);
+        }
+    }
+}
diff --git a/core/java/android/hardware/input/VirtualMouseConfig.aidl b/core/java/android/hardware/input/VirtualMouseConfig.aidl
new file mode 100644
index 0000000..a0d5fb5
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualMouseConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+parcelable VirtualMouseConfig;
diff --git a/core/java/android/hardware/input/VirtualMouseConfig.java b/core/java/android/hardware/input/VirtualMouseConfig.java
new file mode 100644
index 0000000..7ad5d04
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualMouseConfig.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Configurations to create virtual mouse.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualMouseConfig extends VirtualInputDeviceConfig implements Parcelable {
+    @NonNull
+    public static final Creator<VirtualMouseConfig> CREATOR = new Creator<VirtualMouseConfig>() {
+        @Override
+        public VirtualMouseConfig createFromParcel(Parcel in) {
+            return new VirtualMouseConfig(in);
+        }
+
+        @Override
+        public VirtualMouseConfig[] newArray(int size) {
+            return new VirtualMouseConfig[size];
+        }
+    };
+
+    private VirtualMouseConfig(@NonNull VirtualMouseConfig.Builder builder) {
+        super(builder);
+    }
+
+    private VirtualMouseConfig(@NonNull Parcel in) {
+        super(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+    }
+
+    /**
+     * Builder for creating a {@link VirtualMouseConfig}.
+     */
+    public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
+
+        /**
+         * Builds the {@link VirtualMouseConfig} instance.
+         */
+        @NonNull
+        public VirtualMouseConfig build() {
+            return new VirtualMouseConfig(this);
+        }
+    }
+}
diff --git a/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl b/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl
new file mode 100644
index 0000000..e4b0edb
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualTouchscreenConfig.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+parcelable VirtualTouchscreenConfig;
diff --git a/core/java/android/hardware/input/VirtualTouchscreenConfig.java b/core/java/android/hardware/input/VirtualTouchscreenConfig.java
new file mode 100644
index 0000000..e358619
--- /dev/null
+++ b/core/java/android/hardware/input/VirtualTouchscreenConfig.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.hardware.input;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Configurations to create virtual touchscreen.
+ *
+ * @hide
+ */
+@SystemApi
+public final class VirtualTouchscreenConfig extends VirtualInputDeviceConfig implements Parcelable {
+
+    /** The touchscreen width in pixels. */
+    private final int mWidthInPixels;
+    /** The touchscreen height in pixels. */
+    private final int mHeightInPixels;
+
+    private VirtualTouchscreenConfig(@NonNull Builder builder) {
+        super(builder);
+        mWidthInPixels = builder.mWidthInPixels;
+        mHeightInPixels = builder.mHeightInPixels;
+    }
+
+    private VirtualTouchscreenConfig(@NonNull Parcel in) {
+        super(in);
+        mWidthInPixels = in.readInt();
+        mHeightInPixels = in.readInt();
+    }
+
+    /** Returns the touchscreen width in pixels. */
+    public int getWidthInPixels() {
+        return mWidthInPixels;
+    }
+
+    /** Returns the touchscreen height in pixels. */
+    public int getHeightInPixels() {
+        return mHeightInPixels;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mWidthInPixels);
+        dest.writeInt(mHeightInPixels);
+    }
+
+    @NonNull
+    public static final Creator<VirtualTouchscreenConfig> CREATOR =
+            new Creator<VirtualTouchscreenConfig>() {
+                @Override
+                public VirtualTouchscreenConfig createFromParcel(Parcel in) {
+                    return new VirtualTouchscreenConfig(in);
+                }
+
+                @Override
+                public VirtualTouchscreenConfig[] newArray(int size) {
+                    return new VirtualTouchscreenConfig[size];
+                }
+            };
+
+    /**
+     * Builder for creating a {@link VirtualTouchscreenConfig}.
+     */
+    public static final class Builder extends VirtualInputDeviceConfig.Builder<Builder> {
+        private int mWidthInPixels;
+        private int mHeightInPixels;
+
+        /**
+         * @see VirtualTouchscreenConfig#getWidthInPixels().
+         */
+        @NonNull
+        public Builder setWidthInPixels(int widthInPixels) {
+            mWidthInPixels = widthInPixels;
+            return this;
+        }
+
+        /**
+         * @see VirtualTouchscreenConfig#getHeightInPixels().
+         */
+        @NonNull
+        public Builder setHeightInPixels(int heightInPixels) {
+            mHeightInPixels = heightInPixels;
+            return this;
+        }
+
+        /**
+         * Builds the {@link VirtualTouchscreenConfig} instance.
+         */
+        @NonNull
+        public VirtualTouchscreenConfig build() {
+            return new VirtualTouchscreenConfig(this);
+        }
+    }
+}
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index b54da6c..ac23af4 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -24,6 +24,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
 import android.content.Context;
@@ -966,6 +967,34 @@
     }
 
     /**
+     * Queries for the list of preloaded nanoapp IDs on the system.
+     *
+     * @param hubInfo The Context Hub to query a list of nanoapp IDs from.
+     *
+     * @return The list of 64-bit IDs of the preloaded nanoapps.
+     *
+     * @throws NullPointerException if hubInfo is null
+     * @hide
+     */
+    @TestApi
+    @RequiresPermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    @NonNull public long[] getPreloadedNanoAppIds(@NonNull ContextHubInfo hubInfo) {
+        Objects.requireNonNull(hubInfo, "hubInfo cannot be null");
+
+        long[] nanoappIds = null;
+        try {
+            nanoappIds = mService.getPreloadedNanoAppIds(hubInfo);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        if (nanoappIds == null) {
+            nanoappIds = new long[0];
+        }
+        return nanoappIds;
+    }
+
+    /**
      * Unregister a callback for receive messages from the context hub.
      *
      * @see Callback
diff --git a/core/java/android/hardware/location/IContextHubService.aidl b/core/java/android/hardware/location/IContextHubService.aidl
index ced75c4..490267f 100644
--- a/core/java/android/hardware/location/IContextHubService.aidl
+++ b/core/java/android/hardware/location/IContextHubService.aidl
@@ -109,4 +109,8 @@
     // Queries for a list of nanoapps
     @EnforcePermission("ACCESS_CONTEXT_HUB")
     void queryNanoApps(int contextHubId, in IContextHubTransactionCallback transactionCallback);
+
+    // Queries for a list of preloaded nanoapps
+    @EnforcePermission("ACCESS_CONTEXT_HUB")
+    long[] getPreloadedNanoAppIds(in ContextHubInfo hubInfo);
 }
diff --git a/core/java/android/hardware/radio/ProgramList.java b/core/java/android/hardware/radio/ProgramList.java
index ade9fd6..b2dfd85 100644
--- a/core/java/android/hardware/radio/ProgramList.java
+++ b/core/java/android/hardware/radio/ProgramList.java
@@ -24,6 +24,8 @@
 import android.os.Parcelable;
 import android.util.ArrayMap;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -41,14 +43,25 @@
 public final class ProgramList implements AutoCloseable {
 
     private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
     private final Map<ProgramSelector.Identifier, RadioManager.ProgramInfo> mPrograms =
             new ArrayMap<>();
 
+    @GuardedBy("mLock")
     private final List<ListCallback> mListCallbacks = new ArrayList<>();
+
+    @GuardedBy("mLock")
     private final List<OnCompleteListener> mOnCompleteListeners = new ArrayList<>();
+
+    @GuardedBy("mLock")
     private OnCloseListener mOnCloseListener;
-    private boolean mIsClosed = false;
-    private boolean mIsComplete = false;
+
+    @GuardedBy("mLock")
+    private boolean mIsClosed;
+
+    @GuardedBy("mLock")
+    private boolean mIsComplete;
 
     ProgramList() {}
 
@@ -227,6 +240,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void putLocked(RadioManager.ProgramInfo value,
             List<ProgramSelector.Identifier> changedIdentifierList) {
         ProgramSelector.Identifier key = value.getSelector().getPrimaryId();
@@ -235,6 +249,7 @@
         changedIdentifierList.add(sel);
     }
 
+    @GuardedBy("mLock")
     private void removeLocked(ProgramSelector.Identifier key,
             List<ProgramSelector.Identifier> removedIdentifierList) {
         RadioManager.ProgramInfo removed = mPrograms.remove(Objects.requireNonNull(key));
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 51236fe3..248b5d0 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -122,10 +122,10 @@
     boolean isFunctionEnabled(String function);
 
     /* Sets the current USB function. */
-    void setCurrentFunctions(long functions);
+    void setCurrentFunctions(long functions, int operationId);
 
     /* Compatibility version of setCurrentFunctions(long). */
-    void setCurrentFunction(String function, boolean usbDataUnlocked);
+    void setCurrentFunction(String function, boolean usbDataUnlocked, int operationId);
 
     /* Gets the current USB functions. */
     long getCurrentFunctions();
diff --git a/core/java/android/hardware/usb/ParcelableUsbPort.java b/core/java/android/hardware/usb/ParcelableUsbPort.java
index 19655ed..7fc282c 100644
--- a/core/java/android/hardware/usb/ParcelableUsbPort.java
+++ b/core/java/android/hardware/usb/ParcelableUsbPort.java
@@ -34,11 +34,13 @@
     private final int mSupportedContaminantProtectionModes;
     private final boolean mSupportsEnableContaminantPresenceProtection;
     private final boolean mSupportsEnableContaminantPresenceDetection;
+    private final boolean mSupportsComplianceWarnings;
 
     private ParcelableUsbPort(@NonNull String id, int supportedModes,
             int supportedContaminantProtectionModes,
             boolean supportsEnableContaminantPresenceProtection,
-            boolean supportsEnableContaminantPresenceDetection) {
+            boolean supportsEnableContaminantPresenceDetection,
+            boolean supportsComplianceWarnings) {
         mId = id;
         mSupportedModes = supportedModes;
         mSupportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -46,6 +48,8 @@
                 supportsEnableContaminantPresenceProtection;
         mSupportsEnableContaminantPresenceDetection =
                 supportsEnableContaminantPresenceDetection;
+        mSupportsComplianceWarnings =
+                supportsComplianceWarnings;
     }
 
     /**
@@ -59,7 +63,8 @@
         return new ParcelableUsbPort(port.getId(), port.getSupportedModes(),
                 port.getSupportedContaminantProtectionModes(),
                 port.supportsEnableContaminantPresenceProtection(),
-                port.supportsEnableContaminantPresenceDetection());
+                port.supportsEnableContaminantPresenceDetection(),
+                port.supportsComplianceWarnings());
     }
 
     /**
@@ -72,7 +77,8 @@
     public @NonNull UsbPort getUsbPort(@NonNull UsbManager usbManager) {
         return new UsbPort(usbManager, mId, mSupportedModes, mSupportedContaminantProtectionModes,
                 mSupportsEnableContaminantPresenceProtection,
-                mSupportsEnableContaminantPresenceDetection);
+                mSupportsEnableContaminantPresenceDetection,
+                mSupportsComplianceWarnings);
     }
 
     @Override
@@ -87,6 +93,7 @@
         dest.writeInt(mSupportedContaminantProtectionModes);
         dest.writeBoolean(mSupportsEnableContaminantPresenceProtection);
         dest.writeBoolean(mSupportsEnableContaminantPresenceDetection);
+        dest.writeBoolean(mSupportsComplianceWarnings);
     }
 
     public static final @android.annotation.NonNull Creator<ParcelableUsbPort> CREATOR =
@@ -98,11 +105,13 @@
                     int supportedContaminantProtectionModes = in.readInt();
                     boolean supportsEnableContaminantPresenceProtection = in.readBoolean();
                     boolean supportsEnableContaminantPresenceDetection = in.readBoolean();
+                    boolean supportsComplianceWarnings = in.readBoolean();
 
                     return new ParcelableUsbPort(id, supportedModes,
                             supportedContaminantProtectionModes,
                             supportsEnableContaminantPresenceProtection,
-                            supportsEnableContaminantPresenceDetection);
+                            supportsEnableContaminantPresenceDetection,
+                            supportsComplianceWarnings);
                 }
 
                 @Override
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 50dd0064..7a8117c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -38,6 +38,7 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
 import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
@@ -52,6 +53,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * This class allows you to access the state of USB and communicate with USB devices.
@@ -95,7 +97,7 @@
      * If the sticky intent has not been found, that indicates USB is disconnected,
      * USB is not configued, MTP function is enabled, and all the other functions are disabled.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String ACTION_USB_STATE =
@@ -113,6 +115,19 @@
     public static final String ACTION_USB_PORT_CHANGED =
             "android.hardware.usb.action.USB_PORT_CHANGED";
 
+     /**
+     * Broadcast Action: A broadcast for USB compliance warning changes.
+     *
+     * This intent is sent when a port partner's
+     * (USB power source/cable/accessory) compliance warnings change state.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public static final String ACTION_USB_PORT_COMPLIANCE_CHANGED =
+            "android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED";
+
    /**
      * Activity intent sent when user attaches a USB device.
      *
@@ -172,7 +187,7 @@
      * <p>For more information about communicating with USB accessory handshake, refer to
      * <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
      *
-     * {@hide}
+     * @hide
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @SystemApi
@@ -184,7 +199,7 @@
      * Boolean extra indicating whether USB is connected or disconnected.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_CONNECTED = "connected";
@@ -193,7 +208,7 @@
      * Boolean extra indicating whether USB is connected or disconnected as host.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_HOST_CONNECTED = "host_connected";
 
@@ -201,7 +216,7 @@
      * Boolean extra indicating whether USB is configured.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_CONFIGURED = "configured";
@@ -212,7 +227,7 @@
      * has explicitly asked for this data to be unlocked.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
      *
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static final String USB_DATA_UNLOCKED = "unlocked";
@@ -221,7 +236,7 @@
      * A placeholder indicating that no USB function is being specified.
      * Used for compatibility with old init scripts to indicate no functions vs. charging function.
      *
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage
     public static final String USB_FUNCTION_NONE = "none";
@@ -230,7 +245,7 @@
      * Name of the adb USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_ADB = "adb";
 
@@ -238,7 +253,7 @@
      * Name of the RNDIS ethernet USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_FUNCTION_RNDIS = "rndis";
@@ -247,7 +262,7 @@
      * Name of the MTP USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_MTP = "mtp";
 
@@ -255,7 +270,7 @@
      * Name of the PTP USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_PTP = "ptp";
 
@@ -263,7 +278,7 @@
      * Name of the audio source USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
 
@@ -271,7 +286,7 @@
      * Name of the MIDI USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_MIDI = "midi";
 
@@ -279,7 +294,7 @@
      * Name of the Accessory USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     public static final String USB_FUNCTION_ACCESSORY = "accessory";
 
@@ -287,7 +302,7 @@
      * Name of the NCM USB function.
      * Used in extras for the {@link #ACTION_USB_STATE} broadcast
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String USB_FUNCTION_NCM = "ncm";
@@ -295,32 +310,39 @@
     /**
      * Name of Gadget Hal Not Present;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_UNKNOWN = "unknown";
 
     /**
      * Name of the USB Gadget Hal Version v1.0;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_0 = "V1_0";
 
     /**
      * Name of the USB Gadget Hal Version v1.1;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_1 = "V1_1";
 
     /**
      * Name of the USB Gadget Hal Version v1.2;
      *
-     * {@hide}
+     * @hide
      */
     public static final String GADGET_HAL_VERSION_1_2 = "V1_2";
 
     /**
+     * Name of the USB Gadget Hal Version v2.0;
+     *
+     * @hide
+     */
+    public static final String GADGET_HAL_VERSION_2_0 = "V2_0";
+
+    /**
      * Name of extra for {@link #ACTION_USB_PORT_CHANGED}
      * containing the {@link UsbPort} object for the port.
      *
@@ -356,7 +378,7 @@
      * This is obtained with SystemClock.elapsedRealtime()
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_UEVENT_TIME =
@@ -370,7 +392,7 @@
      * between communicating with USB accessory handshake, refer to
      * <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_STRING_COUNT =
@@ -380,7 +402,7 @@
      * Boolean extra indicating whether got start accessory or not
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_START =
@@ -392,7 +414,7 @@
      * sending {@link #ACTION_USB_ACCESSORY_HANDSHAKE}.
      * Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final String EXTRA_ACCESSORY_HANDSHAKE_END =
@@ -426,7 +448,7 @@
     /**
      * The Value for USB gadget hal is not presented.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_NOT_SUPPORTED = -1;
@@ -434,7 +456,7 @@
     /**
      * Value for Gadget Hal Version v1.0.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_0 = 10;
@@ -442,7 +464,7 @@
     /**
      * Value for Gadget Hal Version v1.1.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_1 = 11;
@@ -450,15 +472,23 @@
     /**
      * Value for Gadget Hal Version v1.2.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int GADGET_HAL_V1_2 = 12;
 
     /**
+     * Value for Gadget Hal Version v2.0.
+     *
+     * @hide
+     */
+    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+    public static final int GADGET_HAL_V2_0 = 20;
+
+    /**
      * Value for USB_STATE is not configured.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1;
@@ -466,7 +496,7 @@
     /**
      * Value for USB Transfer Rate of Low Speed in Mbps (real value is 1.5Mbps).
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2;
@@ -474,7 +504,7 @@
     /**
      * Value for USB Transfer Rate of Full Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_FULL_SPEED = 12;
@@ -482,7 +512,7 @@
     /**
      * Value for USB Transfer Rate of High Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_HIGH_SPEED = 480;
@@ -490,7 +520,7 @@
     /**
      * Value for USB Transfer Rate of Super Speed in Mbps.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_5G = 5 * 1024;
@@ -498,7 +528,7 @@
     /**
      * Value for USB Transfer Rate of 10G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_10G = 10 * 1024;
@@ -506,7 +536,7 @@
     /**
      * Value for USB Transfer Rate of 20G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_20G = 20 * 1024;
@@ -514,7 +544,7 @@
     /**
      * Value for USB Transfer Rate of 40G.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
@@ -530,7 +560,7 @@
     /**
      * The Value for USB hal is not presented.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_NOT_SUPPORTED = -1;
@@ -538,7 +568,7 @@
     /**
      * Value for USB Hal Version v1.0.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_0 = 10;
@@ -546,7 +576,7 @@
     /**
      * Value for USB Hal Version v1.1.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_1 = 11;
@@ -554,7 +584,7 @@
     /**
      * Value for USB Hal Version v1.2.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_2 = 12;
@@ -562,7 +592,7 @@
     /**
      * Value for USB Hal Version v1.3.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     public static final int USB_HAL_V1_3 = 13;
@@ -577,63 +607,63 @@
 
     /**
      * Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_NONE = 0;
 
     /**
      * Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_MTP = GadgetFunction.MTP;
 
     /**
      * Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_PTP = GadgetFunction.PTP;
 
     /**
      * Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
 
     /**
      * Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
 
     /**
      * Code for the accessory usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
 
     /**
      * Code for the audio source usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
 
     /**
      * Code for the adb usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_ADB = GadgetFunction.ADB;
 
     /**
      * Code for the ncm source usb function.
-     * {@hide}
+     * @hide
      */
     @SystemApi
     public static final long FUNCTION_NCM = 1 << 10;
@@ -643,6 +673,11 @@
 
     private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     static {
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP);
         FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP);
@@ -674,6 +709,7 @@
             GADGET_HAL_V1_0,
             GADGET_HAL_V1_1,
             GADGET_HAL_V1_2,
+            GADGET_HAL_V2_0,
     })
     public @interface UsbGadgetHalVersion {}
 
@@ -692,7 +728,7 @@
     private final IUsbManager mService;
 
     /**
-     * {@hide}
+     * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public UsbManager(Context context, IUsbManager service) {
@@ -803,7 +839,7 @@
      * {@link #FUNCTION_PTP} are supported.
      * @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
      *
-     * {@hide}
+     * @hide
      */
     public ParcelFileDescriptor getControlFd(long function) {
         try {
@@ -964,7 +1000,7 @@
      * Only system components can call this function.
      * @param device to request permissions for
      *
-     * {@hide}
+     * @hide
      */
     public void grantPermission(UsbDevice device) {
         grantPermission(device, Process.myUid());
@@ -976,7 +1012,7 @@
      * @param device to request permissions for
      * @uid uid to give permission
      *
-     * {@hide}
+     * @hide
      */
     public void grantPermission(UsbDevice device, int uid) {
         try {
@@ -992,7 +1028,7 @@
      * @param device to request permissions for
      * @param packageName of package to grant permissions
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1017,7 +1053,7 @@
      * @param function name of the USB function
      * @return true if the USB function is enabled
      *
-     * {@hide}
+     * @hide
      */
     @Deprecated
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1049,14 +1085,17 @@
      * @param functions the USB function(s) to set, as a bitwise mask.
      *                  Must satisfy {@link UsbManager#areSettableFunctions}
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
     public void setCurrentFunctions(@UsbFunctionMode long functions) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
-            mService.setCurrentFunctions(functions);
+            mService.setCurrentFunctions(functions, operationId);
         } catch (RemoteException e) {
+            Log.e(TAG, "setCurrentFunctions: failed to call setCurrentFunctions. functions:"
+                        + functions + ", opId:" + operationId, e);
             throw e.rethrowFromSystemServer();
         }
     }
@@ -1068,14 +1107,17 @@
      * @param functions the USB function(s) to set.
      * @param usbDataUnlocked unused
 
-     * {@hide}
+     * @hide
      */
     @Deprecated
     @UnsupportedAppUsage
     public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
-            mService.setCurrentFunction(functions, usbDataUnlocked);
+            mService.setCurrentFunction(functions, usbDataUnlocked, operationId);
         } catch (RemoteException e) {
+            Log.e(TAG, "setCurrentFunction: failed to call setCurrentFunction. functions:"
+                        + functions + ", opId:" + operationId, e);
             throw e.rethrowFromSystemServer();
         }
     }
@@ -1090,7 +1132,7 @@
      * @return The currently enabled functions, in a bitwise mask.
      * A zero mask indicates that the current function is the charging function.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1116,7 +1158,7 @@
      * @param functions functions to set, in a bitwise mask.
      *                  Must satisfy {@link UsbManager#areSettableFunctions}
      *
-     * {@hide}
+     * @hide
      */
     public void setScreenUnlockedFunctions(long functions) {
         try {
@@ -1132,7 +1174,7 @@
      * @return The currently set screen enabled functions.
      * A zero mask indicates that the screen unlocked functions feature is not enabled.
      *
-     * {@hide}
+     * @hide
      */
     public long getScreenUnlockedFunctions() {
         try {
@@ -1154,19 +1196,17 @@
      *
      * @return The value of currently USB Bandwidth.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
     public int getUsbBandwidthMbps() {
         int usbSpeed;
-
         try {
             usbSpeed = mService.getCurrentUsbSpeed();
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
-
         return usbSpeedToBandwidth(usbSpeed);
     }
 
@@ -1178,7 +1218,7 @@
      *
      * @return a integer {@code GADGET_HAL_*} represent hal version.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1198,7 +1238,7 @@
      *
      * @return a integer {@code USB_HAL_*} represent hal version.
      *
-     * {@hide}
+     * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
     @RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1494,7 +1534,7 @@
      * @param usbDeviceConnectionHandler The component to handle usb connections,
      * {@code null} to unset.
      *
-     * {@hide}
+     * @hide
      */
     public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
         try {
@@ -1513,7 +1553,7 @@
      *
      * @return Whether the mask is settable.
      *
-     * {@hide}
+     * @hide
      */
     public static boolean areSettableFunctions(long functions) {
         return functions == FUNCTION_NONE
@@ -1527,7 +1567,7 @@
      *
      * @return String representation of given mask
      *
-     * {@hide}
+     * @hide
      */
     public static String usbFunctionsToString(long functions) {
         StringJoiner joiner = new StringJoiner(",");
@@ -1563,7 +1603,7 @@
      *
      * @return A mask of all valid functions in the string
      *
-     * {@hide}
+     * @hide
      */
     public static long usbFunctionsFromString(String functions) {
         if (functions == null || functions.equals(USB_FUNCTION_NONE)) {
@@ -1585,7 +1625,7 @@
      *
      * @return a value of USB bandwidth
      *
-     * {@hide}
+     * @hide
      */
     public static int usbSpeedToBandwidth(int speed) {
         switch (speed) {
@@ -1619,12 +1659,14 @@
      *
      * @return String representation of Usb Gadget Hal Version
      *
-     * {@hide}
+     * @hide
      */
     public static @NonNull String usbGadgetHalVersionToString(int version) {
         String halVersion;
 
-        if (version == GADGET_HAL_V1_2) {
+        if (version == GADGET_HAL_V2_0) {
+            halVersion = GADGET_HAL_VERSION_2_0;
+        } else if (version == GADGET_HAL_V1_2) {
             halVersion = GADGET_HAL_VERSION_1_2;
         } else if (version == GADGET_HAL_V1_1) {
             halVersion = GADGET_HAL_VERSION_1_1;
diff --git a/core/java/android/hardware/usb/UsbPort.java b/core/java/android/hardware/usb/UsbPort.java
index 7c5a4c6..e0f9cad 100644
--- a/core/java/android/hardware/usb/UsbPort.java
+++ b/core/java/android/hardware/usb/UsbPort.java
@@ -46,6 +46,10 @@
 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DOCK;
 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_FORCE;
 import static android.hardware.usb.UsbPortStatus.DATA_STATUS_DISABLED_DEBUG;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_BC_1_2;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP;
+import static android.hardware.usb.UsbPortStatus.COMPLIANCE_WARNING_OTHER;
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
@@ -83,6 +87,7 @@
     private final int mSupportedContaminantProtectionModes;
     private final boolean mSupportsEnableContaminantPresenceProtection;
     private final boolean mSupportsEnableContaminantPresenceDetection;
+    private final boolean mSupportsComplianceWarnings;
 
     private static final int NUM_DATA_ROLES = Constants.PortDataRole.NUM_DATA_ROLES;
     /**
@@ -250,6 +255,18 @@
             int supportedContaminantProtectionModes,
             boolean supportsEnableContaminantPresenceProtection,
             boolean supportsEnableContaminantPresenceDetection) {
+        this(usbManager, id, supportedModes, supportedContaminantProtectionModes,
+                supportsEnableContaminantPresenceProtection,
+                supportsEnableContaminantPresenceDetection,
+                false);
+    }
+
+    /** @hide */
+    public UsbPort(@NonNull UsbManager usbManager, @NonNull String id, int supportedModes,
+            int supportedContaminantProtectionModes,
+            boolean supportsEnableContaminantPresenceProtection,
+            boolean supportsEnableContaminantPresenceDetection,
+            boolean supportsComplianceWarnings) {
         Objects.requireNonNull(id);
         Preconditions.checkFlagsArgument(supportedModes,
                 MODE_DFP | MODE_UFP | MODE_AUDIO_ACCESSORY | MODE_DEBUG_ACCESSORY);
@@ -262,6 +279,7 @@
                 supportsEnableContaminantPresenceProtection;
         mSupportsEnableContaminantPresenceDetection =
                 supportsEnableContaminantPresenceDetection;
+        mSupportsComplianceWarnings = supportsComplianceWarnings;
     }
 
     /**
@@ -331,6 +349,21 @@
     }
 
     /**
+     * Queries USB Port to see if the port is capable of identifying
+     * non compliant USB power source/cable/accessory.
+     *
+     * @return true when the UsbPort is capable of identifying
+     *             non compliant USB power
+     *             source/cable/accessory.
+     * @return false otherwise.
+     */
+    @CheckResult
+    @RequiresPermission(Manifest.permission.MANAGE_USB)
+    public boolean supportsComplianceWarnings() {
+        return mSupportsComplianceWarnings;
+    }
+
+    /**
      * Sets the desired role combination of the port.
      * <p>
      * The supported role combinations depend on what is connected to the port and may be
@@ -686,6 +719,37 @@
     }
 
     /** @hide */
+    public static String complianceWarningsToString(@NonNull int[] complianceWarnings) {
+        StringBuilder complianceWarningString = new StringBuilder();
+        complianceWarningString.append("[");
+
+        if (complianceWarnings != null) {
+            for (int warning : complianceWarnings) {
+                switch (warning) {
+                    case UsbPortStatus.COMPLIANCE_WARNING_OTHER:
+                        complianceWarningString.append("other, ");
+                        break;
+                    case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY:
+                        complianceWarningString.append("debug accessory, ");
+                        break;
+                    case UsbPortStatus.COMPLIANCE_WARNING_BC_1_2:
+                        complianceWarningString.append("bc12, ");
+                        break;
+                    case UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP:
+                        complianceWarningString.append("missing rp, ");
+                        break;
+                    default:
+                        complianceWarningString.append(String.format("Unknown(%d), ", warning));
+                        break;
+                }
+            }
+        }
+
+        complianceWarningString.append("]");
+        return complianceWarningString.toString().replaceAll(", ]$", "]");
+    }
+
+    /** @hide */
     public static void checkMode(int powerRole) {
         Preconditions.checkArgumentInRange(powerRole, Constants.PortMode.NONE,
                 Constants.PortMode.NUM_MODES - 1, "portMode");
@@ -720,10 +784,12 @@
     @Override
     public String toString() {
         return "UsbPort{id=" + mId + ", supportedModes=" + modeToString(mSupportedModes)
-                + "supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes
-                + "supportsEnableContaminantPresenceProtection="
+                + ", supportedContaminantProtectionModes=" + mSupportedContaminantProtectionModes
+                + ", supportsEnableContaminantPresenceProtection="
                 + mSupportsEnableContaminantPresenceProtection
-                + "supportsEnableContaminantPresenceDetection="
-                + mSupportsEnableContaminantPresenceDetection;
+                + ", supportsEnableContaminantPresenceDetection="
+                + mSupportsEnableContaminantPresenceDetection
+                + ", supportsComplianceWarnings="
+                + mSupportsComplianceWarnings;
     }
 }
diff --git a/core/java/android/hardware/usb/UsbPortStatus.java b/core/java/android/hardware/usb/UsbPortStatus.java
index 3221ec8..ed3e40d 100644
--- a/core/java/android/hardware/usb/UsbPortStatus.java
+++ b/core/java/android/hardware/usb/UsbPortStatus.java
@@ -16,9 +16,11 @@
 
 package android.hardware.usb;
 
+import android.Manifest;
+import android.annotation.CheckResult;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -46,6 +48,7 @@
     private final boolean mPowerTransferLimited;
     private final @UsbDataStatus int mUsbDataStatus;
     private final @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
+    private final @NonNull @ComplianceWarning int[] mComplianceWarnings;
 
     /**
      * Power role: This USB port does not have a power role.
@@ -246,6 +249,41 @@
      */
     public static final int POWER_BRICK_STATUS_DISCONNECTED = 2;
 
+    /**
+     * Used to indicate attached sources/cables/accessories/ports
+     * that do not match the other warnings below and do not meet the
+     * requirements of specifications including but not limited to
+     * USB Type-C Cable and Connector, Universal Serial Bus
+     * Power Delivery, and Universal Serial Bus 1.x/2.0/3.x/4.0.
+     * In addition, constants introduced after the target sdk will be
+     * remapped into COMPLIANCE_WARNING_OTHER.
+     */
+    public static final int COMPLIANCE_WARNING_OTHER = 1;
+
+    /**
+     * Used to indicate Type-C port partner
+     * (cable/accessory/source) that identifies itself as debug
+     * accessory source as defined in USB Type-C Cable and
+     * Connector Specification. However, the specification states
+     * that this is meant for debug only and shall not be used for
+     * with commercial products.
+     */
+    public static final int COMPLIANCE_WARNING_DEBUG_ACCESSORY = 2;
+
+    /**
+     * Used to indicate USB ports that does not
+     * identify itself as one of the charging port types (SDP/CDP
+     * DCP etc) as defined by Battery Charging v1.2 Specification.
+     */
+    public static final int COMPLIANCE_WARNING_BC_1_2 = 3;
+
+    /**
+     * Used to indicate Type-C sources/cables that are missing pull
+     * up resistors on the CC pins as required by USB Type-C Cable
+     * and Connector Specification.
+     */
+    public static final int COMPLIANCE_WARNING_MISSING_RP = 4;
+
     @IntDef(prefix = { "CONTAMINANT_DETECTION_" }, value = {
             CONTAMINANT_DETECTION_NOT_SUPPORTED,
             CONTAMINANT_DETECTION_DISABLED,
@@ -275,6 +313,15 @@
     @Retention(RetentionPolicy.SOURCE)
     @interface UsbPortMode{}
 
+    @IntDef(prefix = { "COMPLIANCE_WARNING_" }, value = {
+            COMPLIANCE_WARNING_OTHER,
+            COMPLIANCE_WARNING_DEBUG_ACCESSORY,
+            COMPLIANCE_WARNING_BC_1_2,
+            COMPLIANCE_WARNING_MISSING_RP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface ComplianceWarning{}
+
     /** @hide */
     @IntDef(prefix = { "DATA_STATUS_" }, flag = true, value = {
             DATA_STATUS_UNKNOWN,
@@ -302,7 +349,8 @@
             int supportedRoleCombinations, int contaminantProtectionStatus,
             int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
             boolean powerTransferLimited,
-            @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
+            @PowerBrickConnectionStatus int powerBrickConnectionStatus,
+            @NonNull @ComplianceWarning int[] complianceWarnings) {
         mCurrentMode = currentMode;
         mCurrentPowerRole = currentPowerRole;
         mCurrentDataRole = currentDataRole;
@@ -312,21 +360,29 @@
         mUsbDataStatus = usbDataStatus;
         mPowerTransferLimited = powerTransferLimited;
         mPowerBrickConnectionStatus = powerBrickConnectionStatus;
+        mComplianceWarnings = complianceWarnings;
+    }
+
+    /** @hide */
+    public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
+            int supportedRoleCombinations, int contaminantProtectionStatus,
+            int contaminantDetectionStatus, @UsbDataStatus int usbDataStatus,
+            boolean powerTransferLimited,
+            @PowerBrickConnectionStatus int powerBrickConnectionStatus) {
+        this(currentMode, currentPowerRole, currentDataRole, supportedRoleCombinations,
+                contaminantProtectionStatus, contaminantDetectionStatus,
+                usbDataStatus, powerTransferLimited, powerBrickConnectionStatus,
+                new int[] {});
     }
 
     /** @hide */
     public UsbPortStatus(int currentMode, int currentPowerRole, int currentDataRole,
             int supportedRoleCombinations, int contaminantProtectionStatus,
             int contaminantDetectionStatus) {
-        mCurrentMode = currentMode;
-        mCurrentPowerRole = currentPowerRole;
-        mCurrentDataRole = currentDataRole;
-        mSupportedRoleCombinations = supportedRoleCombinations;
-        mContaminantProtectionStatus = contaminantProtectionStatus;
-        mContaminantDetectionStatus = contaminantDetectionStatus;
-        mUsbDataStatus = DATA_STATUS_UNKNOWN;
-        mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
-        mPowerTransferLimited = false;
+        this(currentMode, currentPowerRole, currentDataRole, supportedRoleCombinations,
+                contaminantProtectionStatus, contaminantDetectionStatus,
+                DATA_STATUS_UNKNOWN, false, POWER_BRICK_STATUS_UNKNOWN,
+                new int[] {});
     }
 
     /**
@@ -443,6 +499,21 @@
         return mPowerBrickConnectionStatus;
     }
 
+    /**
+     * Returns non compliant reasons, if any, for the connected
+     * charger/cable/accessory/USB port.
+     *
+     * @return array including {@link #NON_COMPLIANT_REASON_DEBUG_ACCESSORY},
+     *         {@link #NON_COMPLIANT_REASON_BC12},
+     *         {@link #NON_COMPLIANT_REASON_MISSING_RP},
+     *         or {@link #NON_COMPLIANT_REASON_TYPEC}
+     */
+    @CheckResult
+    @NonNull
+    public @ComplianceWarning int[] getComplianceWarnings() {
+        return mComplianceWarnings;
+    }
+
     @NonNull
     @Override
     public String toString() {
@@ -460,9 +531,11 @@
                         + UsbPort.usbDataStatusToString(getUsbDataStatus())
                 + ", isPowerTransferLimited="
                         + isPowerTransferLimited()
-                +", powerBrickConnectionStatus="
+                + ", powerBrickConnectionStatus="
                         + UsbPort
                             .powerBrickConnectionStatusToString(getPowerBrickConnectionStatus())
+                + ", complianceWarnings="
+                        + UsbPort.complianceWarningsToString(getComplianceWarnings())
                 + "}";
     }
 
@@ -482,6 +555,7 @@
         dest.writeInt(mUsbDataStatus);
         dest.writeBoolean(mPowerTransferLimited);
         dest.writeInt(mPowerBrickConnectionStatus);
+        dest.writeIntArray(mComplianceWarnings);
     }
 
     public static final @NonNull Parcelable.Creator<UsbPortStatus> CREATOR =
@@ -497,10 +571,12 @@
             int usbDataStatus = in.readInt();
             boolean powerTransferLimited = in.readBoolean();
             int powerBrickConnectionStatus = in.readInt();
+            @ComplianceWarning int[] complianceWarnings = in.createIntArray();
             return new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus, powerTransferLimited,
-                    powerBrickConnectionStatus);
+                    powerBrickConnectionStatus,
+                    complianceWarnings);
         }
 
         @Override
@@ -524,6 +600,7 @@
         private boolean mPowerTransferLimited;
         private @UsbDataStatus int mUsbDataStatus;
         private @PowerBrickConnectionStatus int mPowerBrickConnectionStatus;
+        private @ComplianceWarning int[] mComplianceWarnings;
 
         public Builder() {
             mCurrentMode = MODE_NONE;
@@ -533,6 +610,7 @@
             mContaminantDetectionStatus = CONTAMINANT_DETECTION_NOT_SUPPORTED;
             mUsbDataStatus = DATA_STATUS_UNKNOWN;
             mPowerBrickConnectionStatus = POWER_BRICK_STATUS_UNKNOWN;
+            mComplianceWarnings = new int[] {};
         }
 
         /**
@@ -619,6 +697,20 @@
         }
 
         /**
+         * Sets the non-compliant charger reasons of {@link UsbPortStatus}
+         *
+         * @return Instance of {@link Builder}
+         */
+        @NonNull
+        public Builder setComplianceWarnings(
+                @NonNull int[] complianceWarnings) {
+            mComplianceWarnings = complianceWarnings == null ? new int[] {} :
+                    complianceWarnings;
+            return this;
+        }
+
+
+        /**
          * Creates the {@link UsbPortStatus} object.
          */
         @NonNull
@@ -626,7 +718,7 @@
             UsbPortStatus status = new UsbPortStatus(mCurrentMode, mCurrentPowerRole,
                     mCurrentDataRole, mSupportedRoleCombinations, mContaminantProtectionStatus,
                     mContaminantDetectionStatus, mUsbDataStatus, mPowerTransferLimited,
-                    mPowerBrickConnectionStatus);
+                    mPowerBrickConnectionStatus, mComplianceWarnings);
             return status;
         }
     };
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index bf4fc4a..872414a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,11 +70,14 @@
 import android.compat.annotation.ChangeId;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -98,6 +101,7 @@
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.Xml;
 import android.util.proto.ProtoOutputStream;
 import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
 import android.view.Choreographer;
@@ -158,6 +162,8 @@
 import com.android.internal.inputmethod.SoftInputShowHideReason;
 import com.android.internal.util.RingBuffer;
 
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
@@ -730,7 +736,6 @@
         @Override
         public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
-            mConfigTracker.onInitialize(params.configChanges);
             mPrivOps.set(params.privilegedOperations);
             InputMethodPrivilegedOperationsRegistry.put(params.token, mPrivOps);
             mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags);
@@ -1601,6 +1606,8 @@
         mHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_hideNavBarForKeyboard);
 
+        initConfigurationTracker();
+
         // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
         // for update resources & configuration correctly when show soft input
         // in non-default display.
@@ -1656,6 +1663,36 @@
         Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
+    private void initConfigurationTracker() {
+        final int flags = PackageManager.GET_META_DATA
+                | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        final ComponentName imeComponent = new ComponentName(
+                getPackageName(), getClass().getName());
+        final String imeId = imeComponent.flattenToShortString();
+        final ServiceInfo si;
+        try {
+            si = getPackageManager().getServiceInfo(imeComponent,
+                    PackageManager.ComponentInfoFlags.of(flags));
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.wtf(TAG, "Unable to find input method " + imeId, e);
+            return;
+        }
+        try (XmlResourceParser parser = si.loadXmlMetaData(getPackageManager(),
+                InputMethod.SERVICE_META_DATA);
+             TypedArray sa = getResources().obtainAttributes(Xml.asAttributeSet(parser),
+                     com.android.internal.R.styleable.InputMethod)) {
+            if (parser == null) {
+                throw new XmlPullParserException(
+                        "No " + InputMethod.SERVICE_META_DATA + " meta-data");
+            }
+            final int handledConfigChanges = sa.getInt(
+                    com.android.internal.R.styleable.InputMethod_configChanges, 0);
+            mConfigTracker.onInitialize(handledConfigChanges);
+        } catch (Exception e) {
+            Log.wtf(TAG, "Unable to load input method " + imeId, e);
+        }
+    }
+
     /**
      * This is a hook that subclasses can use to perform initialization of
      * their interface.  It is called for you prior to any of your UI objects
@@ -2766,12 +2803,12 @@
             return false;
         }
         if ((flags&InputMethod.SHOW_EXPLICIT) == 0) {
-            if (!configChange && onEvaluateFullscreenMode()) {
+            if (!configChange && onEvaluateFullscreenMode() && !isInputViewShown()) {
                 // Don't show if this is not explicitly requested by the user and
-                // the input method is fullscreen.  That would be too disruptive.
-                // However, we skip this change for a config change, since if
-                // the IME is already shown we do want to go into fullscreen
-                // mode at this point.
+                // the input method is fullscreen unless it is already shown. That
+                // would be too disruptive. However, we skip this change for a
+                // config change, since if the IME is already shown we do want to
+                // go into fullscreen mode at this point.
                 return false;
             }
             if (!mSettingsObserver.shouldShowImeWithHardKeyboard() &&
diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/core/java/android/nfc/AvailableNfcAntenna.java
index 946ba67..6e6512a 100644
--- a/core/java/android/nfc/AvailableNfcAntenna.java
+++ b/core/java/android/nfc/AvailableNfcAntenna.java
@@ -27,13 +27,15 @@
  */
 public final class AvailableNfcAntenna implements Parcelable {
     /**
-     * Location on the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen.
+     * Location of the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen
+     * and the device orientation is Portrait.
      */
     private final int mLocationX;
     /**
-     * Location on the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen.
+     * Location of the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen
+     * and the device orientation is Portrait.
      */
     private final int mLocationY;
 
@@ -43,16 +45,18 @@
     }
 
     /**
-     * Location on the antenna on the X axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen.
+     * Location of the antenna on the X axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen
+     * and the device orientation is Portrait.
      */
     public int getLocationX() {
         return mLocationX;
     }
 
     /**
-     * Location on the antenna on the Y axis in millimeters.
-     * 0 is the bottom-left when the user is facing the screen.
+     * Location of the antenna on the Y axis in millimeters.
+     * 0 is the bottom-left when the user is facing the screen
+     * and the device orientation is Portrait.
      */
     public int getLocationY() {
         return mLocationY;
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 8278e89..4c9ae37 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -355,6 +355,26 @@
     }
 
     /**
+     * Return the Linux UID assigned to the process that sent the transaction
+     * currently being processed.
+     *
+     * Logs WTF if the current thread is not currently
+     * executing an incoming transaction and the calling identity has not been
+     * explicitly set with {@link #clearCallingIdentity()}
+     *
+     * @hide
+     */
+    public static final int getCallingUidOrWtf() {
+        if (!isDirectlyHandlingTransaction() && !hasExplicitIdentity()) {
+            Log.wtf(TAG,
+                    "Thread is not in a binder transaction, "
+                            + "and the calling identity has not been "
+                            + "explicitly set with clearCallingIdentity");
+        }
+        return getCallingUid();
+    }
+
+    /**
      * Return the UserHandle assigned to the process that sent you the
      * current transaction that is being processed. This is the user
      * of the caller. It is distinct from {@link #getCallingUid()} in that a
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index a887f2a..d31540a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -58,6 +58,8 @@
     void setUserIcon(int userId, in Bitmap icon);
     ParcelFileDescriptor getUserIcon(int userId);
     UserInfo getPrimaryUser();
+    int getMainUserId();
+    int getPreviousFullUserToEnterForeground();
     List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated);
     List<UserInfo> getProfiles(int userId, boolean enabledOnly);
     int[] getProfileIds(int userId, boolean enabledOnly);
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 9ea4278..394927e 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -252,10 +252,12 @@
     }
 
     /**
-     * Returns the list of declared instances for an interface.
+     * Returns an array of all declared instances for a particular interface.
      *
-     * @return true if the service is declared somewhere (eg. VINTF manifest) and
-     * waitForService should always be able to return the service.
+     * For instance, if 'android.foo.IFoo/foo' is declared (e.g. in VINTF
+     * manifest), and 'android.foo.IFoo' is passed here, then ["foo"] would be
+     * returned.
+     *
      * @hide
      */
     @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index fb197f5..cdde18a 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -100,7 +100,7 @@
     /** @hide */
     public static final long TRACE_TAG_VIBRATOR = 1L << 23;
     /** @hide */
-    @SystemApi(client = MODULE_LIBRARIES)
+    @SystemApi
     public static final long TRACE_TAG_AIDL = 1L << 24;
     /** @hide */
     public static final long TRACE_TAG_NNAPI = 1L << 25;
@@ -241,9 +241,16 @@
     /**
      * Writes a trace message to indicate that a given section of code has
      * begun. Must be followed by a call to {@link #asyncTraceEnd} using the same
-     * tag. Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
-     * asynchronous events do not need to be nested. The name and cookie used to
-     * begin an event must be used to end it.
+     * tag, name and cookie.
+     *
+     * If two events with the same methodName overlap in time then they *must* have
+     * different cookie values. If they do not, the trace can become corrupted
+     * in unpredictable ways.
+     *
+     * Unlike {@link #traceBegin(long, String)} and {@link #traceEnd(long)},
+     * asynchronous events cannot be not nested. Consider using
+     * {@link #asyncTraceForTrackBegin(long, String, String, int)}
+     * if nested asynchronous events are needed.
      *
      * @param traceTag The trace tag.
      * @param methodName The method name to appear in the trace.
@@ -264,6 +271,9 @@
      * Must be called exactly once for each call to {@link #asyncTraceBegin(long, String, int)}
      * using the same tag, name and cookie.
      *
+     * See the documentation for {@link #asyncTraceBegin(long, String, int)}.
+     * for inteded usage of this method.
+     *
      * @param traceTag The trace tag.
      * @param methodName The method name to appear in the trace.
      * @param cookie Unique identifier for distinguishing simultaneous events
@@ -283,14 +293,73 @@
      * Writes a trace message to indicate that a given section of code has
      * begun. Must be followed by a call to {@link #asyncTraceForTrackEnd} using the same
      * track name and cookie.
-     * This function operates exactly like {@link #asyncTraceBegin(long, String, int)},
-     * except with the inclusion of a track name argument for where this method should appear.
-     * The cookie must be unique on the trackName level, not the methodName level
+     *
+     * Events with the same trackName and cookie nest inside each other in the
+     * same way as calls to {@link #traceBegin(long, String)} and
+     * {@link #traceEnd(long)}.
+     *
+     * If two events with the same trackName overlap in time but do not nest
+     * correctly, then they *must* have different cookie values. If they do not,
+     * the trace can become corrupted in unpredictable ways.
+     *
+     * Good Example:
+     *
+     * public void parent() {
+     *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "parent", mId);
+     *   child()
+     *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
+     * }
+     *
+     * public void child() {
+     *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "Track", "child", mId);
+     *   // Some code here.
+     *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "Track", mId);
+     * }
+     *
+     * This would be visualized as so:
+     *   [   Parent   ]
+     *     [ Child ]
+     *
+     * Bad Example:
+     *
+     * public static void processData(String dataToProcess) {
+     *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", 0);
+     *   // Some code here.
+     *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", 0);
+     * }
+     *
+     * public static void processDataInParallel({@code List<String>} data) {
+     *   ExecutorService executor = Executors.newCachedThreadPool();
+     *   for (String s : data) {
+     *     pool.execute(() -> processData(s));
+     *   }
+     * }
+     *
+     * This is invalid because it's possible for processData to be run many times
+     * in parallel (i.e. processData events overlap) but the same cookie is
+     * provided each time.
+     *
+     * To fix this, specify a different id in each invocation of processData:
+     *
+     * public static void processData(String dataToProcess, int id) {
+     *   asyncTraceForTrackBegin(TRACE_TAG_ALWAYS, "processDataInParallel", "processData", id);
+     *   // Some code here.
+     *   asyncTraceForTrackEnd(TRACE_TAG_ALWAYS, "processDataInParallel", id);
+     * }
+     *
+     * public static void processDataInParallel({@code List<String>} data) {
+     *   ExecutorService executor = Executors.newCachedThreadPool();
+     *   for (int i = 0; i < data.size(); ++i) {
+     *     pool.execute(() -> processData(data.get(i), i));
+     *   }
+     * }
      *
      * @param traceTag The trace tag.
      * @param trackName The track where the event should appear in the trace.
      * @param methodName The method name to appear in the trace.
-     * @param cookie Unique identifier for distinguishing simultaneous events
+     * @param cookie Unique identifier used for nesting events on a single
+     *               track. Events which overlap without nesting on the same
+     *               track must have different values for cookie.
      *
      * @hide
      */
@@ -307,9 +376,14 @@
      * {@link #asyncTraceForTrackBegin(long, String, String, int)}
      * using the same tag, track name, and cookie.
      *
+     * See the documentation for {@link #asyncTraceForTrackBegin(long, String, String, int)}.
+     * for inteded usage of this method.
+     *
      * @param traceTag The trace tag.
      * @param trackName The track where the event should appear in the trace.
-     * @param cookie Unique identifier for distinguishing simultaneous events
+     * @param cookie Unique identifier used for nesting events on a single
+     *               track. Events which overlap without nesting on the same
+     *               track must have different values for cookie.
      *
      * @hide
      */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 1f21bfe..dd02e02 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2377,14 +2377,16 @@
     }
 
     /**
-     * Returns true if the context user is the designated "main user" of the device. This user may
-     * have access to certain features which are limited to at most one user.
+     * Returns {@code true} if the context user is the designated "main user" of the device. This
+     * user may have access to certain features which are limited to at most one user. There will
+     * never be more than one main user on a device.
      *
-     * <p>Currently, the first human user on the device will be the main user; in the future, the
-     * concept may be transferable, so a different user (or even no user at all) may be designated
-     * the main user instead.
+     * <p>Currently, on most form factors the first human user on the device will be the main user;
+     * in the future, the concept may be transferable, so a different user (or even no user at all)
+     * may be designated the main user instead. On other form factors there might not be a main
+     * user.
      *
-     * <p>Note that this will be the not be the system user on devices for which
+     * <p>Note that this will not be the system user on devices for which
      * {@link #isHeadlessSystemUserMode()} returns true.
      * @hide
      */
@@ -2400,6 +2402,29 @@
     }
 
     /**
+     * Returns the designated "main user" of the device, or {@code null} if there is no main user.
+     *
+     * @see #isMainUser()
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            Manifest.permission.MANAGE_USERS,
+            Manifest.permission.CREATE_USERS,
+            Manifest.permission.QUERY_USERS})
+    public @Nullable UserHandle getMainUser() {
+        try {
+            final int mainUserId = mService.getMainUserId();
+            if (mainUserId == UserHandle.USER_NULL) {
+                return null;
+            }
+            return UserHandle.of(mainUserId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Used to check if the context user is an admin user. An admin user is allowed to
      * modify or configure certain settings that aren't available to non-admin users,
      * create and delete additional users, etc. There can be more than one admin users.
@@ -2951,8 +2976,15 @@
      * </ol>
      *
      * @return whether the user is visible at the moment, as defined above.
+     *
+     * @hide
      */
+    @SystemApi
     @UserHandleAware
+    @RequiresPermission(anyOf = {
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.MANAGE_USERS"
+    })
     public boolean isUserVisible() {
         try {
             return mService.isUserVisible(mUserId);
@@ -2965,9 +2997,14 @@
      * Gets the visible users (as defined by {@link #isUserVisible()}.
      *
      * @return visible users at the moment.
+     *
+     * @hide
      */
-    @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS,
-            Manifest.permission.INTERACT_ACROSS_USERS})
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            "android.permission.INTERACT_ACROSS_USERS",
+            "android.permission.MANAGE_USERS"
+    })
     public @NonNull Set<UserHandle> getVisibleUsers() {
         ArraySet<UserHandle> result = new ArraySet<>();
         try {
@@ -4275,6 +4312,43 @@
     }
 
     /**
+     * Returns the user who was last in the foreground, not including the current user and not
+     * including profiles.
+     *
+     * <p>Returns {@code null} if there is no previous user, for example if there
+     * is only one full user (i.e. only one user which is not a profile) on the device.
+     *
+     * <p>This method may be used for example to find the user to switch back to if the
+     * current user is removed, or if creating a new user is aborted.
+     *
+     * <p>Note that reboots do not interrupt this calculation; the previous user need not have
+     * used the device since it rebooted.
+     *
+     * <p>Note also that on devices that support multiple users on multiple displays, it is possible
+     * that the returned user will be visible on a secondary display, as the foreground user is the
+     * one associated with the main display.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(anyOf = {
+            android.Manifest.permission.MANAGE_USERS,
+            android.Manifest.permission.CREATE_USERS,
+            android.Manifest.permission.QUERY_USERS
+    })
+    public @Nullable UserHandle getPreviousForegroundUser() {
+        try {
+            final int previousUser = mService.getPreviousFullUserToEnterForeground();
+            if (previousUser == UserHandle.USER_NULL) {
+                return null;
+            }
+            return UserHandle.of(previousUser);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks whether it's possible to add more users.
      *
      * @return true if more users can be added, false if limit has been reached.
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 71bc4b3..3448a9e 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -227,6 +227,31 @@
     }
 
     /**
+     * Computes a legacy vibration pattern (i.e. a pattern with duration values for "off/on"
+     * vibration components) that is equivalent to this VibrationEffect.
+     *
+     * <p>All non-repeating effects created with {@link #createWaveform(int[], int)} are convertible
+     * into an equivalent vibration pattern with this method. It is not guaranteed that an effect
+     * created with other means becomes converted into an equivalent legacy vibration pattern, even
+     * if it has an equivalent vibration pattern. If this method is unable to create an equivalent
+     * vibration pattern for such effects, it will return {@code null}.
+     *
+     * <p>Note that a valid equivalent long[] pattern cannot be created for an effect that has any
+     * form of repeating behavior, regardless of how the effect was created. For repeating effects,
+     * the method will always return {@code null}.
+     *
+     * @return a long array representing a vibration pattern equivalent to the VibrationEffect, if
+     *               the method successfully derived a vibration pattern equivalent to the effect
+     *               (this will always be the case if the effect was created via
+     *               {@link #createWaveform(int[], int)} and is non-repeating). Otherwise, returns
+     *               {@code null}.
+     * @hide
+     */
+    @TestApi
+    @Nullable
+    public abstract long[] computeCreateWaveformOffOnTimingsOrNull();
+
+    /**
      * Create a waveform vibration.
      *
      * <p>Waveform vibrations are a potentially repeating series of timing and amplitude pairs,
@@ -641,6 +666,51 @@
             return mRepeatIndex;
         }
 
+         /** @hide */
+        @Override
+        @Nullable
+        public long[] computeCreateWaveformOffOnTimingsOrNull() {
+            if (getRepeatIndex() >= 0) {
+                // Repeating effects cannot be fully represented as a long[] legacy pattern.
+                return null;
+            }
+
+            List<VibrationEffectSegment> segments = getSegments();
+
+            // The maximum possible size of the final pattern is 1 plus the number of segments in
+            // the original effect. This is because we will add an empty "off" segment at the
+            // start of the pattern if the first segment of the original effect is an "on" segment.
+            // (because the legacy patterns start with an "off" pattern). Other than this one case,
+            // we will add the durations of back-to-back segments of similar amplitudes (amplitudes
+            // that are all "on" or "off") and create a pattern entry for the total duration, which
+            // will not take more number pattern entries than the number of segments processed.
+            long[] patternBuffer = new long[segments.size() + 1];
+            int patternIndex = 0;
+
+            for (int i = 0; i < segments.size(); i++) {
+                StepSegment stepSegment =
+                        castToValidStepSegmentForOffOnTimingsOrNull(segments.get(i));
+                if (stepSegment == null) {
+                    // This means that there is 1 or more segments of this effect that is/are not a
+                    // possible component of a legacy vibration pattern. Thus, the VibrationEffect
+                    // does not have any equivalent legacy vibration pattern.
+                    return null;
+                }
+
+                boolean isSegmentOff = stepSegment.getAmplitude() == 0;
+                // Even pattern indices are "off", and odd pattern indices are "on"
+                boolean isCurrentPatternIndexOff = (patternIndex % 2) == 0;
+                if (isSegmentOff != isCurrentPatternIndexOff) {
+                    // Move the pattern index one step ahead, so that the current segment's
+                    // "off"/"on" property matches that of the index's
+                    ++patternIndex;
+                }
+                patternBuffer[patternIndex] += stepSegment.getDuration();
+            }
+
+            return Arrays.copyOf(patternBuffer, patternIndex + 1);
+        }
+
         /** @hide */
         @Override
         public void validate() {
@@ -806,6 +876,31 @@
                         return new Composed[size];
                     }
                 };
+
+        /**
+         * Casts a provided {@link VibrationEffectSegment} to a {@link StepSegment} and returns it,
+         * only if it can possibly be a segment for an effect created via
+         * {@link #createWaveform(int[], int)}. Otherwise, returns {@code null}.
+         */
+        @Nullable
+        private static StepSegment castToValidStepSegmentForOffOnTimingsOrNull(
+                VibrationEffectSegment segment) {
+            if (!(segment instanceof StepSegment)) {
+                return null;
+            }
+
+            StepSegment stepSegment = (StepSegment) segment;
+            if (stepSegment.getFrequencyHz() != 0) {
+                return null;
+            }
+
+            float amplitude = stepSegment.getAmplitude();
+            if (amplitude != 0 && amplitude != DEFAULT_AMPLITUDE) {
+                return null;
+            }
+
+            return stepSegment;
+        }
     }
 
     /**
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 19e7bd4..ca88ae3 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -262,6 +262,14 @@
     public static final String NAMESPACE_GAME_DRIVER = "game_driver";
 
     /**
+     * Namespace for all HDMI Control features.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final String NAMESPACE_HDMI_CONTROL = "hdmi_control";
+
+    /**
      * Namespace for all input-related features that are used at the native level.
      * These features are applied at reboot.
      *
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 80098d5..f12bff2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -599,8 +599,8 @@
      * the result is set to {@link android.app.Activity#RESULT_CANCELED}.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_MANAGE_APP_LONG_JOBS =
-            "android.settings.MANAGE_APP_LONG_JOBS";
+    public static final String ACTION_MANAGE_APP_LONG_RUNNING_JOBS =
+            "android.settings.MANAGE_APP_LONG_RUNNING_JOBS";
 
     /**
      * Activity Action: Show settings to allow configuration of cross-profile access for apps
@@ -708,7 +708,7 @@
             "android.settings.WIFI_SETTINGS";
 
     /**
-     * Activity Action: Show settings to allow configuration of MTE.
+     * Activity Action: Show settings to allow configuration of Advanced memory protection.
      * <p>
      * Memory Tagging Extension (MTE) is a CPU extension that allows to protect against certain
      * classes of security problems at a small runtime performance cost overhead.
@@ -720,8 +720,8 @@
      * Output: Nothing.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_MEMTAG_SETTINGS =
-            "android.settings.MEMTAG_SETTINGS";
+    public static final String ACTION_ADVANCED_MEMORY_PROTECTION_SETTINGS =
+            "android.settings.ADVANCED_MEMORY_PROTECTION_SETTINGS";
 
     /**
      * Activity Action: Show settings to allow configuration of a static IP
@@ -7224,6 +7224,15 @@
         public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard";
 
         /**
+         * Whether stylus button presses are disabled. This is a boolean that
+         * determines if stylus buttons are ignored.
+         *
+         * @hide
+         */
+        @SuppressLint("NoSettingsProvider")
+        public static final String STYLUS_BUTTONS_DISABLED = "stylus_buttons_disabled";
+
+        /**
          * Host name and port for global http proxy. Uses ':' seperator for
          * between host and port.
          *
@@ -7898,6 +7907,13 @@
                 "high_text_contrast_enabled";
 
         /**
+         * The color contrast, float in [-1, 1], 1 being the highest contrast.
+         *
+         * @hide
+         */
+        public static final String CONTRAST_LEVEL = "contrast_level";
+
+        /**
          * Setting that specifies whether the display magnification is enabled via a system-wide
          * triple tap gesture. Display magnifications allows the user to zoom in the display content
          * and is targeted to low vision users. The current magnification scale is controlled by
@@ -17928,6 +17944,12 @@
             public static final String WET_MODE_ON = "wet_mode_on";
 
             /*
+             * Whether the RSB wake feature is enabled.
+             * @hide
+             */
+            public static final String RSB_WAKE_ENABLED = "rsb_wake_enabled";
+
+            /*
              * Whether the screen-unlock (keyguard) sound is enabled.
              * @hide
              */
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e720f1a..4d6422c 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -126,6 +126,8 @@
             Tag.BOOT_PATCHLEVEL; // KM_UINT | 719;
     public static final int KM_TAG_DEVICE_UNIQUE_ATTESTATION =
             Tag.DEVICE_UNIQUE_ATTESTATION; // KM_BOOL | 720;
+    public static final int KM_TAG_ATTESTATION_ID_SECOND_IMEI =
+            Tag.ATTESTATION_ID_SECOND_IMEI; // KM_BYTES | 723;
 
     public static final int KM_TAG_NONCE = Tag.NONCE; // KM_BYTES | 1001;
     public static final int KM_TAG_MAC_LENGTH = Tag.MAC_LENGTH; // KM_UINT | 1003;
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index d9a310f..745f36d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -332,7 +332,6 @@
     }
 
     @Override
-    /** @hide */
     protected final void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("Service component: "); pw.println(
                 ComponentName.flattenToShortString(mServiceComponentName));
diff --git a/core/java/android/service/credentials/Action.java b/core/java/android/service/credentials/Action.java
index 553a324..7757081 100644
--- a/core/java/android/service/credentials/Action.java
+++ b/core/java/android/service/credentials/Action.java
@@ -27,8 +27,6 @@
 /**
  * An action defined by the provider that intents into the provider's app for specific
  * user actions.
- *
- * @hide
  */
 public final class Action implements Parcelable {
     /** Slice object containing display content to be displayed with this action on the UI. */
@@ -39,6 +37,13 @@
     /**
      * Constructs an action to be displayed on the UI.
      *
+     * <p> Actions must be used for any provider related operations, such as opening the provider
+     * app, intenting straight into certain app activities like 'manage credentials', top
+     * level authentication before displaying any content etc.
+     *
+     * <p> See details on usage of {@code Action} for various actionable entries in
+     * {@link BeginCreateCredentialResponse} and {@link GetCredentialsResponse}.
+     *
      * @param slice the display content to be displayed on the UI, along with this action
      * @param pendingIntent the intent to be invoked when the user selects this action
      */
diff --git a/core/java/android/service/credentials/BeginCreateCredentialRequest.aidl b/core/java/android/service/credentials/BeginCreateCredentialRequest.aidl
new file mode 100644
index 0000000..30cab8d
--- /dev/null
+++ b/core/java/android/service/credentials/BeginCreateCredentialRequest.aidl
@@ -0,0 +1,3 @@
+package android.service.credentials;
+
+parcelable BeginCreateCredentialRequest;
\ No newline at end of file
diff --git a/core/java/android/service/credentials/BeginCreateCredentialRequest.java b/core/java/android/service/credentials/BeginCreateCredentialRequest.java
new file mode 100644
index 0000000..1918d8c
--- /dev/null
+++ b/core/java/android/service/credentials/BeginCreateCredentialRequest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+
+/**
+ * Request for beginning a create credential request.
+ *
+ * See {@link BeginCreateCredentialResponse} for the counterpart response
+ */
+public final class BeginCreateCredentialRequest implements Parcelable {
+    private final @NonNull String mCallingPackage;
+    private final @NonNull String mType;
+    private final @NonNull Bundle mData;
+
+    /**
+     * Constructs a new instance.
+     *
+     * @throws IllegalArgumentException If {@code callingPackage}, or {@code type} string is
+     * null or empty.
+     * @throws NullPointerException If {@code data} is null.
+     */
+    public BeginCreateCredentialRequest(@NonNull String callingPackage,
+            @NonNull String type, @NonNull Bundle data) {
+        mCallingPackage = Preconditions.checkStringNotEmpty(callingPackage,
+                "callingPackage must not be null or empty");
+        mType = Preconditions.checkStringNotEmpty(type,
+                "type must not be null or empty");
+        mData = Objects.requireNonNull(data, "data must not be null");
+    }
+
+    private BeginCreateCredentialRequest(@NonNull Parcel in) {
+        mCallingPackage = in.readString8();
+        mType = in.readString8();
+        mData = in.readBundle(Bundle.class.getClassLoader());
+    }
+
+    public static final @NonNull Creator<BeginCreateCredentialRequest> CREATOR =
+            new Creator<BeginCreateCredentialRequest>() {
+                @Override
+                public BeginCreateCredentialRequest createFromParcel(@NonNull Parcel in) {
+                    return new BeginCreateCredentialRequest(in);
+                }
+
+                @Override
+                public BeginCreateCredentialRequest[] newArray(int size) {
+                    return new BeginCreateCredentialRequest[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mCallingPackage);
+        dest.writeString8(mType);
+        dest.writeBundle(mData);
+    }
+
+    /** Returns the calling package of the calling app. */
+    @NonNull
+    public String getCallingPackage() {
+        return mCallingPackage;
+    }
+
+    /** Returns the type of the credential to be created. */
+    @NonNull
+    public String getType() {
+        return mType;
+    }
+
+    /** Returns the data to be used while resolving the credential to create. */
+    @NonNull
+    public Bundle getData() {
+        return mData;
+    }
+}
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.aidl b/core/java/android/service/credentials/BeginCreateCredentialResponse.aidl
new file mode 100644
index 0000000..d2a1408
--- /dev/null
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+parcelable BeginCreateCredentialResponse;
diff --git a/core/java/android/service/credentials/BeginCreateCredentialResponse.java b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
new file mode 100644
index 0000000..022678e
--- /dev/null
+++ b/core/java/android/service/credentials/BeginCreateCredentialResponse.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Response to a {@link BeginCreateCredentialRequest}.
+ */
+public final class BeginCreateCredentialResponse implements Parcelable {
+    private final @NonNull List<CreateEntry> mCreateEntries;
+    private final @Nullable CreateEntry mRemoteCreateEntry;
+
+    private BeginCreateCredentialResponse(@NonNull Parcel in) {
+        List<CreateEntry> createEntries = new ArrayList<>();
+        in.readTypedList(createEntries, CreateEntry.CREATOR);
+        mCreateEntries = createEntries;
+        mRemoteCreateEntry = in.readTypedObject(CreateEntry.CREATOR);
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mCreateEntries);
+        dest.writeTypedObject(mRemoteCreateEntry, flags);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final @NonNull Creator<BeginCreateCredentialResponse> CREATOR =
+            new Creator<BeginCreateCredentialResponse>() {
+                @Override
+                public BeginCreateCredentialResponse createFromParcel(@NonNull Parcel in) {
+                    return new BeginCreateCredentialResponse(in);
+                }
+
+                @Override
+                public BeginCreateCredentialResponse[] newArray(int size) {
+                    return new BeginCreateCredentialResponse[size];
+                }
+            };
+
+    /* package-private */ BeginCreateCredentialResponse(
+            @NonNull List<CreateEntry> createEntries,
+            @Nullable CreateEntry remoteCreateEntry) {
+        this.mCreateEntries = createEntries;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mCreateEntries);
+        this.mRemoteCreateEntry = remoteCreateEntry;
+    }
+
+    /** Returns the list of create entries to be displayed on the UI. */
+    public @NonNull List<CreateEntry> getCreateEntries() {
+        return mCreateEntries;
+    }
+
+    /** Returns the remote create entry to be displayed on the UI. */
+    public @Nullable CreateEntry getRemoteCreateEntry() {
+        return mRemoteCreateEntry;
+    }
+
+    /**
+     * A builder for {@link BeginCreateCredentialResponse}
+     */
+    @SuppressWarnings("WeakerAccess") /* synthetic access */
+    public static final class Builder {
+        private @NonNull List<CreateEntry> mCreateEntries = new ArrayList<>();
+        private @Nullable CreateEntry mRemoteCreateEntry;
+
+        /**
+         * Sets the list of create entries to be shown on the UI.
+         *
+         * @throws IllegalArgumentException If {@code createEntries} is empty.
+         * @throws NullPointerException If {@code createEntries} is null, or any of its elements
+         * are null.
+         */
+        public @NonNull Builder setCreateEntries(@NonNull List<CreateEntry> createEntries) {
+            Preconditions.checkCollectionNotEmpty(createEntries, "createEntries");
+            mCreateEntries = Preconditions.checkCollectionElementsNotNull(
+                    createEntries, "createEntries");
+            return this;
+        }
+
+        /**
+         * Adds an entry to the list of create entries to be shown on the UI.
+         *
+         * @throws NullPointerException If {@code createEntry} is null.
+         */
+        public @NonNull Builder addCreateEntry(@NonNull CreateEntry createEntry) {
+            mCreateEntries.add(Objects.requireNonNull(createEntry));
+            return this;
+        }
+
+        /**
+         * Sets a remote create entry to be shown on the UI. Provider must set this entry if they
+         * wish to create the credential on a different device.
+         *
+         * <p> When constructing the {@link CreateEntry} object, the {@code pendingIntent} must be
+         * set such that it leads to an activity that can provide UI to fulfill the request on
+         * a remote device. When user selects this {@code remoteCreateEntry}, the system will
+         * invoke the {@code pendingIntent} set on the {@link CreateEntry}.
+         *
+         * <p> Once the remote credential flow is complete, the {@link android.app.Activity}
+         * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
+         * {@link CredentialProviderService#EXTRA_CREATE_CREDENTIAL_RESULT} key should be populated
+         * with a {@link android.credentials.CreateCredentialResponse} object.
+         */
+        public @NonNull Builder setRemoteCreateEntry(@Nullable CreateEntry remoteCreateEntry) {
+            mRemoteCreateEntry = remoteCreateEntry;
+            return this;
+        }
+
+        /**
+         * Builds a new instance of {@link BeginCreateCredentialResponse}.
+         *
+         * @throws NullPointerException If {@code createEntries} is null.
+         * @throws IllegalArgumentException If {@code createEntries} is empty.
+         */
+        public @NonNull BeginCreateCredentialResponse build() {
+            Preconditions.checkCollectionNotEmpty(mCreateEntries, "createEntries must "
+                    + "not be null, or empty");
+            return new BeginCreateCredentialResponse(mCreateEntries, mRemoteCreateEntry);
+        }
+    }
+}
diff --git a/core/java/android/service/credentials/CreateCredentialRequest.aidl b/core/java/android/service/credentials/CreateCredentialRequest.aidl
deleted file mode 100644
index eb7fba9..0000000
--- a/core/java/android/service/credentials/CreateCredentialRequest.aidl
+++ /dev/null
@@ -1,3 +0,0 @@
-package android.service.credentials;
-
-parcelable CreateCredentialRequest;
\ No newline at end of file
diff --git a/core/java/android/service/credentials/CreateCredentialRequest.java b/core/java/android/service/credentials/CreateCredentialRequest.java
index e6da349..aee85ab 100644
--- a/core/java/android/service/credentials/CreateCredentialRequest.java
+++ b/core/java/android/service/credentials/CreateCredentialRequest.java
@@ -27,8 +27,6 @@
 
 /**
  * Request for creating a credential.
- *
- * @hide
  */
 public final class CreateCredentialRequest implements Parcelable {
     private final @NonNull String mCallingPackage;
diff --git a/core/java/android/service/credentials/CreateCredentialResponse.aidl b/core/java/android/service/credentials/CreateCredentialResponse.aidl
deleted file mode 100644
index 73c9147..0000000
--- a/core/java/android/service/credentials/CreateCredentialResponse.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.credentials;
-
-parcelable CreateCredentialResponse;
diff --git a/core/java/android/service/credentials/CreateCredentialResponse.java b/core/java/android/service/credentials/CreateCredentialResponse.java
deleted file mode 100644
index f69dca8..0000000
--- a/core/java/android/service/credentials/CreateCredentialResponse.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.credentials;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Response to a {@link CreateCredentialRequest}.
- *
- * @hide
- */
-public final class CreateCredentialResponse implements Parcelable {
-    private final @NonNull List<SaveEntry> mSaveEntries;
-    private final @Nullable Action mRemoteSaveEntry;
-    //TODO : Add actions if needed
-
-    private CreateCredentialResponse(@NonNull Parcel in) {
-        List<SaveEntry> saveEntries = new ArrayList<>();
-        in.readTypedList(saveEntries, SaveEntry.CREATOR);
-        mSaveEntries = saveEntries;
-        mRemoteSaveEntry = in.readTypedObject(Action.CREATOR);
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedList(mSaveEntries);
-        dest.writeTypedObject(mRemoteSaveEntry, flags);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final @NonNull Creator<CreateCredentialResponse> CREATOR =
-            new Creator<CreateCredentialResponse>() {
-                @Override
-                public CreateCredentialResponse createFromParcel(@NonNull Parcel in) {
-                    return new CreateCredentialResponse(in);
-                }
-
-                @Override
-                public CreateCredentialResponse[] newArray(int size) {
-                    return new CreateCredentialResponse[size];
-                }
-            };
-
-    /* package-private */ CreateCredentialResponse(
-            @NonNull List<SaveEntry> saveEntries,
-            @Nullable Action remoteSaveEntry) {
-        this.mSaveEntries = saveEntries;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mSaveEntries);
-        this.mRemoteSaveEntry = remoteSaveEntry;
-    }
-
-    /** Returns the list of save entries to be displayed on the UI. */
-    public @NonNull List<SaveEntry> getSaveEntries() {
-        return mSaveEntries;
-    }
-
-    /** Returns the remote save entry to be displayed on the UI. */
-    public @NonNull Action getRemoteSaveEntry() {
-        return mRemoteSaveEntry;
-    }
-
-    /**
-     * A builder for {@link CreateCredentialResponse}
-     */
-    @SuppressWarnings("WeakerAccess")
-    public static final class Builder {
-        private @NonNull List<SaveEntry> mSaveEntries = new ArrayList<>();
-        private @Nullable Action mRemoteSaveEntry;
-
-        /**
-         * Sets the list of save entries to be shown on the UI.
-         *
-         * @throws IllegalArgumentException If {@code saveEntries} is empty.
-         * @throws NullPointerException If {@code saveEntries} is null, or any of its elements
-         * are null.
-         */
-        public @NonNull Builder setSaveEntries(@NonNull List<SaveEntry> saveEntries) {
-            Preconditions.checkCollectionNotEmpty(saveEntries, "saveEntries");
-            mSaveEntries = Preconditions.checkCollectionElementsNotNull(
-                    saveEntries, "saveEntries");
-            return this;
-        }
-
-        /**
-         * Adds an entry to the list of save entries to be shown on the UI.
-         *
-         * @throws NullPointerException If {@code saveEntry} is null.
-         */
-        public @NonNull Builder addSaveEntry(@NonNull SaveEntry saveEntry) {
-            mSaveEntries.add(Objects.requireNonNull(saveEntry));
-            return this;
-        }
-
-        /**
-         * Sets a remote save entry to be shown on the UI.
-         */
-        public @NonNull Builder setRemoteSaveEntry(@Nullable Action remoteSaveEntry) {
-            mRemoteSaveEntry = remoteSaveEntry;
-            return this;
-        }
-
-        /**
-         * Builds the instance.
-         *
-         * @throws IllegalArgumentException If {@code saveEntries} is empty.
-         */
-        public @NonNull CreateCredentialResponse build() {
-            Preconditions.checkCollectionNotEmpty(mSaveEntries, "saveEntries must "
-                    + "not be empty");
-            return new CreateCredentialResponse(
-                    mSaveEntries,
-                    mRemoteSaveEntry);
-        }
-    }
-}
diff --git a/core/java/android/service/credentials/CreateEntry.java b/core/java/android/service/credentials/CreateEntry.java
new file mode 100644
index 0000000..eb25e25
--- /dev/null
+++ b/core/java/android/service/credentials/CreateEntry.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An entry to be shown on the UI. This entry represents where the credential to be created will
+ * be stored. Examples include user's account, family group etc.
+ */
+public final class CreateEntry implements Parcelable {
+    private final @NonNull Slice mSlice;
+    private final @NonNull PendingIntent mPendingIntent;
+
+    private CreateEntry(@NonNull Parcel in) {
+        mSlice = in.readTypedObject(Slice.CREATOR);
+        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
+    }
+
+    public static final @NonNull Creator<CreateEntry> CREATOR = new Creator<CreateEntry>() {
+        @Override
+        public CreateEntry createFromParcel(@NonNull Parcel in) {
+            return new CreateEntry(in);
+        }
+
+        @Override
+        public CreateEntry[] newArray(int size) {
+            return new CreateEntry[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedObject(mSlice, flags);
+        dest.writeTypedObject(mPendingIntent, flags);
+    }
+
+    /**
+     * Constructs a CreateEntry to be displayed on the UI.
+     *
+     * @param slice the display content to be displayed on the UI, along with this entry
+     * @param pendingIntent the intent to be invoked when the user selects this entry
+     */
+    public CreateEntry(
+            @NonNull Slice slice,
+            @NonNull PendingIntent pendingIntent) {
+        this.mSlice = slice;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mSlice);
+        this.mPendingIntent = pendingIntent;
+        com.android.internal.util.AnnotationValidations.validate(
+                NonNull.class, null, mPendingIntent);
+    }
+
+    /** Returns the content to be displayed with this create entry on the UI. */
+    public @NonNull Slice getSlice() {
+        return mSlice;
+    }
+
+    /** Returns the pendingIntent to be invoked when this create entry on the UI is selectcd. */
+    public @NonNull PendingIntent getPendingIntent() {
+        return mPendingIntent;
+    }
+}
diff --git a/core/java/android/service/credentials/CredentialEntry.java b/core/java/android/service/credentials/CredentialEntry.java
index 98c537a..941db02b 100644
--- a/core/java/android/service/credentials/CredentialEntry.java
+++ b/core/java/android/service/credentials/CredentialEntry.java
@@ -31,8 +31,6 @@
 /**
  * A credential entry that is displayed on the account selector UI. Each entry corresponds to
  * something that the user can select.
- *
- * @hide
  */
 public final class CredentialEntry implements Parcelable {
     /** The type of the credential entry to be shown on the UI. */
@@ -145,61 +143,67 @@
         private boolean mAutoSelectAllowed = false;
 
         /**
-         * Builds the instance.
+         * Creates a builder for a {@link CredentialEntry} that should invoke a
+         * {@link PendingIntent} when selected by the user.
+         *
+         * <p>The {@code pendingIntent} can be used to launch activities that require some user
+         * engagement before getting the credential corresponding to this entry,
+         * e.g. authentication, confirmation etc.
+         * Once the activity fulfills the required user engagement, the
+         * {@link android.app.Activity} result should be set to
+         * {@link android.app.Activity#RESULT_OK}, and the
+         * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} must be set with a
+         * {@link Credential} object.
+         *
          * @param type the type of credential underlying this credential entry
          * @param slice the content to be displayed with this entry on the UI
+         * @param pendingIntent the pendingIntent to be invoked when this entry is selected by the
+         *                      user
          *
-         * @throws IllegalArgumentException If {@code type} is null or empty.
-         * @throws NullPointerException If {@code slice} is null.
+         * @throws NullPointerException If {@code slice}, or {@code pendingIntent} is null.
+         * @throws IllegalArgumentException If {@code type} is null or empty, or if
+         * {@code pendingIntent} was not created with {@link PendingIntent#getActivity}
+         * or {@link PendingIntent#getActivities}.
          */
-        public Builder(@NonNull String type, @NonNull Slice slice) {
+        public Builder(@NonNull String type, @NonNull Slice slice,
+                @NonNull PendingIntent pendingIntent) {
             mType = Preconditions.checkStringNotEmpty(type, "type must not be "
                     + "null, or empty");
             mSlice = Objects.requireNonNull(slice,
                     "slice must not be null");
+            mPendingIntent = Objects.requireNonNull(pendingIntent,
+                    "pendingIntent must not be null");
+            if (!mPendingIntent.isActivity()) {
+                throw new IllegalStateException("Pending intent must start an activity");
+            }
         }
 
         /**
-         * Sets the pendingIntent to be invoked if the user selects this entry.
+         * Creates a builder for a {@link CredentialEntry} that contains a {@link Credential},
+         * and does not require further action.
+         * @param type the type of credential underlying this credential entry
+         * @param slice the content to be displayed with this entry on the UI
+         * @param credential the credential to be returned to the client app, when this entry is
+         *                   selected by the user
          *
-         * The pending intent can be used to launch activities that require some user engagement
-         * before getting the credential corresponding to this entry, e.g. authentication,
-         * confirmation etc.
-         * Once the activity fulfills the required user engagement, a {@link Credential} object
-         * must be returned as an extra on activity finish.
-         *
-         * @throws IllegalStateException If {@code credential} is already set. Must either set the
-         * {@code credential}, or the {@code pendingIntent}.
+         * @throws IllegalArgumentException If {@code type} is null or empty.
+         * @throws NullPointerException If {@code slice}, or {@code credential} is null.
          */
-        public @NonNull Builder setPendingIntent(@Nullable PendingIntent pendingIntent) {
-            if (pendingIntent != null) {
-                Preconditions.checkState(mCredential == null,
-                        "credential is already set. Cannot set both the pendingIntent "
-                                + "and the credential");
-            }
-            mPendingIntent = pendingIntent;
-            return this;
-        }
-
-        /**
-         * Sets the credential to be used, if the user selects this entry.
-         *
-         * @throws IllegalStateException If {@code pendingIntent} is already set. Must either set
-         * the {@code pendingIntent}, or the {@code credential}.
-         */
-        public @NonNull Builder setCredential(@Nullable Credential credential) {
-            if (credential != null) {
-                Preconditions.checkState(mPendingIntent == null,
-                        "pendingIntent is already set. Cannot set both the "
-                                + "pendingIntent and the credential");
-            }
-            mCredential = credential;
-            return this;
+        public Builder(@NonNull String type, @NonNull Slice slice, @NonNull Credential credential) {
+            mType = Preconditions.checkStringNotEmpty(type, "type must not be "
+                    + "null, or empty");
+            mSlice = Objects.requireNonNull(slice,
+                    "slice must not be null");
+            mCredential = Objects.requireNonNull(credential,
+                    "credential must not be null");
         }
 
         /**
          * Sets whether the entry is allowed to be auto selected by the framework.
          * The default value is set to false.
+         *
+         * <p> The entry is only auto selected if it is the only entry on the user selector,
+         * AND the developer has also enabled auto select, while building the request.
          */
         public @NonNull Builder setAutoSelectAllowed(@NonNull boolean autoSelectAllowed) {
             mAutoSelectAllowed = autoSelectAllowed;
diff --git a/core/java/android/service/credentials/CredentialProviderException.java b/core/java/android/service/credentials/CredentialProviderException.java
index 06f0052..02b7443 100644
--- a/core/java/android/service/credentials/CredentialProviderException.java
+++ b/core/java/android/service/credentials/CredentialProviderException.java
@@ -24,8 +24,6 @@
 
 /**
  * Contains custom exceptions to be used by credential providers on failure.
- *
- * @hide
  */
 public class CredentialProviderException extends Exception {
     public static final int ERROR_UNKNOWN = 0;
@@ -59,6 +57,11 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface CredentialProviderError { }
 
+    public CredentialProviderException(@CredentialProviderError int errorCode,
+            @NonNull String message, @NonNull Throwable cause) {
+        super(message, cause);
+        mErrorCode = errorCode;
+    }
 
     public CredentialProviderException(@CredentialProviderError int errorCode,
             @NonNull String message) {
diff --git a/core/java/android/service/credentials/CredentialProviderService.java b/core/java/android/service/credentials/CredentialProviderService.java
index 24b7c3c..32646e6 100644
--- a/core/java/android/service/credentials/CredentialProviderService.java
+++ b/core/java/android/service/credentials/CredentialProviderService.java
@@ -37,30 +37,63 @@
 /**
  * Service to be extended by credential providers, in order to return user credentials
  * to the framework.
- *
- * @hide
  */
 public abstract class CredentialProviderService extends Service {
-    /** Extra to be used by provider to populate the credential when ending the activity started
-     * through the {@code pendingIntent} on the selected {@link SaveEntry}. **/
-    public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE =
-            "android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE";
-
-    /** Extra to be used by provider to populate the {@link CredentialsDisplayContent} when
-     * an authentication action entry is selected. **/
-    public static final String EXTRA_GET_CREDENTIALS_DISPLAY_CONTENT =
-            "android.service.credentials.extra.GET_CREDENTIALS_DISPLAY_CONTENT";
+    /**
+     * Intent extra: The {@link android.credentials.CreateCredentialRequest} attached with
+     * the {@code pendingIntent} that is invoked when the user selects a {@link CreateEntry}
+     * returned as part of the {@link BeginCreateCredentialResponse}
+     *
+     * <p>
+     * Type: {@link android.credentials.CreateCredentialRequest}
+     */
+    public static final String EXTRA_CREATE_CREDENTIAL_REQUEST =
+            "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST";
 
     /**
-     * Provider must read the value against this extra to receive the complete create credential
-     * request parameters, when a pending intent is launched.
+     * Intent extra: The result of a create flow operation, to be set on finish of the
+     * {@link android.app.Activity} invoked through the {@code pendingIntent} set on
+     * a {@link CreateEntry}.
+     *
+     * <p>
+     * Type: {@link android.credentials.CreateCredentialResponse}
      */
-    public static final String EXTRA_CREATE_CREDENTIAL_REQUEST_PARAMS =
-            "android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST_PARAMS";
+    public static final String EXTRA_CREATE_CREDENTIAL_RESULT =
+            "android.service.credentials.extra.CREATE_CREDENTIAL_RESULT";
 
-    /** Extra to be used by the provider when setting the credential result. */
-    public static final String EXTRA_GET_CREDENTIAL =
-            "android.service.credentials.extra.GET_CREDENTIAL";
+    /**
+     * Intent extra: The result of a get credential flow operation, to be set on finish of the
+     * {@link android.app.Activity} invoked through the {@code pendingIntent} set on
+     * a {@link CredentialEntry}.
+     *
+     * <p>
+     * Type: {@link android.credentials.Credential}
+     */
+    public static final String EXTRA_CREDENTIAL_RESULT =
+            "android.service.credentials.extra.CREDENTIAL_RESULT";
+
+    /**
+     * Intent extra: The result of an authentication flow, to be set on finish of the
+     * {@link android.app.Activity} invoked through the {@link android.app.PendingIntent} set on
+     * a {@link GetCredentialsResponse}. This result should contain the actual content, including
+     * credential entries and action entries, to be shown on the selector.
+     *
+     * <p>
+     * Type: {@link CredentialsResponseContent}
+     */
+    public static final String EXTRA_GET_CREDENTIALS_CONTENT_RESULT =
+            "android.service.credentials.extra.GET_CREDENTIALS_CONTENT_RESULT";
+
+    /**
+     * Intent extra: The error result of any {@link android.app.PendingIntent} flow, to be set
+     * on finish of the corresponding {@link android.app.Activity}. This result should contain an
+     * error code, representing the error encountered by the provider.
+     *
+     * <p>
+     * Type: {@link String}
+     */
+    public static final String EXTRA_ERROR =
+            "android.service.credentials.extra.ERROR";
 
     private static final String TAG = "CredProviderService";
 
@@ -129,20 +162,21 @@
         }
 
         @Override
-        public ICancellationSignal onCreateCredential(CreateCredentialRequest request,
-                ICreateCredentialCallback callback) {
+        public ICancellationSignal onBeginCreateCredential(BeginCreateCredentialRequest request,
+                IBeginCreateCredentialCallback callback) {
             Objects.requireNonNull(request);
             Objects.requireNonNull(callback);
 
             ICancellationSignal transport = CancellationSignal.createTransport();
 
             mHandler.sendMessage(obtainMessage(
-                    CredentialProviderService::onCreateCredential,
+                    CredentialProviderService::onBeginCreateCredential,
                     CredentialProviderService.this, request,
                     CancellationSignal.fromTransport(transport),
-                    new OutcomeReceiver<CreateCredentialResponse, CredentialProviderException>() {
+                    new OutcomeReceiver<
+                            BeginCreateCredentialResponse, CredentialProviderException>() {
                         @Override
-                        public void onResult(CreateCredentialResponse result) {
+                        public void onResult(BeginCreateCredentialResponse result) {
                             try {
                                 callback.onSuccess(result);
                             } catch (RemoteException e) {
@@ -182,8 +216,8 @@
      *                           the android system.
      * @param callback Object used to relay the response of the credential creation request.
      */
-    public abstract void onCreateCredential(@NonNull CreateCredentialRequest request,
+    public abstract void onBeginCreateCredential(@NonNull BeginCreateCredentialRequest request,
             @NonNull CancellationSignal cancellationSignal,
-            @NonNull OutcomeReceiver<CreateCredentialResponse,
+            @NonNull OutcomeReceiver<BeginCreateCredentialResponse,
                     CredentialProviderException> callback);
 }
diff --git a/core/java/android/service/credentials/CredentialsDisplayContent.java b/core/java/android/service/credentials/CredentialsDisplayContent.java
deleted file mode 100644
index 4b23800..0000000
--- a/core/java/android/service/credentials/CredentialsDisplayContent.java
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.credentials;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import com.android.internal.util.Preconditions;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Content to be displayed on the account selector UI, including credential entries,
- * actions etc.
- *
- * @hide
- */
-public final class CredentialsDisplayContent implements Parcelable {
-    /** List of credential entries to be displayed on the UI. */
-    private final @NonNull List<CredentialEntry> mCredentialEntries;
-
-    /** List of provider actions to be displayed on the UI. */
-    private final @NonNull List<Action> mActions;
-
-    /** Remote credential entry to get the response from a different device. */
-    private final @Nullable Action mRemoteCredentialEntry;
-
-    private CredentialsDisplayContent(@NonNull List<CredentialEntry> credentialEntries,
-            @NonNull List<Action> actions,
-            @Nullable Action remoteCredentialEntry) {
-        mCredentialEntries = credentialEntries;
-        mActions = actions;
-        mRemoteCredentialEntry = remoteCredentialEntry;
-    }
-
-    private CredentialsDisplayContent(@NonNull Parcel in) {
-        List<CredentialEntry> credentialEntries = new ArrayList<>();
-        in.readTypedList(credentialEntries, CredentialEntry.CREATOR);
-        mCredentialEntries = credentialEntries;
-        List<Action> actions = new ArrayList<>();
-        in.readTypedList(actions, Action.CREATOR);
-        mActions = actions;
-        mRemoteCredentialEntry = in.readTypedObject(Action.CREATOR);
-    }
-
-    public static final @NonNull Creator<CredentialsDisplayContent> CREATOR =
-            new Creator<CredentialsDisplayContent>() {
-                @Override
-                public CredentialsDisplayContent createFromParcel(@NonNull Parcel in) {
-                    return new CredentialsDisplayContent(in);
-                }
-
-                @Override
-                public CredentialsDisplayContent[] newArray(int size) {
-                    return new CredentialsDisplayContent[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedList(mCredentialEntries, flags);
-        dest.writeTypedList(mActions, flags);
-        dest.writeTypedObject(mRemoteCredentialEntry, flags);
-    }
-
-    /**
-     * Returns the list of credential entries to be displayed on the UI.
-     */
-    public @NonNull List<CredentialEntry> getCredentialEntries() {
-        return mCredentialEntries;
-    }
-
-    /**
-     * Returns the list of actions to be displayed on the UI.
-     */
-    public @NonNull List<Action> getActions() {
-        return mActions;
-    }
-
-    /**
-     * Returns the remote credential entry to be displayed on the UI.
-     */
-    public @Nullable Action getRemoteCredentialEntry() {
-        return mRemoteCredentialEntry;
-    }
-
-    /**
-     * Builds an instance of {@link CredentialsDisplayContent}.
-     */
-    public static final class Builder {
-        private List<CredentialEntry> mCredentialEntries = new ArrayList<>();
-        private List<Action> mActions = new ArrayList<>();
-        private Action mRemoteCredentialEntry;
-
-        /**
-         * Sets the remote credential entry to be displayed on the UI.
-         */
-        public @NonNull Builder setRemoteCredentialEntry(@Nullable Action remoteCredentialEntry) {
-            mRemoteCredentialEntry = remoteCredentialEntry;
-            return this;
-        }
-
-        /**
-         * Adds a {@link CredentialEntry} to the list of entries to be displayed on
-         * the UI.
-         *
-         * @throws NullPointerException If the {@code credentialEntry} is null.
-         */
-        public @NonNull Builder addCredentialEntry(@NonNull CredentialEntry credentialEntry) {
-            mCredentialEntries.add(Objects.requireNonNull(credentialEntry));
-            return this;
-        }
-
-        /**
-         * Adds an {@link Action} to the list of actions to be displayed on
-         * the UI.
-         *
-         * @throws NullPointerException If {@code action} is null.
-         */
-        public @NonNull Builder addAction(@NonNull Action action) {
-            mActions.add(Objects.requireNonNull(action, "action must not be null"));
-            return this;
-        }
-
-        /**
-         * Sets the list of actions to be displayed on the UI.
-         *
-         * @throws NullPointerException If {@code actions} is null, or any of its elements
-         * is null.
-         */
-        public @NonNull Builder setActions(@NonNull List<Action> actions) {
-            mActions = Preconditions.checkCollectionElementsNotNull(actions,
-                    "actions");
-            return this;
-        }
-
-        /**
-         * Sets the list of credential entries to be displayed on the
-         * account selector UI.
-         *
-         * @throws NullPointerException If {@code credentialEntries} is null, or any of its
-         * elements is null.
-         */
-        public @NonNull Builder setCredentialEntries(
-                @NonNull List<CredentialEntry> credentialEntries) {
-            mCredentialEntries = Preconditions.checkCollectionElementsNotNull(
-                    credentialEntries,
-                    "credentialEntries");
-            return this;
-        }
-
-        /**
-         * Builds a {@link GetCredentialsResponse} instance.
-         *
-         * @throws NullPointerException If {@code credentialEntries} is null.
-         * @throws IllegalStateException if both {@code credentialEntries} and
-         * {@code actions} are empty.
-         */
-        public @NonNull CredentialsDisplayContent build() {
-            if (mCredentialEntries != null && mCredentialEntries.isEmpty()
-                    && mActions != null && mActions.isEmpty()) {
-                throw new IllegalStateException("credentialEntries and actions must not both "
-                        + "be empty");
-            }
-            return new CredentialsDisplayContent(mCredentialEntries, mActions,
-                    mRemoteCredentialEntry);
-        }
-    }
-}
diff --git a/core/java/android/service/credentials/CredentialsResponseContent.java b/core/java/android/service/credentials/CredentialsResponseContent.java
new file mode 100644
index 0000000..32cab50
--- /dev/null
+++ b/core/java/android/service/credentials/CredentialsResponseContent.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The content to be displayed on the account selector UI, including credential entries,
+ * actions etc. Returned as part of {@link GetCredentialsResponse}
+ */
+public final class CredentialsResponseContent implements Parcelable {
+    /** List of credential entries to be displayed on the UI. */
+    private final @NonNull List<CredentialEntry> mCredentialEntries;
+
+    /** List of provider actions to be displayed on the UI. */
+    private final @NonNull List<Action> mActions;
+
+    /** Remote credential entry to get the response from a different device. */
+    private final @Nullable CredentialEntry mRemoteCredentialEntry;
+
+    private CredentialsResponseContent(@NonNull List<CredentialEntry> credentialEntries,
+            @NonNull List<Action> actions,
+            @Nullable CredentialEntry remoteCredentialEntry) {
+        mCredentialEntries = credentialEntries;
+        mActions = actions;
+        mRemoteCredentialEntry = remoteCredentialEntry;
+    }
+
+    private CredentialsResponseContent(@NonNull Parcel in) {
+        List<CredentialEntry> credentialEntries = new ArrayList<>();
+        in.readTypedList(credentialEntries, CredentialEntry.CREATOR);
+        mCredentialEntries = credentialEntries;
+        List<Action> actions = new ArrayList<>();
+        in.readTypedList(actions, Action.CREATOR);
+        mActions = actions;
+        mRemoteCredentialEntry = in.readTypedObject(CredentialEntry.CREATOR);
+    }
+
+    public static final @NonNull Creator<CredentialsResponseContent> CREATOR =
+            new Creator<CredentialsResponseContent>() {
+                @Override
+                public CredentialsResponseContent createFromParcel(@NonNull Parcel in) {
+                    return new CredentialsResponseContent(in);
+                }
+
+                @Override
+                public CredentialsResponseContent[] newArray(int size) {
+                    return new CredentialsResponseContent[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeTypedList(mCredentialEntries, flags);
+        dest.writeTypedList(mActions, flags);
+        dest.writeTypedObject(mRemoteCredentialEntry, flags);
+    }
+
+    /**
+     * Returns the list of credential entries to be displayed on the UI.
+     */
+    public @NonNull List<CredentialEntry> getCredentialEntries() {
+        return mCredentialEntries;
+    }
+
+    /**
+     * Returns the list of actions to be displayed on the UI.
+     */
+    public @NonNull List<Action> getActions() {
+        return mActions;
+    }
+
+    /**
+     * Returns the remote credential entry to be displayed on the UI.
+     */
+    public @Nullable CredentialEntry getRemoteCredentialEntry() {
+        return mRemoteCredentialEntry;
+    }
+
+    /**
+     * Builds an instance of {@link CredentialsResponseContent}.
+     */
+    public static final class Builder {
+        private List<CredentialEntry> mCredentialEntries = new ArrayList<>();
+        private List<Action> mActions = new ArrayList<>();
+        private CredentialEntry mRemoteCredentialEntry;
+
+        /**
+         * Sets a remote credential entry to be shown on the UI. Provider must set this if they
+         * wish to get the credential from a different device.
+         *
+         * <p> When constructing the {@link CredentialEntry} object, the {@code pendingIntent}
+         * must be set such that it leads to an activity that can provide UI to fulfill the request
+         * on a remote device. When user selects this {@code remoteCredentialEntry}, the system will
+         * invoke the {@code pendingIntent} set on the {@link CredentialEntry}.
+         *
+         * <p> Once the remote credential flow is complete, the {@link android.app.Activity}
+         * result should be set to {@link android.app.Activity#RESULT_OK} and an extra with the
+         * {@link CredentialProviderService#EXTRA_CREDENTIAL_RESULT} key should be populated
+         * with a {@link android.credentials.Credential} object.
+         */
+        public @NonNull Builder setRemoteCredentialEntry(@Nullable CredentialEntry
+                remoteCredentialEntry) {
+            mRemoteCredentialEntry = remoteCredentialEntry;
+            return this;
+        }
+
+        /**
+         * Adds a {@link CredentialEntry} to the list of entries to be displayed on
+         * the UI.
+         *
+         * @throws NullPointerException If the {@code credentialEntry} is null.
+         */
+        public @NonNull Builder addCredentialEntry(@NonNull CredentialEntry credentialEntry) {
+            mCredentialEntries.add(Objects.requireNonNull(credentialEntry));
+            return this;
+        }
+
+        /**
+         * Adds an {@link Action} to the list of actions to be displayed on
+         * the UI.
+         *
+         * <p> An {@code action} must be used for independent user actions,
+         * such as opening the app, intenting directly into a certain app activity etc. The
+         * {@code pendingIntent} set with the {@code action} must invoke the corresponding
+         * activity.
+         *
+         * @throws NullPointerException If {@code action} is null.
+         */
+        public @NonNull Builder addAction(@NonNull Action action) {
+            mActions.add(Objects.requireNonNull(action, "action must not be null"));
+            return this;
+        }
+
+        /**
+         * Sets the list of actions to be displayed on the UI.
+         *
+         * @throws NullPointerException If {@code actions} is null, or any of its elements
+         * is null.
+         */
+        public @NonNull Builder setActions(@NonNull List<Action> actions) {
+            mActions = Preconditions.checkCollectionElementsNotNull(actions,
+                    "actions");
+            return this;
+        }
+
+        /**
+         * Sets the list of credential entries to be displayed on the
+         * account selector UI.
+         *
+         * @throws NullPointerException If {@code credentialEntries} is null, or any of its
+         * elements is null.
+         */
+        public @NonNull Builder setCredentialEntries(
+                @NonNull List<CredentialEntry> credentialEntries) {
+            mCredentialEntries = Preconditions.checkCollectionElementsNotNull(
+                    credentialEntries,
+                    "credentialEntries");
+            return this;
+        }
+
+        /**
+         * Builds a {@link GetCredentialsResponse} instance.
+         *
+         * @throws IllegalStateException if {@code credentialEntries}, {@code actions}
+         * and {@code remoteCredentialEntry} are all null or empty.
+         */
+        public @NonNull CredentialsResponseContent build() {
+            if (mCredentialEntries != null && mCredentialEntries.isEmpty()
+                    && mActions != null && mActions.isEmpty() && mRemoteCredentialEntry == null) {
+                throw new IllegalStateException("credentialEntries and actions must not both "
+                        + "be empty");
+            }
+            return new CredentialsResponseContent(mCredentialEntries, mActions,
+                    mRemoteCredentialEntry);
+        }
+    }
+}
diff --git a/core/java/android/service/credentials/GetCredentialsRequest.java b/core/java/android/service/credentials/GetCredentialsRequest.java
index 03ba20e..9052b54 100644
--- a/core/java/android/service/credentials/GetCredentialsRequest.java
+++ b/core/java/android/service/credentials/GetCredentialsRequest.java
@@ -29,8 +29,6 @@
 
 /**
  * Request for getting user's credentials from a given credential provider.
- *
- * @hide
  */
 public final class GetCredentialsRequest implements Parcelable {
     /** Calling package of the app requesting for credentials. */
diff --git a/core/java/android/service/credentials/GetCredentialsResponse.java b/core/java/android/service/credentials/GetCredentialsResponse.java
index 979a699..5263141 100644
--- a/core/java/android/service/credentials/GetCredentialsResponse.java
+++ b/core/java/android/service/credentials/GetCredentialsResponse.java
@@ -26,12 +26,10 @@
 /**
  * Response from a credential provider, containing credential entries and other associated
  * data to be shown on the account selector UI.
- *
- * @hide
  */
 public final class GetCredentialsResponse implements Parcelable {
     /** Content to be used for the UI. */
-    private final @Nullable CredentialsDisplayContent mCredentialsDisplayContent;
+    private final @Nullable CredentialsResponseContent mCredentialsResponseContent;
 
     /**
      * Authentication action that must be launched and completed before showing any content
@@ -40,11 +38,17 @@
     private final @Nullable Action mAuthenticationAction;
 
     /**
-     * Creates a {@link GetCredentialsRequest} instance with an authentication action set.
+     * Creates a {@link GetCredentialsResponse} instance with an authentication {@link Action} set.
      * Providers must use this method when no content can be shown before authentication.
      *
-     * Once the authentication action activity is launched, and the user is authenticated, providers
-     * should create another response with {@link CredentialsDisplayContent} using
+     * <p> When the user selects this {@code authenticationAction}, the system invokes the
+     * corresponding {@code pendingIntent}. Once the authentication flow is complete,
+     * the {@link android.app.Activity} result should be set
+     * to {@link android.app.Activity#RESULT_OK} and the
+     * {@link CredentialProviderService#EXTRA_GET_CREDENTIALS_CONTENT_RESULT} extra should be set
+     * with a fully populated {@link CredentialsResponseContent} object.
+     * the authentication action activity is launched, and the user is authenticated, providers
+     * should create another response with {@link CredentialsResponseContent} using
      * {@code createWithDisplayContent}, and add that response to the result of the authentication
      * activity.
      *
@@ -58,27 +62,27 @@
     }
 
     /**
-     * Creates a {@link GetCredentialsRequest} instance with display content to be shown on the UI.
+     * Creates a {@link GetCredentialsRequest} instance with content to be shown on the UI.
      * Providers must use this method when there is content to be shown without top level
-     * authentication required.
+     * authentication required, including credential entries, action entries or a remote entry,
      *
-     * @throws NullPointerException If {@code credentialsDisplayContent} is null.
+     * @throws NullPointerException If {@code credentialsResponseContent} is null.
      */
-    public static @NonNull GetCredentialsResponse createWithDisplayContent(
-            @NonNull CredentialsDisplayContent credentialsDisplayContent) {
-        Objects.requireNonNull(credentialsDisplayContent,
-                "credentialsDisplayContent must not be null");
-        return new GetCredentialsResponse(credentialsDisplayContent, null);
+    public static @NonNull GetCredentialsResponse createWithResponseContent(
+            @NonNull CredentialsResponseContent credentialsResponseContent) {
+        Objects.requireNonNull(credentialsResponseContent,
+                "credentialsResponseContent must not be null");
+        return new GetCredentialsResponse(credentialsResponseContent, null);
     }
 
-    private GetCredentialsResponse(@Nullable CredentialsDisplayContent credentialsDisplayContent,
+    private GetCredentialsResponse(@Nullable CredentialsResponseContent credentialsResponseContent,
             @Nullable Action authenticationAction) {
-        mCredentialsDisplayContent = credentialsDisplayContent;
+        mCredentialsResponseContent = credentialsResponseContent;
         mAuthenticationAction = authenticationAction;
     }
 
     private GetCredentialsResponse(@NonNull Parcel in) {
-        mCredentialsDisplayContent = in.readTypedObject(CredentialsDisplayContent.CREATOR);
+        mCredentialsResponseContent = in.readTypedObject(CredentialsResponseContent.CREATOR);
         mAuthenticationAction = in.readTypedObject(Action.CREATOR);
     }
 
@@ -102,23 +106,23 @@
 
     @Override
     public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedObject(mCredentialsDisplayContent, flags);
+        dest.writeTypedObject(mCredentialsResponseContent, flags);
         dest.writeTypedObject(mAuthenticationAction, flags);
     }
 
     /**
-     * Returns the authentication action to be invoked before any other content
-     * can be shown to the user.
+     * If this response represents a top level authentication action, returns the authentication
+     * action to be invoked before any other content can be shown to the user.
      */
     public @Nullable Action getAuthenticationAction() {
         return mAuthenticationAction;
     }
 
     /**
-     * Returns the credentialDisplayContent that does not require authentication, and
-     * can be shown to the user on the account selector UI.
+     * Returns the actual content to be displayed on the selector, if this response does not
+     * require any top level authentication.
      */
-    public @Nullable CredentialsDisplayContent getCredentialsDisplayContent() {
-        return mCredentialsDisplayContent;
+    public @Nullable CredentialsResponseContent getCredentialsResponseContent() {
+        return mCredentialsResponseContent;
     }
 }
diff --git a/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl b/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl
new file mode 100644
index 0000000..ec0bc36
--- /dev/null
+++ b/core/java/android/service/credentials/IBeginCreateCredentialCallback.aidl
@@ -0,0 +1,13 @@
+package android.service.credentials;
+
+import android.service.credentials.BeginCreateCredentialResponse;
+
+/**
+ * Interface from the system to a credential provider service.
+ *
+ * @hide
+ */
+oneway interface IBeginCreateCredentialCallback {
+    void onSuccess(in BeginCreateCredentialResponse request);
+    void onFailure(int errorCode, in CharSequence message);
+}
\ No newline at end of file
diff --git a/core/java/android/service/credentials/ICreateCredentialCallback.aidl b/core/java/android/service/credentials/ICreateCredentialCallback.aidl
deleted file mode 100644
index 4cc76a4..0000000
--- a/core/java/android/service/credentials/ICreateCredentialCallback.aidl
+++ /dev/null
@@ -1,13 +0,0 @@
-package android.service.credentials;
-
-import android.service.credentials.CreateCredentialResponse;
-
-/**
- * Interface from the system to a credential provider service.
- *
- * @hide
- */
-oneway interface ICreateCredentialCallback {
-    void onSuccess(in CreateCredentialResponse request);
-    void onFailure(int errorCode, in CharSequence message);
-}
\ No newline at end of file
diff --git a/core/java/android/service/credentials/ICredentialProviderService.aidl b/core/java/android/service/credentials/ICredentialProviderService.aidl
index c21cefa..b9eb3ed 100644
--- a/core/java/android/service/credentials/ICredentialProviderService.aidl
+++ b/core/java/android/service/credentials/ICredentialProviderService.aidl
@@ -18,9 +18,9 @@
 
 import android.os.ICancellationSignal;
 import android.service.credentials.GetCredentialsRequest;
-import android.service.credentials.CreateCredentialRequest;
+import android.service.credentials.BeginCreateCredentialRequest;
 import android.service.credentials.IGetCredentialsCallback;
-import android.service.credentials.ICreateCredentialCallback;
+import android.service.credentials.IBeginCreateCredentialCallback;
 import android.os.ICancellationSignal;
 
 /**
@@ -30,5 +30,5 @@
  */
 interface ICredentialProviderService {
     ICancellationSignal onGetCredentials(in GetCredentialsRequest request, in IGetCredentialsCallback callback);
-    ICancellationSignal onCreateCredential(in CreateCredentialRequest request, in ICreateCredentialCallback callback);
+    ICancellationSignal onBeginCreateCredential(in BeginCreateCredentialRequest request, in IBeginCreateCredentialCallback callback);
 }
diff --git a/core/java/android/service/credentials/SaveEntry.java b/core/java/android/service/credentials/SaveEntry.java
deleted file mode 100644
index 55ff6ff..0000000
--- a/core/java/android/service/credentials/SaveEntry.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.credentials;
-
-import android.annotation.NonNull;
-import android.app.PendingIntent;
-import android.app.slice.Slice;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * An entry to be shown on the UI. This entry represents where the credential to be created will
- * be stored. Examples include user's account, family group etc.
- *
- * @hide
- */
-public final class SaveEntry implements Parcelable {
-    private final @NonNull Slice mSlice;
-    private final @NonNull PendingIntent mPendingIntent;
-
-    private SaveEntry(@NonNull Parcel in) {
-        mSlice = in.readTypedObject(Slice.CREATOR);
-        mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
-    }
-
-    public static final @NonNull Creator<SaveEntry> CREATOR = new Creator<SaveEntry>() {
-        @Override
-        public SaveEntry createFromParcel(@NonNull Parcel in) {
-            return new SaveEntry(in);
-        }
-
-        @Override
-        public SaveEntry[] newArray(int size) {
-            return new SaveEntry[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeTypedObject(mSlice, flags);
-        dest.writeTypedObject(mPendingIntent, flags);
-    }
-
-    /**
-     * Constructs a save entry to be displayed on the UI.
-     *
-     * @param slice the display content to be displayed on the UI, along with this entry
-     * @param pendingIntent the intent to be invoked when the user selects this entry
-     */
-    public SaveEntry(
-            @NonNull Slice slice,
-            @NonNull PendingIntent pendingIntent) {
-        this.mSlice = slice;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mSlice);
-        this.mPendingIntent = pendingIntent;
-        com.android.internal.util.AnnotationValidations.validate(
-                NonNull.class, null, mPendingIntent);
-    }
-
-    /** Returns the content to be displayed with this save entry on the UI. */
-    public @NonNull Slice getSlice() {
-        return mSlice;
-    }
-
-    /** Returns the pendingIntent to be invoked when this save entry on the UI is selectcd. */
-    public @NonNull PendingIntent getPendingIntent() {
-        return mPendingIntent;
-    }
-}
diff --git a/core/java/android/service/voice/HotwordAudioStream.java b/core/java/android/service/voice/HotwordAudioStream.java
index bf8ee47..6ae952c 100644
--- a/core/java/android/service/voice/HotwordAudioStream.java
+++ b/core/java/android/service/voice/HotwordAudioStream.java
@@ -47,6 +47,21 @@
 public final class HotwordAudioStream implements Parcelable {
 
     /**
+     * Key for int value to be read from {@link #getMetadata()}. The value is read by the system and
+     * is the length (in bytes) of the byte buffers created to copy bytes in the
+     * {@link #getAudioStreamParcelFileDescriptor()} written by the {@link HotwordDetectionService}.
+     * The buffer length should be chosen such that no additional latency is introduced. Typically,
+     * this should be <em>at least</em> the size of byte chunks written by the
+     * {@link HotwordDetectionService}.
+     *
+     * <p>If no value specified in the metadata for the buffer length, or if the value is less than
+     * 1, or if it is greater than 65,536, or if it is not an int, the default value of 2,560 will
+     * be used.</p>
+     */
+    public static final String KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES =
+            "android.service.voice.key.AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES";
+
+    /**
      * The {@link AudioFormat} of the audio stream.
      */
     @NonNull
@@ -92,41 +107,6 @@
         return new PersistableBundle();
     }
 
-    private String timestampToString() {
-        if (mTimestamp == null) {
-            return "";
-        }
-        return "TimeStamp:"
-                + " framePos=" + mTimestamp.framePosition
-                + " nanoTime=" + mTimestamp.nanoTime;
-    }
-
-    private void parcelTimestamp(Parcel dest, int flags) {
-        if (mTimestamp != null) {
-            // mTimestamp is not null, we write it to the parcel, set true.
-            dest.writeBoolean(true);
-            dest.writeLong(mTimestamp.framePosition);
-            dest.writeLong(mTimestamp.nanoTime);
-        } else {
-            // mTimestamp is null, we don't write any value out, set false.
-            dest.writeBoolean(false);
-        }
-    }
-
-    @Nullable
-    private static AudioTimestamp unparcelTimestamp(Parcel in) {
-        // If it is true, it means we wrote the value to the parcel before, parse it.
-        // Otherwise, return null.
-        if (in.readBoolean()) {
-            final AudioTimestamp timeStamp = new AudioTimestamp();
-            timeStamp.framePosition = in.readLong();
-            timeStamp.nanoTime = in.readLong();
-            return timeStamp;
-        } else {
-            return null;
-        }
-    }
-
     /**
      * Provides an instance of {@link Builder} with state corresponding to this instance.
      * @hide
@@ -229,7 +209,7 @@
         return "HotwordAudioStream { " +
                 "audioFormat = " + mAudioFormat + ", " +
                 "audioStreamParcelFileDescriptor = " + mAudioStreamParcelFileDescriptor + ", " +
-                "timestamp = " + timestampToString() + ", " +
+                "timestamp = " + mTimestamp + ", " +
                 "metadata = " + mMetadata +
         " }";
     }
@@ -278,7 +258,7 @@
         dest.writeByte(flg);
         dest.writeTypedObject(mAudioFormat, flags);
         dest.writeTypedObject(mAudioStreamParcelFileDescriptor, flags);
-        parcelTimestamp(dest, flags);
+        if (mTimestamp != null) dest.writeTypedObject(mTimestamp, flags);
         dest.writeTypedObject(mMetadata, flags);
     }
 
@@ -296,7 +276,7 @@
         byte flg = in.readByte();
         AudioFormat audioFormat = (AudioFormat) in.readTypedObject(AudioFormat.CREATOR);
         ParcelFileDescriptor audioStreamParcelFileDescriptor = (ParcelFileDescriptor) in.readTypedObject(ParcelFileDescriptor.CREATOR);
-        AudioTimestamp timestamp = unparcelTimestamp(in);
+        AudioTimestamp timestamp = (flg & 0x4) == 0 ? null : (AudioTimestamp) in.readTypedObject(AudioTimestamp.CREATOR);
         PersistableBundle metadata = (PersistableBundle) in.readTypedObject(PersistableBundle.CREATOR);
 
         this.mAudioFormat = audioFormat;
@@ -449,10 +429,10 @@
     }
 
     @DataClass.Generated(
-            time = 1666342101364L,
+            time = 1669916341034L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/service/voice/HotwordAudioStream.java",
-            inputSignatures = "private final @android.annotation.NonNull android.media.AudioFormat mAudioFormat\nprivate final @android.annotation.NonNull android.os.ParcelFileDescriptor mAudioStreamParcelFileDescriptor\nprivate final @android.annotation.Nullable android.media.AudioTimestamp mTimestamp\nprivate final @android.annotation.NonNull android.os.PersistableBundle mMetadata\nprivate static  android.media.AudioTimestamp defaultTimestamp()\nprivate static  android.os.PersistableBundle defaultMetadata()\nprivate  java.lang.String timestampToString()\nprivate  void parcelTimestamp(android.os.Parcel,int)\nprivate static @android.annotation.Nullable android.media.AudioTimestamp unparcelTimestamp(android.os.Parcel)\npublic  android.service.voice.HotwordAudioStream.Builder buildUpon()\nclass HotwordAudioStream extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genParcelable=true, genToString=true)")
+            inputSignatures = "public static final  java.lang.String KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES\nprivate final @android.annotation.NonNull android.media.AudioFormat mAudioFormat\nprivate final @android.annotation.NonNull android.os.ParcelFileDescriptor mAudioStreamParcelFileDescriptor\nprivate final @android.annotation.Nullable android.media.AudioTimestamp mTimestamp\nprivate final @android.annotation.NonNull android.os.PersistableBundle mMetadata\nprivate static  android.media.AudioTimestamp defaultTimestamp()\nprivate static  android.os.PersistableBundle defaultMetadata()\npublic  android.service.voice.HotwordAudioStream.Builder buildUpon()\nclass HotwordAudioStream extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index aebd91a..84a233f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -2183,6 +2183,17 @@
         }
     }
 
+    /**
+     * Returns a Looper which messages such as {@link WallpaperService#DO_ATTACH},
+     * {@link WallpaperService#DO_DETACH} etc. are sent to.
+     * By default, returns the process's main looper.
+     * @hide
+     */
+    @NonNull
+    public Looper onProvideEngineLooper() {
+        return super.getMainLooper();
+    }
+
     private boolean isValid(RectF area) {
         if (area == null) return false;
         boolean valid = area.bottom > area.top && area.left < area.right
@@ -2215,12 +2226,12 @@
         Engine mEngine;
         @SetWallpaperFlags int mWhich;
 
-        IWallpaperEngineWrapper(WallpaperService context,
+        IWallpaperEngineWrapper(WallpaperService service,
                 IWallpaperConnection conn, IBinder windowToken,
                 int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
                 int displayId, @SetWallpaperFlags int which) {
             mWallpaperManager = getSystemService(WallpaperManager.class);
-            mCaller = new HandlerCaller(context, context.getMainLooper(), this, true);
+            mCaller = new HandlerCaller(service, service.onProvideEngineLooper(), this, true);
             mConnection = conn;
             mWindowToken = windowToken;
             mWindowType = windowType;
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e5c9adb..dded76c 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -26,7 +26,6 @@
 import android.os.Handler;
 import android.os.HandlerExecutor;
 import android.os.Looper;
-import android.telephony.Annotation.CallState;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
@@ -726,7 +725,7 @@
      */
     @Deprecated
     @RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
-    public void onCallStateChanged(@CallState int state, String phoneNumber) {
+    public void onCallStateChanged(@Annotation.CallState int state, String phoneNumber) {
         // default implementation empty
     }
 
@@ -1569,12 +1568,48 @@
                     () -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state)));
         }
 
-        public void onCallAttributesChanged(CallAttributes callAttributes) {
+        public void onCallStatesChanged(List<CallState> callStateList) {
             PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
             if (psl == null) return;
 
+            if (callStateList == null) return;
+            CallAttributes ca;
+            if (callStateList.isEmpty()) {
+                ca = new CallAttributes(
+                        new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+            } else {
+                int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                for (CallState cs : callStateList) {
+                    switch (cs.getCallClassification()) {
+                        case CallState.CALL_CLASSIFICATION_FOREGROUND:
+                            foregroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_BACKGROUND:
+                            backgroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_RINGING:
+                            ringingCallState = cs.getCallState();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                ca = new CallAttributes(
+                        new PreciseCallState(
+                                ringingCallState, foregroundCallState, backgroundCallState,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        callStateList.get(0).getNetworkType(),
+                        callStateList.get(0).getCallQuality());
+            }
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes)));
+                    () -> mExecutor.execute(
+                            () -> psl.onCallAttributesChanged(ca)));
         }
 
         public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index e8960b8..257f3b7 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -27,6 +27,7 @@
 import android.os.Build;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.ims.ImsReasonInfo;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.IPhoneStateListener;
@@ -62,7 +63,7 @@
  * appropriate sub-interfaces.
  */
 public class TelephonyCallback {
-
+    private static final String LOG_TAG = "TelephonyCallback";
     /**
      * Experiment flag to set the per-pid registration limit for TelephonyCallback
      *
@@ -1332,7 +1333,9 @@
     @SystemApi
     public interface CallAttributesListener {
         /**
-         * Callback invoked when the call attributes changes on the registered subscription.
+         * Callback invoked when the call attributes changes on the active call on the registered
+         * subscription. If the user swaps between a foreground and background call the call
+         * attributes will be reported for the active call only.
          * Note, the registration subscription ID comes from {@link TelephonyManager} object
          * which registers TelephonyCallback by
          * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
@@ -1346,9 +1349,77 @@
          * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
          *
          * @param callAttributes the call attributes
+         * @deprecated Use onCallStatesChanged({@link List<CallState>}) to get each of call
+         *          state for all ongoing calls on the subscription.
          */
         @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
-        void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+        @Deprecated
+        default void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
+            Log.w(LOG_TAG, "onCallAttributesChanged(List<CallState>) should be "
+                    + "overridden.");
+        }
+
+        /**
+         * Callback invoked when the call attributes changes on the ongoing calls on the registered
+         * subscription. If there are 1 foreground and 1 background call, Two {@link CallState}
+         * will be passed.
+         * Note, the registration subscription ID comes from {@link TelephonyManager} object
+         * which registers TelephonyCallback by
+         * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+         * If this TelephonyManager object was created with
+         * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+         * subscription ID. Otherwise, this callback applies to
+         * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+         * In the event that there are no active(state is not
+         * {@link PreciseCallState#PRECISE_CALL_STATE_IDLE}) calls, this API will report empty list.
+         *
+         * The calling app should have carrier privileges
+         * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+         * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+         *
+         * @param callStateList the list of call states for each ongoing call. If there are
+         *                           a active call and a holding call, 1 call attributes for
+         *                           {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}  and another
+         *                           for {@link PreciseCallState#PRECISE_CALL_STATE_HOLDING}
+         *                           will be in this list.
+         */
+        // Added as default for backward compatibility
+        @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+        default void onCallStatesChanged(@NonNull List<CallState> callStateList) {
+            if (callStateList.size() > 0) {
+                int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+                for (CallState cs : callStateList) {
+                    switch (cs.getCallClassification()) {
+                        case CallState.CALL_CLASSIFICATION_FOREGROUND:
+                            foregroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_BACKGROUND:
+                            backgroundCallState = cs.getCallState();
+                            break;
+                        case CallState.CALL_CLASSIFICATION_RINGING:
+                            ringingCallState = cs.getCallState();
+                            break;
+                        default:
+                            break;
+                    }
+                }
+                onCallAttributesChanged(new CallAttributes(
+                        new PreciseCallState(
+                                ringingCallState, foregroundCallState, backgroundCallState,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        callStateList.get(0).getNetworkType(),
+                        callStateList.get(0).getCallQuality()));
+            } else {
+                onCallAttributesChanged(new CallAttributes(
+                        new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                PreciseCallState.PRECISE_CALL_STATE_IDLE,
+                                DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+                        TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()));
+            }
+        }
     }
 
     /**
@@ -1702,14 +1773,13 @@
                     () -> mExecutor.execute(() -> listener.onRadioPowerStateChanged(state)));
         }
 
-        public void onCallAttributesChanged(CallAttributes callAttributes) {
+        public void onCallStatesChanged(List<CallState> callStateList) {
             CallAttributesListener listener =
                     (CallAttributesListener) mTelephonyCallbackWeakRef.get();
             if (listener == null) return;
 
             Binder.withCleanCallingIdentity(
-                    () -> mExecutor.execute(() -> listener.onCallAttributesChanged(
-                            callAttributes)));
+                    () -> mExecutor.execute(() -> listener.onCallStatesChanged(callStateList)));
         }
 
         public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index a3696e3..0a1538de 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -32,13 +32,13 @@
 import android.telephony.Annotation.DataActivityType;
 import android.telephony.Annotation.DisconnectCauses;
 import android.telephony.Annotation.NetworkType;
-import android.telephony.Annotation.PreciseCallStates;
 import android.telephony.Annotation.PreciseDisconnectCauses;
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SimActivationState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsReasonInfo;
 import android.util.ArraySet;
 import android.util.Log;
@@ -741,17 +741,20 @@
      * @param slotIndex for which precise call state changed. Can be derived from subId except when
      * subId is invalid.
      * @param subId for which precise call state changed.
-     * @param ringCallPreciseState ringCall state.
-     * @param foregroundCallPreciseState foreground call state.
-     * @param backgroundCallPreciseState background call state.
+     * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+     * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for
+     *                   ringing, foreground & background calls.
+     * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+     *                        background calls.
+     * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
      */
     public void notifyPreciseCallState(int slotIndex, int subId,
-            @PreciseCallStates int ringCallPreciseState,
-            @PreciseCallStates int foregroundCallPreciseState,
-            @PreciseCallStates int backgroundCallPreciseState) {
+            @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+            @Annotation.ImsCallServiceType int[] imsServiceTypes,
+            @Annotation.ImsCallType int[] imsCallTypes) {
         try {
-            sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
-                foregroundCallPreciseState, backgroundCallPreciseState);
+            sRegistry.notifyPreciseCallState(slotIndex, subId, callStates,
+                    imsCallIds, imsServiceTypes, imsCallTypes);
         } catch (RemoteException ex) {
             // system process is dead
             throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/text/Highlights.java b/core/java/android/text/Highlights.java
new file mode 100644
index 0000000..356dfca
--- /dev/null
+++ b/core/java/android/text/Highlights.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.text;
+
+import android.graphics.Paint;
+import android.util.Pair;
+
+import androidx.annotation.IntRange;
+import androidx.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A class that represents of the highlight of the text.
+ */
+public class Highlights {
+    private final List<Pair<Paint, int[]>> mHighlights;
+
+    private Highlights(List<Pair<Paint, int[]>> highlights) {
+        mHighlights = highlights;
+    }
+
+    /**
+     * Returns a number of highlight.
+     *
+     * @return a number of highlight.
+     *
+     * @see Builder#addRange(Paint, int, int)
+     * @see Builder#addRanges(Paint, int...)
+     */
+    public @IntRange(from = 0) int getSize() {
+        return mHighlights.size();
+    }
+
+    /**
+     * Returns a paint used for the i-th highlight.
+     *
+     * @param index an index of the highlight. Must be between 0 and {@link #getSize()}
+     * @return a paint object
+     *
+     * @see Builder#addRange(Paint, int, int)
+     * @see Builder#addRanges(Paint, int...)
+     */
+    public @NonNull Paint getPaint(@IntRange(from = 0) int index) {
+        return mHighlights.get(index).first;
+    }
+
+    /**
+     * Returns ranges of the i-th highlight.
+     *
+     * Ranges are represented of flattened inclusive start and exclusive end integers array. The
+     * inclusive start offset of the {@code i}-th range is stored in {@code 2 * i}-th of the array.
+     * The exclusive end offset of the {@code i}-th range is stored in {@code 2* i + 1}-th of the
+     * array. For example, the two ranges: (1, 2) and (3, 4) are flattened into single int array
+     * [1, 2, 3, 4].
+     *
+     * @param index an index of the highlight. Must be between 0 and {@link #getSize()}
+     * @return a paint object
+     *
+     * @see Builder#addRange(Paint, int, int)
+     * @see Builder#addRanges(Paint, int...)
+     */
+    public @NonNull int[] getRanges(int index) {
+        return mHighlights.get(index).second;
+    }
+
+    /**
+     * A builder for the Highlights.
+     */
+    public static final class Builder {
+        private final List<Pair<Paint, int[]>> mHighlights = new ArrayList<>();
+
+        /**
+         * Add single range highlight.
+         *
+         * @param paint a paint object used for drawing highlight path.
+         * @param start an inclusive offset of the text.
+         * @param end an exclusive offset of the text.
+         * @return this builder instance.
+         */
+        public @NonNull Builder addRange(@NonNull Paint paint, @IntRange(from = 0) int start,
+                @IntRange(from = 0) int end) {
+            if (start > end) {
+                throw new IllegalArgumentException("start must not be larger than end: "
+                        + start + ", " + end);
+            }
+            Objects.requireNonNull(paint);
+
+            int[] range = new int[] {start, end};
+            mHighlights.add(new Pair<>(paint, range));
+            return this;
+        }
+
+        /**
+         * Add multiple ranges highlight.
+         *
+         * @param paint a paint object used for drawing highlight path.
+         * @param ranges a flatten ranges. The {@code 2 * i}-th element is an inclusive start offset
+         *              of the {@code i}-th character. The {@code 2 * i + 1}-th element is an
+         *              exclusive end offset of the {@code i}-th character.
+         * @return this builder instance.
+         */
+        public @NonNull Builder addRanges(@NonNull Paint paint, @NonNull int... ranges) {
+            if (ranges.length % 2 == 1) {
+                throw new IllegalArgumentException(
+                        "Flatten ranges must have even numbered elements");
+            }
+            for (int j = 0; j < ranges.length / 2; ++j) {
+                int start = ranges[j * 2];
+                int end = ranges[j * 2 + 1];
+                if (start > end) {
+                    throw new IllegalArgumentException(
+                            "Reverse range found in the flatten range: " + Arrays.toString(
+                                    ranges));
+                }
+            }
+            Objects.requireNonNull(paint);
+            mHighlights.add(new Pair<>(paint, ranges));
+            return this;
+        }
+
+        /**
+         * Build a new Highlights instance.
+         *
+         * @return a new Highlights instance.
+         */
+        public @NonNull Highlights build() {
+            return new Highlights(mHighlights);
+        }
+    }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 54ec07e..64dc16d 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -44,6 +44,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * A base class that manages text layout in visual elements on
@@ -347,9 +348,13 @@
 
     /**
      * Draw this Layout on the specified Canvas.
+     *
+     * This API draws background first, then draws text on top of it.
+     *
+     * @see #draw(Canvas, List, List, Path, Paint, int)
      */
     public void draw(Canvas c) {
-        draw(c, null, null, 0);
+        draw(c, (Path) null, (Paint) null, 0);
     }
 
     /**
@@ -357,23 +362,142 @@
      * between the background and the text.
      *
      * @param canvas the canvas
-     * @param highlight the path of the highlight or cursor; can be null
-     * @param highlightPaint the paint for the highlight
+     * @param selectionHighlight the path of the selection highlight or cursor; can be null
+     * @param selectionHighlightPaint the paint for the selection highlight
      * @param cursorOffsetVertical the amount to temporarily translate the
      *        canvas while rendering the highlight
+     *
+     * @see #draw(Canvas, List, List, Path, Paint, int)
      */
-    public void draw(Canvas canvas, Path highlight, Paint highlightPaint,
+    public void draw(
+            Canvas canvas, Path selectionHighlight,
+            Paint selectionHighlightPaint, int cursorOffsetVertical) {
+        draw(canvas, null, null, selectionHighlight, selectionHighlightPaint, cursorOffsetVertical);
+    }
+
+    /**
+     * Draw this layout on the specified canvas.
+     *
+     * This API draws background first, then draws highlight paths on top of it, then draws
+     * selection or cursor, then finally draws text on top of it.
+     *
+     * @see #drawBackground(Canvas)
+     * @see #drawText(Canvas)
+     *
+     * @param canvas the canvas
+     * @param highlightPaths the path of the highlights. The highlightPaths and highlightPaints must
+     *                      have the same length and aligned in the same order. For example, the
+     *                      paint of the n-th of the highlightPaths should be stored at the n-th of
+     *                      highlightPaints.
+     * @param highlightPaints the paints for the highlights. The highlightPaths and highlightPaints
+     *                        must have the same length and aligned in the same order. For example,
+     *                        the paint of the n-th of the highlightPaths should be stored at the
+     *                        n-th of highlightPaints.
+     * @param selectionPath the selection or cursor path
+     * @param selectionPaint the paint for the selection or cursor.
+     * @param cursorOffsetVertical the amount to temporarily translate the canvas while rendering
+     *                            the highlight
+     */
+    public void draw(@NonNull Canvas canvas,
+            @Nullable List<Path> highlightPaths,
+            @Nullable List<Paint> highlightPaints,
+            @Nullable Path selectionPath,
+            @Nullable Paint selectionPaint,
             int cursorOffsetVertical) {
         final long lineRange = getLineRangeForDraw(canvas);
         int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
         int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
         if (lastLine < 0) return;
 
-        drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
-                firstLine, lastLine);
+        drawWithoutText(canvas, highlightPaths, highlightPaints, selectionPath, selectionPaint,
+                cursorOffsetVertical, firstLine, lastLine);
         drawText(canvas, firstLine, lastLine);
     }
 
+    /**
+     * Draw text part of this layout.
+     *
+     * Different from {@link #draw(Canvas, List, List, Path, Paint, int)} API, this API only draws
+     * text part, not drawing highlights, selections, or backgrounds.
+     *
+     * @see #draw(Canvas, List, List, Path, Paint, int)
+     * @see #drawBackground(Canvas)
+     *
+     * @param canvas the canvas
+     */
+    public void drawText(@NonNull Canvas canvas) {
+        final long lineRange = getLineRangeForDraw(canvas);
+        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
+        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
+        if (lastLine < 0) return;
+        drawText(canvas, firstLine, lastLine);
+    }
+
+    /**
+     * Draw background of this layout.
+     *
+     * Different from {@link #draw(Canvas, List, List, Path, Paint, int)} API, this API only draws
+     * background, not drawing text, highlights or selections. The background here is drawn by
+     * {@link LineBackgroundSpan} attached to the text.
+     *
+     * @see #draw(Canvas, List, List, Path, Paint, int)
+     * @see #drawText(Canvas)
+     *
+     * @param canvas the canvas
+     */
+    public void drawBackground(@NonNull Canvas canvas) {
+        final long lineRange = getLineRangeForDraw(canvas);
+        int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
+        int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
+        if (lastLine < 0) return;
+        drawBackground(canvas, firstLine, lastLine);
+    }
+
+    /**
+     * @hide public for Editor.java
+     */
+    public void drawWithoutText(
+            @NonNull Canvas canvas,
+            @Nullable List<Path> highlightPaths,
+            @Nullable List<Paint> highlightPaints,
+            @Nullable Path selectionPath,
+            @Nullable Paint selectionPaint,
+            int cursorOffsetVertical,
+            int firstLine,
+            int lastLine) {
+        drawBackground(canvas, firstLine, lastLine);
+        if (highlightPaths == null && highlightPaints == null) {
+            return;
+        }
+        if (cursorOffsetVertical != 0) canvas.translate(0, cursorOffsetVertical);
+        try {
+            if (highlightPaths != null) {
+                if (highlightPaints == null) {
+                    throw new IllegalArgumentException(
+                            "if highlight is specified, highlightPaint must be specified.");
+                }
+                if (highlightPaints.size() != highlightPaths.size()) {
+                    throw new IllegalArgumentException(
+                            "The highlight path size is different from the size of highlight"
+                                    + " paints");
+                }
+                for (int i = 0; i < highlightPaths.size(); ++i) {
+                    final Path highlight = highlightPaths.get(i);
+                    final Paint highlightPaint = highlightPaints.get(i);
+                    if (highlight != null) {
+                        canvas.drawPath(highlight, highlightPaint);
+                    }
+                }
+            }
+
+            if (selectionPath != null) {
+                canvas.drawPath(selectionPath, selectionPaint);
+            }
+        } finally {
+            if (cursorOffsetVertical != 0) canvas.translate(0, -cursorOffsetVertical);
+        }
+    }
+
     private boolean isJustificationRequired(int lineNum) {
         if (mJustificationMode == JUSTIFICATION_MODE_NONE) return false;
         final int lineEnd = getLineEnd(lineNum);
@@ -635,8 +759,9 @@
      * @hide
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    public void drawBackground(Canvas canvas, Path highlight, Paint highlightPaint,
-            int cursorOffsetVertical, int firstLine, int lastLine) {
+    public void drawBackground(
+            @NonNull Canvas canvas,
+            int firstLine, int lastLine) {
         // First, draw LineBackgroundSpans.
         // LineBackgroundSpans know nothing about the alignment, margins, or
         // direction of the layout or line.  XXX: Should they?
@@ -700,14 +825,6 @@
             }
             mLineBackgroundSpans.recycle();
         }
-
-        // There can be a highlight even without spans if we are drawing
-        // a non-spanned transformation of a spanned editing buffer.
-        if (highlight != null) {
-            if (cursorOffsetVertical != 0) canvas.translate(0, cursorOffsetVertical);
-            canvas.drawPath(highlight, highlightPaint);
-            if (cursorOffsetVertical != 0) canvas.translate(0, -cursorOffsetVertical);
-        }
     }
 
     /**
diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java
index 517d982..959295b 100755
--- a/core/java/android/util/DisplayMetrics.java
+++ b/core/java/android/util/DisplayMetrics.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.res.FontScaleConverter;
 import android.os.SystemProperties;
 
 /**
@@ -273,6 +274,15 @@
      * increments at runtime based on a user preference for the font size.
      */
     public float scaledDensity;
+
+    /**
+     * If non-null, this will be used to calculate font sizes instead of {@link #scaledDensity}.
+     *
+     * @hide
+     */
+    @Nullable
+    public FontScaleConverter fontScaleConverter;
+
     /**
      * The exact physical pixels per inch of the screen in the X dimension.
      */
@@ -350,6 +360,7 @@
         noncompatScaledDensity = o.noncompatScaledDensity;
         noncompatXdpi = o.noncompatXdpi;
         noncompatYdpi = o.noncompatYdpi;
+        fontScaleConverter = o.fontScaleConverter;
     }
     
     public void setToDefaults() {
@@ -367,6 +378,7 @@
         noncompatScaledDensity = scaledDensity;
         noncompatXdpi = xdpi;
         noncompatYdpi = ydpi;
+        fontScaleConverter = null;
     }
 
     @Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 4afd268..4277d01 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -122,6 +122,13 @@
     public static final String SETTINGS_NEW_KEYBOARD_TRACKPAD = "settings_new_keyboard_trackpad";
 
     /**
+     * Enable trackpad gesture settings UI
+     * @hide
+     */
+    public static final String SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE =
+            "settings_new_keyboard_trackpad_gesture";
+
+    /**
      * Enable the new pages which is implemented with SPA.
      * @hide
      */
@@ -133,6 +140,13 @@
     public static final String SETTINGS_ADB_METRICS_WRITER = "settings_adb_metrics_writer";
 
     /**
+     * Flag to show stylus-specific preferences in Connected Devices
+     * @hide
+     */
+    public static final String SETTINGS_SHOW_STYLUS_PREFERENCES =
+            "settings_show_stylus_preferences";
+
+    /**
      * Flag to enable/disable biometrics enrollment v2
      * @hide
      */
@@ -171,12 +185,15 @@
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_SHORTCUT, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY, "false");
         DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD, "false");
+        DEFAULT_FLAGS.put(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE, "false");
         DEFAULT_FLAGS.put(SETTINGS_ENABLE_SPA, "false");
         DEFAULT_FLAGS.put(SETTINGS_ADB_METRICS_WRITER, "false");
+        DEFAULT_FLAGS.put(SETTINGS_SHOW_STYLUS_PREFERENCES, "false");
         DEFAULT_FLAGS.put(SETTINGS_BIOMETRICS2_ENROLLMENT, "false");
     }
 
     private static final Set<String> PERSISTENT_FLAGS;
+
     static {
         PERSISTENT_FLAGS = new HashSet<>();
         PERSISTENT_FLAGS.add(SETTINGS_ALLOW_INTENT_REDIRECTION_FOR_CLONE_PROFILE);
@@ -190,6 +207,7 @@
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_SHORTCUT);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_MODIFIER_KEY);
         PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD);
+        PERSISTENT_FLAGS.add(SETTINGS_NEW_KEYBOARD_TRACKPAD_GESTURE);
     }
 
     /**
diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java
index 7b28b8a..bc0e35d 100644
--- a/core/java/android/util/IntArray.java
+++ b/core/java/android/util/IntArray.java
@@ -234,4 +234,23 @@
     public int[] toArray() {
         return Arrays.copyOf(mValues, mSize);
     }
+
+    @Override
+    public String toString() {
+        // Code below is copied from Arrays.toString(), but uses mSize in the lopp (it cannot call
+        // Arrays.toString() directly as it would return the unused elements as well)
+        int iMax = mSize - 1;
+        if (iMax == -1) {
+            return "[]";
+        }
+        StringBuilder b = new StringBuilder();
+        b.append('[');
+        for (int i = 0;; i++) {
+            b.append(mValues[i]);
+            if (i == iMax) {
+                return b.append(']').toString();
+            }
+            b.append(", ");
+        }
+    }
 }
diff --git a/core/java/android/util/RotationUtils.java b/core/java/android/util/RotationUtils.java
index c54d9b6..3e7c67e 100644
--- a/core/java/android/util/RotationUtils.java
+++ b/core/java/android/util/RotationUtils.java
@@ -25,6 +25,7 @@
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.view.Surface.Rotation;
 import android.view.SurfaceControl;
@@ -193,6 +194,29 @@
     }
 
     /**
+     * Same as {@link #rotatePoint}, but for float coordinates.
+     */
+    public static void rotatePointF(PointF inOutPoint, @Rotation int rotation,
+            float parentW, float parentH) {
+        float origX = inOutPoint.x;
+        switch (rotation) {
+            case ROTATION_0:
+                return;
+            case ROTATION_90:
+                inOutPoint.x = inOutPoint.y;
+                inOutPoint.y = parentW - origX;
+                return;
+            case ROTATION_180:
+                inOutPoint.x = parentW - inOutPoint.x;
+                inOutPoint.y = parentH - inOutPoint.y;
+                return;
+            case ROTATION_270:
+                inOutPoint.x = parentH - inOutPoint.y;
+                inOutPoint.y = origX;
+        }
+    }
+
+    /**
      * Sets a matrix such that given a rotation, it transforms physical display
      * coordinates to that rotation's logical coordinates.
      *
diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java
index 44318bb..7e054fc 100644
--- a/core/java/android/util/TypedValue.java
+++ b/core/java/android/util/TypedValue.java
@@ -408,7 +408,14 @@
         case COMPLEX_UNIT_DIP:
             return value * metrics.density;
         case COMPLEX_UNIT_SP:
-            return value * metrics.scaledDensity;
+                if (metrics.fontScaleConverter != null) {
+                    return applyDimension(
+                            COMPLEX_UNIT_DIP,
+                            metrics.fontScaleConverter.convertSpToDp(value),
+                            metrics);
+                } else {
+                    return value * metrics.scaledDensity;
+                }
         case COMPLEX_UNIT_PT:
             return value * metrics.xdpi * (1.0f/72);
         case COMPLEX_UNIT_IN:
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 5933ae4..a42d3eb 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -319,6 +319,19 @@
     public static final int FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 10;
 
     /**
+     * Flag: Indicates that the display maintains its own focus and touch mode.
+     *
+     * This flag is similar to {@link com.android.internal.R.bool.config_perDisplayFocusEnabled} in
+     * behavior, but only applies to the specific display instead of system-wide to all displays.
+     *
+     * Note: The display must be trusted in order to have its own focus.
+     *
+     * @see #FLAG_TRUSTED
+     * @hide
+     */
+    public static final int FLAG_OWN_FOCUS = 1 << 11;
+
+    /**
      * Display flag: Indicates that the contents of the display should not be scaled
      * to fit the physical screen dimensions.  Used for development only to emulate
      * devices with smaller physicals screens while preserving density.
@@ -996,6 +1009,28 @@
     }
 
     /**
+     * Returns the {@link DisplayShape} which is based on display coordinates.
+     *
+     * To get the {@link DisplayShape} based on the window frame, use
+     * {@link WindowInsets#getDisplayShape()} instead.
+     *
+     * @see DisplayShape
+     */
+    @SuppressLint("VisiblySynchronized")
+    @NonNull
+    public DisplayShape getShape() {
+        synchronized (mLock) {
+            updateDisplayInfoLocked();
+            final DisplayShape displayShape = mDisplayInfo.displayShape;
+            final @Surface.Rotation int rotation = getLocalRotation();
+            if (displayShape != null && rotation != mDisplayInfo.rotation) {
+                return displayShape.setRotation(rotation);
+            }
+            return displayShape;
+        }
+    }
+
+    /**
      * Gets the pixel format of the display.
      * @return One of the constants defined in {@link android.graphics.PixelFormat}.
      *
@@ -1907,13 +1942,16 @@
         private final float mRefreshRate;
         @NonNull
         private final float[] mAlternativeRefreshRates;
+        @NonNull
+        @HdrCapabilities.HdrType
+        private final int[] mSupportedHdrTypes;
 
         /**
          * @hide
          */
         @TestApi
         public Mode(int width, int height, float refreshRate) {
-            this(INVALID_MODE_ID, width, height, refreshRate, new float[0]);
+            this(INVALID_MODE_ID, width, height, refreshRate, new float[0], new int[0]);
         }
 
         /**
@@ -1921,14 +1959,14 @@
          */
         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
         public Mode(int modeId, int width, int height, float refreshRate) {
-            this(modeId, width, height, refreshRate, new float[0]);
+            this(modeId, width, height, refreshRate, new float[0], new int[0]);
         }
 
         /**
          * @hide
          */
         public Mode(int modeId, int width, int height, float refreshRate,
-                float[] alternativeRefreshRates) {
+                float[] alternativeRefreshRates, @HdrCapabilities.HdrType int[] supportedHdrTypes) {
             mModeId = modeId;
             mWidth = width;
             mHeight = height;
@@ -1936,6 +1974,8 @@
             mAlternativeRefreshRates =
                     Arrays.copyOf(alternativeRefreshRates, alternativeRefreshRates.length);
             Arrays.sort(mAlternativeRefreshRates);
+            mSupportedHdrTypes = Arrays.copyOf(supportedHdrTypes, supportedHdrTypes.length);
+            Arrays.sort(mSupportedHdrTypes);
         }
 
         /**
@@ -2010,6 +2050,15 @@
         }
 
         /**
+         * Returns the supported {@link HdrCapabilities} HDR_TYPE_* for this specific mode
+         */
+        @NonNull
+        @HdrCapabilities.HdrType
+        public int[] getSupportedHdrTypes() {
+            return mSupportedHdrTypes;
+        }
+
+        /**
          * Returns {@code true} if this mode matches the given parameters.
          *
          * @hide
@@ -2083,7 +2132,8 @@
             }
             Mode that = (Mode) other;
             return mModeId == that.mModeId && matches(that.mWidth, that.mHeight, that.mRefreshRate)
-                    && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates);
+                    && Arrays.equals(mAlternativeRefreshRates, that.mAlternativeRefreshRates)
+                    && Arrays.equals(mSupportedHdrTypes, that.mSupportedHdrTypes);
         }
 
         @Override
@@ -2094,6 +2144,7 @@
             hash = hash * 17 + mHeight;
             hash = hash * 17 + Float.floatToIntBits(mRefreshRate);
             hash = hash * 17 + Arrays.hashCode(mAlternativeRefreshRates);
+            hash = hash * 17 + Arrays.hashCode(mSupportedHdrTypes);
             return hash;
         }
 
@@ -2106,6 +2157,8 @@
                     .append(", fps=").append(mRefreshRate)
                     .append(", alternativeRefreshRates=")
                     .append(Arrays.toString(mAlternativeRefreshRates))
+                    .append(", supportedHdrTypes=")
+                    .append(Arrays.toString(mSupportedHdrTypes))
                     .append("}")
                     .toString();
         }
@@ -2116,7 +2169,8 @@
         }
 
         private Mode(Parcel in) {
-            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray());
+            this(in.readInt(), in.readInt(), in.readInt(), in.readFloat(), in.createFloatArray(),
+                    in.createIntArray());
         }
 
         @Override
@@ -2126,6 +2180,7 @@
             out.writeInt(mHeight);
             out.writeFloat(mRefreshRate);
             out.writeFloatArray(mAlternativeRefreshRates);
+            out.writeIntArray(mSupportedHdrTypes);
         }
 
         @SuppressWarnings("hiding")
@@ -2291,6 +2346,9 @@
         /**
          * Gets the supported HDR types of this display.
          * Returns empty array if HDR is not supported by the display.
+         *
+         * @deprecated use {@link Display#getMode()}
+         * and {@link Mode#getSupportedHdrTypes()} instead
          */
         public @HdrType int[] getSupportedHdrTypes() {
             return mSupportedHdrTypes;
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 0ba3072..138017c 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -323,6 +323,9 @@
     @Surface.Rotation
     public int installOrientation;
 
+    @Nullable
+    public DisplayShape displayShape;
+
     public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
         @Override
         public DisplayInfo createFromParcel(Parcel source) {
@@ -395,7 +398,8 @@
                 && brightnessMaximum == other.brightnessMaximum
                 && brightnessDefault == other.brightnessDefault
                 && Objects.equals(roundedCorners, other.roundedCorners)
-                && installOrientation == other.installOrientation;
+                && installOrientation == other.installOrientation
+                && Objects.equals(displayShape, other.displayShape);
     }
 
     @Override
@@ -448,6 +452,7 @@
         brightnessDefault = other.brightnessDefault;
         roundedCorners = other.roundedCorners;
         installOrientation = other.installOrientation;
+        displayShape = other.displayShape;
     }
 
     public void readFromParcel(Parcel source) {
@@ -506,6 +511,7 @@
             userDisabledHdrTypes[i] = source.readInt();
         }
         installOrientation = source.readInt();
+        displayShape = source.readTypedObject(DisplayShape.CREATOR);
     }
 
     @Override
@@ -562,6 +568,7 @@
             dest.writeInt(userDisabledHdrTypes[i]);
         }
         dest.writeInt(installOrientation);
+        dest.writeTypedObject(displayShape, flags);
     }
 
     @Override
diff --git a/core/java/android/view/DisplayShape.aidl b/core/java/android/view/DisplayShape.aidl
new file mode 100644
index 0000000..af8b417
--- /dev/null
+++ b/core/java/android/view/DisplayShape.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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;
+
+parcelable DisplayShape;
diff --git a/core/java/android/view/DisplayShape.java b/core/java/android/view/DisplayShape.java
new file mode 100644
index 0000000..43bd773
--- /dev/null
+++ b/core/java/android/view/DisplayShape.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 static android.view.Surface.ROTATION_0;
+
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DisplayUtils;
+import android.util.PathParser;
+import android.util.RotationUtils;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * A class representing the shape of a display. It provides a {@link Path} of the display shape of
+ * the display shape.
+ *
+ * {@link DisplayShape} is immutable.
+ */
+public final class DisplayShape implements Parcelable {
+
+    /** @hide */
+    public static final DisplayShape NONE = new DisplayShape("" /* displayShapeSpec */,
+            0 /* displayWidth */, 0 /* displayHeight */, 0 /* physicalPixelDisplaySizeRatio */,
+            0 /* rotation */);
+
+    /** @hide */
+    @VisibleForTesting
+    public final String mDisplayShapeSpec;
+    private final float mPhysicalPixelDisplaySizeRatio;
+    private final int mDisplayWidth;
+    private final int mDisplayHeight;
+    private final int mRotation;
+    private final int mOffsetX;
+    private final int mOffsetY;
+    private final float mScale;
+
+    private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+            float physicalPixelDisplaySizeRatio, int rotation) {
+        this(displayShapeSpec, displayWidth, displayHeight, physicalPixelDisplaySizeRatio,
+                rotation, 0, 0, 1f);
+    }
+
+    private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+            float physicalPixelDisplaySizeRatio, int rotation, int offsetX, int offsetY,
+            float scale) {
+        mDisplayShapeSpec = displayShapeSpec;
+        mDisplayWidth = displayWidth;
+        mDisplayHeight = displayHeight;
+        mPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+        mRotation = rotation;
+        mOffsetX = offsetX;
+        mOffsetY = offsetY;
+        mScale = scale;
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public static DisplayShape fromResources(
+            @NonNull Resources res, @NonNull String displayUniqueId, int physicalDisplayWidth,
+            int physicalDisplayHeight, int displayWidth, int displayHeight) {
+        final boolean isScreenRound = RoundedCorners.getBuiltInDisplayIsRound(res, displayUniqueId);
+        final String spec = getSpecString(res, displayUniqueId);
+        if (spec == null || spec.isEmpty()) {
+            return createDefaultDisplayShape(displayWidth, displayHeight, isScreenRound);
+        }
+        final float physicalPixelDisplaySizeRatio = DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+                physicalDisplayWidth, physicalDisplayHeight, displayWidth, displayHeight);
+        return fromSpecString(spec, physicalPixelDisplaySizeRatio, displayWidth, displayHeight);
+    }
+
+    /**
+     * @hide
+     */
+    @NonNull
+    public static DisplayShape createDefaultDisplayShape(
+            int displayWidth, int displayHeight, boolean isScreenRound) {
+        return fromSpecString(createDefaultSpecString(displayWidth, displayHeight, isScreenRound),
+                1f, displayWidth, displayHeight);
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    @NonNull
+    public static DisplayShape fromSpecString(@NonNull String spec,
+            float physicalPixelDisplaySizeRatio, int displayWidth, int displayHeight) {
+        return Cache.getDisplayShape(spec, physicalPixelDisplaySizeRatio, displayWidth,
+                    displayHeight);
+    }
+
+    private static String createDefaultSpecString(int displayWidth, int displayHeight,
+            boolean isCircular) {
+        final String spec;
+        if (isCircular) {
+            final float xRadius = displayWidth / 2f;
+            final float yRadius = displayHeight / 2f;
+            // Draw a circular display shape.
+            spec = "M0," + yRadius
+                    // Draw upper half circle with arcTo command.
+                    + " A" + xRadius + "," + yRadius + " 0 1,1 " + displayWidth + "," + yRadius
+                    // Draw lower half circle with arcTo command.
+                    + " A" + xRadius + "," + yRadius + " 0 1,1 0," + yRadius + " Z";
+        } else {
+            // Draw a rectangular display shape.
+            spec = "M0,0"
+                    // Draw top edge.
+                    + " L" + displayWidth + ",0"
+                    // Draw right edge.
+                    + " L" + displayWidth + "," + displayHeight
+                    // Draw bottom edge.
+                    + " L0," + displayHeight
+                    // Draw left edge by close command which draws a line from current position to
+                    // the initial points (0,0).
+                    + " Z";
+        }
+        return spec;
+    }
+
+    /**
+     * Gets the display shape svg spec string of a display which is determined by the given display
+     * unique id.
+     *
+     * Loads the default config {@link R.string#config_mainDisplayShape} if
+     * {@link R.array#config_displayUniqueIdArray} is not set.
+     *
+     * @hide
+     */
+    public static String getSpecString(Resources res, String displayUniqueId) {
+        final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+        final TypedArray array = res.obtainTypedArray(R.array.config_displayShapeArray);
+        final String spec;
+        if (index >= 0 && index < array.length()) {
+            spec = array.getString(index);
+        } else {
+            spec = res.getString(R.string.config_mainDisplayShape);
+        }
+        array.recycle();
+        return spec;
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setRotation(int rotation) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, rotation, mOffsetX, mOffsetY, mScale);
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setOffset(int offsetX, int offsetY) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, offsetX, offsetY, mScale);
+    }
+
+    /**
+     * @hide
+     */
+    public DisplayShape setScale(float scale) {
+        return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, scale);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+                mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, mScale);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (o instanceof DisplayShape) {
+            DisplayShape ds = (DisplayShape) o;
+            return Objects.equals(mDisplayShapeSpec, ds.mDisplayShapeSpec)
+                    && mDisplayWidth == ds.mDisplayWidth && mDisplayHeight == ds.mDisplayHeight
+                    && mPhysicalPixelDisplaySizeRatio == ds.mPhysicalPixelDisplaySizeRatio
+                    && mRotation == ds.mRotation && mOffsetX == ds.mOffsetX
+                    && mOffsetY == ds.mOffsetY && mScale == ds.mScale;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return "DisplayShape{"
+                + " spec=" + mDisplayShapeSpec
+                + " displayWidth=" + mDisplayWidth
+                + " displayHeight=" + mDisplayHeight
+                + " physicalPixelDisplaySizeRatio=" + mPhysicalPixelDisplaySizeRatio
+                + " rotation=" + mRotation
+                + " offsetX=" + mOffsetX
+                + " offsetY=" + mOffsetY
+                + " scale=" + mScale + "}";
+    }
+
+    /**
+     * Returns a {@link Path} of the display shape.
+     *
+     * @return a {@link Path} of the display shape.
+     */
+    @NonNull
+    public Path getPath() {
+        return Cache.getPath(this);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeString8(mDisplayShapeSpec);
+        dest.writeInt(mDisplayWidth);
+        dest.writeInt(mDisplayHeight);
+        dest.writeFloat(mPhysicalPixelDisplaySizeRatio);
+        dest.writeInt(mRotation);
+        dest.writeInt(mOffsetX);
+        dest.writeInt(mOffsetY);
+        dest.writeFloat(mScale);
+    }
+
+    public static final @NonNull Creator<DisplayShape> CREATOR = new Creator<DisplayShape>() {
+        @Override
+        public DisplayShape createFromParcel(Parcel in) {
+            final String spec = in.readString8();
+            final int displayWidth = in.readInt();
+            final int displayHeight = in.readInt();
+            final float ratio = in.readFloat();
+            final int rotation = in.readInt();
+            final int offsetX = in.readInt();
+            final int offsetY = in.readInt();
+            final float scale = in.readFloat();
+            return new DisplayShape(spec, displayWidth, displayHeight, ratio, rotation, offsetX,
+                    offsetY, scale);
+        }
+
+        @Override
+        public DisplayShape[] newArray(int size) {
+            return new DisplayShape[size];
+        }
+    };
+
+    private static final class Cache {
+        private static final Object CACHE_LOCK = new Object();
+
+        @GuardedBy("CACHE_LOCK")
+        private static String sCachedSpec;
+        @GuardedBy("CACHE_LOCK")
+        private static int sCachedDisplayWidth;
+        @GuardedBy("CACHE_LOCK")
+        private static int sCachedDisplayHeight;
+        @GuardedBy("CACHE_LOCK")
+        private static float sCachedPhysicalPixelDisplaySizeRatio;
+        @GuardedBy("CACHE_LOCK")
+        private static DisplayShape sCachedDisplayShape;
+
+        @GuardedBy("CACHE_LOCK")
+        private static DisplayShape sCacheForPath;
+        @GuardedBy("CACHE_LOCK")
+        private static Path sCachedPath;
+
+        static DisplayShape getDisplayShape(String spec, float physicalPixelDisplaySizeRatio,
+                int displayWidth, int displayHeight) {
+            synchronized (CACHE_LOCK) {
+                if (spec.equals(sCachedSpec)
+                        && sCachedDisplayWidth == displayWidth
+                        && sCachedDisplayHeight == displayHeight
+                        && sCachedPhysicalPixelDisplaySizeRatio == physicalPixelDisplaySizeRatio) {
+                    return sCachedDisplayShape;
+                }
+            }
+
+            final DisplayShape shape = new DisplayShape(spec, displayWidth, displayHeight,
+                    physicalPixelDisplaySizeRatio, ROTATION_0);
+
+            synchronized (CACHE_LOCK) {
+                sCachedSpec = spec;
+                sCachedDisplayWidth = displayWidth;
+                sCachedDisplayHeight = displayHeight;
+                sCachedPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+                sCachedDisplayShape = shape;
+            }
+            return shape;
+        }
+
+        static Path getPath(@NonNull DisplayShape shape) {
+            synchronized (CACHE_LOCK) {
+                if (shape.equals(sCacheForPath)) {
+                    return sCachedPath;
+                }
+            }
+
+            final Path path = PathParser.createPathFromPathData(shape.mDisplayShapeSpec);
+
+            if (!path.isEmpty()) {
+                final Matrix matrix = new Matrix();
+                if (shape.mRotation != ROTATION_0) {
+                    RotationUtils.transformPhysicalToLogicalCoordinates(
+                            shape.mRotation, shape.mDisplayWidth, shape.mDisplayHeight, matrix);
+                }
+                if (shape.mPhysicalPixelDisplaySizeRatio != 1f) {
+                    matrix.preScale(shape.mPhysicalPixelDisplaySizeRatio,
+                            shape.mPhysicalPixelDisplaySizeRatio);
+                }
+                if (shape.mOffsetX != 0 || shape.mOffsetY != 0) {
+                    matrix.postTranslate(shape.mOffsetX, shape.mOffsetY);
+                }
+                if (shape.mScale != 1f) {
+                    matrix.postScale(shape.mScale, shape.mScale);
+                }
+                path.transform(matrix);
+            }
+
+            synchronized (CACHE_LOCK) {
+                sCacheForPath = shape;
+                sCachedPath = path;
+            }
+            return path;
+        }
+    }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e2bc566..6d9f99f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -53,7 +53,6 @@
 import android.view.KeyEvent;
 import android.view.InputEvent;
 import android.view.InsetsState;
-import android.view.InsetsVisibilities;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
 import android.view.InputChannel;
@@ -738,9 +737,8 @@
      * If invoked through a package other than a launcher app, returns an empty list.
      *
      * @param displayId the id of the logical display
-     * @param packageName the name of the calling package
      */
-    List<DisplayInfo> getPossibleDisplayInfo(int displayId, String packageName);
+    List<DisplayInfo> getPossibleDisplayInfo(int displayId);
 
     /**
      * Called to show global actions.
diff --git a/core/java/android/view/InsetsFrameProvider.java b/core/java/android/view/InsetsFrameProvider.java
index da54da16..58ee59d 100644
--- a/core/java/android/view/InsetsFrameProvider.java
+++ b/core/java/android/view/InsetsFrameProvider.java
@@ -31,6 +31,10 @@
  *
  * The insets frame will by default as the window frame size. If the providers are set, the
  * calculation result based on the source size will be used as the insets frame.
+ *
+ * The InsetsFrameProvider should be self-contained. Nothing describing the window itself, such as
+ * contentInsets, visibleInsets, etc. won't affect the insets providing to other windows when this
+ * is set.
  * @hide
  */
 public class InsetsFrameProvider implements Parcelable {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index a8cc9b6..c56d618 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -197,6 +197,9 @@
     private PrivacyIndicatorBounds mPrivacyIndicatorBounds =
             new PrivacyIndicatorBounds();
 
+    /** The display shape */
+    private DisplayShape mDisplayShape = DisplayShape.NONE;
+
     public InsetsState() {
     }
 
@@ -271,6 +274,7 @@
                 alwaysConsumeSystemBars, calculateRelativeCutout(frame),
                 calculateRelativeRoundedCorners(frame),
                 calculateRelativePrivacyIndicatorBounds(frame),
+                calculateRelativeDisplayShape(frame),
                 compatInsetsTypes, (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
     }
 
@@ -335,6 +339,16 @@
         return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
     }
 
+    private DisplayShape calculateRelativeDisplayShape(Rect frame) {
+        if (mDisplayFrame.equals(frame)) {
+            return mDisplayShape;
+        }
+        if (frame == null) {
+            return DisplayShape.NONE;
+        }
+        return mDisplayShape.setOffset(-frame.left, -frame.top);
+    }
+
     public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
         Insets insets = Insets.NONE;
         for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -589,6 +603,14 @@
         return mPrivacyIndicatorBounds;
     }
 
+    public void setDisplayShape(DisplayShape displayShape) {
+        mDisplayShape = displayShape;
+    }
+
+    public DisplayShape getDisplayShape() {
+        return mDisplayShape;
+    }
+
     /**
      * Modifies the state of this class to exclude a certain type to make it ready for dispatching
      * to the client.
@@ -628,6 +650,7 @@
         mRoundedCorners = mRoundedCorners.scale(scale);
         mRoundedCornerFrame.scale(scale);
         mPrivacyIndicatorBounds = mPrivacyIndicatorBounds.scale(scale);
+        mDisplayShape = mDisplayShape.setScale(scale);
         for (int i = 0; i < SIZE; i++) {
             final InsetsSource source = mSources[i];
             if (source != null) {
@@ -650,6 +673,7 @@
         mRoundedCorners = other.getRoundedCorners();
         mRoundedCornerFrame.set(other.mRoundedCornerFrame);
         mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+        mDisplayShape = other.getDisplayShape();
         if (copySources) {
             for (int i = 0; i < SIZE; i++) {
                 InsetsSource source = other.mSources[i];
@@ -675,6 +699,7 @@
         mRoundedCorners = other.getRoundedCorners();
         mRoundedCornerFrame.set(other.mRoundedCornerFrame);
         mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+        mDisplayShape = other.getDisplayShape();
         final ArraySet<Integer> t = toInternalType(types);
         for (int i = t.size() - 1; i >= 0; i--) {
             final int type = t.valueAt(i);
@@ -807,6 +832,7 @@
         pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
         pw.println(newPrefix + "mRoundedCornerFrame=" + mRoundedCornerFrame);
         pw.println(newPrefix + "mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds);
+        pw.println(newPrefix + "mDisplayShape=" + mDisplayShape);
         for (int i = 0; i < SIZE; i++) {
             InsetsSource source = mSources[i];
             if (source == null) continue;
@@ -911,7 +937,8 @@
                 || !mDisplayCutout.equals(state.mDisplayCutout)
                 || !mRoundedCorners.equals(state.mRoundedCorners)
                 || !mRoundedCornerFrame.equals(state.mRoundedCornerFrame)
-                || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)) {
+                || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)
+                || !mDisplayShape.equals(state.mDisplayShape)) {
             return false;
         }
         for (int i = 0; i < SIZE; i++) {
@@ -941,7 +968,7 @@
     @Override
     public int hashCode() {
         return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
-                mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame);
+                mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame, mDisplayShape);
     }
 
     public InsetsState(Parcel in) {
@@ -961,6 +988,7 @@
         dest.writeTypedObject(mRoundedCorners, flags);
         mRoundedCornerFrame.writeToParcel(dest, flags);
         dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
+        dest.writeTypedObject(mDisplayShape, flags);
     }
 
     public static final @NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -981,6 +1009,7 @@
         mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
         mRoundedCornerFrame.readFromParcel(in);
         mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
+        mDisplayShape = in.readTypedObject(DisplayShape.CREATOR);
     }
 
     @Override
@@ -998,6 +1027,7 @@
                 + ", mRoundedCorners=" + mRoundedCorners
                 + "  mRoundedCornerFrame=" + mRoundedCornerFrame
                 + ", mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds
+                + ", mDisplayShape=" + mDisplayShape
                 + ", mSources= { " + joiner
                 + " }";
     }
diff --git a/core/java/android/view/InsetsVisibilities.aidl b/core/java/android/view/InsetsVisibilities.aidl
deleted file mode 100644
index bd573ea..0000000
--- a/core/java/android/view/InsetsVisibilities.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2021, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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;
-
-parcelable InsetsVisibilities;
diff --git a/core/java/android/view/InsetsVisibilities.java b/core/java/android/view/InsetsVisibilities.java
deleted file mode 100644
index 7d259fb..0000000
--- a/core/java/android/view/InsetsVisibilities.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Arrays;
-import java.util.StringJoiner;
-
-/**
- * A collection of visibilities of insets. This is used for carrying the requested visibilities.
- * @hide
- */
-public class InsetsVisibilities implements Parcelable {
-
-    private static final int UNSPECIFIED = 0;
-    private static final int VISIBLE = 1;
-    private static final int INVISIBLE = -1;
-
-    private final int[] mVisibilities = new int[InsetsState.SIZE];
-
-    public InsetsVisibilities() {
-    }
-
-    public InsetsVisibilities(InsetsVisibilities other) {
-        set(other);
-    }
-
-    public InsetsVisibilities(Parcel in) {
-        in.readIntArray(mVisibilities);
-    }
-
-    /**
-     * Copies from another {@link InsetsVisibilities}.
-     *
-     * @param other an instance of {@link InsetsVisibilities}.
-     */
-    public void set(InsetsVisibilities other) {
-        System.arraycopy(other.mVisibilities, InsetsState.FIRST_TYPE, mVisibilities,
-                InsetsState.FIRST_TYPE, InsetsState.SIZE);
-    }
-
-    /**
-     * Sets a visibility to a type.
-     *
-     * @param type The {@link @InsetsState.InternalInsetsType}.
-     * @param visible {@code true} represents visible; {@code false} represents invisible.
-     */
-    public void setVisibility(@InsetsState.InternalInsetsType int type, boolean visible) {
-        mVisibilities[type] = visible ? VISIBLE : INVISIBLE;
-    }
-
-    /**
-     * Returns the specified insets visibility of the type. If it has never been specified,
-     * this returns the default visibility.
-     *
-     * @param type The {@link @InsetsState.InternalInsetsType}.
-     * @return The specified visibility or the default one if it is not specified.
-     */
-    public boolean getVisibility(@InsetsState.InternalInsetsType int type) {
-        final int visibility = mVisibilities[type];
-        return visibility == UNSPECIFIED
-                ? InsetsState.getDefaultVisibility(type)
-                : visibility == VISIBLE;
-    }
-
-    @Override
-    public String toString() {
-        StringJoiner joiner = new StringJoiner(", ");
-        for (int type = InsetsState.FIRST_TYPE; type <= InsetsState.LAST_TYPE; type++) {
-            final int visibility = mVisibilities[type];
-            if (visibility != UNSPECIFIED) {
-                joiner.add(InsetsState.typeToString(type) + ": "
-                        + (visibility == VISIBLE ? "visible" : "invisible"));
-            }
-        }
-        return joiner.toString();
-    }
-
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(mVisibilities);
-    }
-
-    @Override
-    public boolean equals(Object other) {
-        if (!(other instanceof InsetsVisibilities)) {
-            return false;
-        }
-        return Arrays.equals(mVisibilities, ((InsetsVisibilities) other).mVisibilities);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeIntArray(mVisibilities);
-    }
-
-    public void readFromParcel(@NonNull Parcel in) {
-        in.readIntArray(mVisibilities);
-    }
-
-    public static final @NonNull Creator<InsetsVisibilities> CREATOR =
-            new Creator<InsetsVisibilities>() {
-
-        public InsetsVisibilities createFromParcel(Parcel in) {
-            return new InsetsVisibilities(in);
-        }
-
-        public InsetsVisibilities[] newArray(int size) {
-            return new InsetsVisibilities[size];
-        }
-    };
-}
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 2a8e7e4..080c0d8 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -533,6 +533,13 @@
         mHotSpotY = hotSpotY;
     }
 
+    @Override
+    public String toString() {
+        return "PointerIcon{type=" + typeToString(mType)
+                + ", hotspotX=" + mHotSpotX + ", hotspotY=" + mHotSpotY
+                + ", systemIconResourceId=" + mSystemIconResourceId + "}";
+    }
+
     private static void validateHotSpot(Bitmap bitmap, float hotSpotX, float hotSpotY) {
         if (hotSpotX < 0 || hotSpotX >= bitmap.getWidth()) {
             throw new IllegalArgumentException("x hotspot lies outside of the bitmap area");
@@ -624,4 +631,40 @@
         displayManager.registerDisplayListener(sDisplayListener, null /* handler */);
     }
 
+    /**
+     * Convert type constant to string.
+     * @hide
+     */
+    public static String typeToString(int type) {
+        switch (type) {
+            case TYPE_CUSTOM: return "CUSTOM";
+            case TYPE_NULL: return "NULL";
+            case TYPE_NOT_SPECIFIED: return "NOT_SPECIFIED";
+            case TYPE_ARROW: return "ARROW";
+            case TYPE_SPOT_HOVER: return "SPOT_HOVER";
+            case TYPE_SPOT_TOUCH: return "SPOT_TOUCH";
+            case TYPE_SPOT_ANCHOR: return "SPOT_ANCHOR";
+            case TYPE_CONTEXT_MENU: return "CONTEXT_MENU";
+            case TYPE_HAND: return "HAND";
+            case TYPE_HELP: return "HELP";
+            case TYPE_WAIT: return "WAIT";
+            case TYPE_CELL: return "CELL";
+            case TYPE_CROSSHAIR: return "CROSSHAIR";
+            case TYPE_TEXT: return "TEXT";
+            case TYPE_VERTICAL_TEXT: return "VERTICAL_TEXT";
+            case TYPE_ALIAS: return "ALIAS";
+            case TYPE_COPY: return "COPY";
+            case TYPE_NO_DROP: return "NO_DROP";
+            case TYPE_ALL_SCROLL: return "ALL_SCROLL";
+            case TYPE_HORIZONTAL_DOUBLE_ARROW: return "HORIZONTAL_DOUBLE_ARROW";
+            case TYPE_VERTICAL_DOUBLE_ARROW: return "VERTICAL_DOUBLE_ARROW";
+            case TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW: return "TOP_RIGHT_DIAGONAL_DOUBLE_ARROW";
+            case TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW: return "TOP_LEFT_DIAGONAL_DOUBLE_ARROW";
+            case TYPE_ZOOM_IN: return "ZOOM_IN";
+            case TYPE_ZOOM_OUT: return "ZOOM_OUT";
+            case TYPE_GRAB: return "GRAB";
+            case TYPE_GRABBING: return "GRABBING";
+            default: return Integer.toString(type);
+        }
+    }
 }
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index 5e17551..8d8ddb9 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -35,6 +35,7 @@
 
 import android.annotation.ColorInt;
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.app.WindowConfiguration;
@@ -175,10 +176,16 @@
     public final Rect screenSpaceBounds;
 
     /**
-     * The starting bounds of the source container in screen space coordinates. This is {@code null}
-     * if the animation target isn't MODE_CHANGING. Since this is the starting bounds, it's size
-     * should be equivalent to the size of the starting thumbnail. Note that sourceContainerBounds
-     * is the end bounds of a change transition.
+     * The starting bounds of the source container in screen space coordinates.
+     * For {@link #MODE_OPENING}, this will be equivalent to {@link #screenSpaceBounds}.
+     * For {@link #MODE_CLOSING}, this will be equivalent to {@link #screenSpaceBounds} unless the
+     * closing container is also resizing. For example, when ActivityEmbedding split pair becomes
+     * stacked, the container on the back will be resized to fullscreen, but will also be covered
+     * (closing) by the container in the front.
+     * For {@link #MODE_CHANGING}, since this is the starting bounds, its size should be equivalent
+     * to the bounds of the starting thumbnail.
+     *
+     * Note that {@link #screenSpaceBounds} is the end bounds of a transition.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public final Rect startBounds;
@@ -247,7 +254,8 @@
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
-            SurfaceControl startLeash, Rect startBounds, ActivityManager.RunningTaskInfo taskInfo,
+            SurfaceControl startLeash, @Nullable Rect startBounds,
+            ActivityManager.RunningTaskInfo taskInfo,
             boolean allowEnterPip) {
         this(taskId, mode, leash, isTranslucent, clipRect, contentInsets, prefixOrderIndex,
                 position, localBounds, screenSpaceBounds, windowConfig, isNotInRecents, startLeash,
@@ -258,7 +266,7 @@
             Rect clipRect, Rect contentInsets, int prefixOrderIndex, Point position,
             Rect localBounds, Rect screenSpaceBounds,
             WindowConfiguration windowConfig, boolean isNotInRecents,
-            SurfaceControl startLeash, Rect startBounds,
+            SurfaceControl startLeash, @Nullable Rect startBounds,
             ActivityManager.RunningTaskInfo taskInfo, boolean allowEnterPip,
             @WindowManager.LayoutParams.WindowType int windowType) {
         this.mode = mode;
@@ -275,10 +283,13 @@
         this.windowConfiguration = windowConfig;
         this.isNotInRecents = isNotInRecents;
         this.startLeash = startLeash;
-        this.startBounds = startBounds == null ? null : new Rect(startBounds);
         this.taskInfo = taskInfo;
         this.allowEnterPip = allowEnterPip;
         this.windowType = windowType;
+        // Same as screenSpaceBounds if the window is not resizing.
+        this.startBounds = startBounds == null
+                ? new Rect(screenSpaceBounds)
+                : new Rect(startBounds);
     }
 
     public RemoteAnimationTarget(Parcel in) {
@@ -399,9 +410,7 @@
         if (startLeash != null) {
             startLeash.dumpDebug(proto, START_LEASH);
         }
-        if (startBounds != null) {
-            startBounds.dumpDebug(proto, START_BOUNDS);
-        }
+        startBounds.dumpDebug(proto, START_BOUNDS);
         proto.end(token);
     }
 
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e1ca0f1..30e7a7a 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -1563,6 +1563,7 @@
         public float refreshRate;
         public long appVsyncOffsetNanos;
         public long presentationDeadlineNanos;
+        public int[] supportedHdrTypes;
 
         /**
          * The config group ID this config is associated to.
@@ -1582,6 +1583,7 @@
                     + ", refreshRate=" + refreshRate
                     + ", appVsyncOffsetNanos=" + appVsyncOffsetNanos
                     + ", presentationDeadlineNanos=" + presentationDeadlineNanos
+                    + ", supportedHdrTypes=" + Arrays.toString(supportedHdrTypes)
                     + ", group=" + group + "}";
         }
 
@@ -1598,13 +1600,14 @@
                     && Float.compare(that.refreshRate, refreshRate) == 0
                     && appVsyncOffsetNanos == that.appVsyncOffsetNanos
                     && presentationDeadlineNanos == that.presentationDeadlineNanos
+                    && Arrays.equals(supportedHdrTypes, that.supportedHdrTypes)
                     && group == that.group;
         }
 
         @Override
         public int hashCode() {
             return Objects.hash(id, width, height, xDpi, yDpi, refreshRate, appVsyncOffsetNanos,
-                    presentationDeadlineNanos, group);
+                    presentationDeadlineNanos, group, Arrays.hashCode(supportedHdrTypes));
         }
     }
 
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index ef18458..33ea92d 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -728,8 +728,8 @@
 
     private void releaseSurfaces(boolean releaseSurfacePackage) {
         mAlpha = 1f;
+        mSurface.destroy();
         synchronized (mSurfaceControlLock) {
-            mSurface.destroy();
             if (mBlastBufferQueue != null) {
                 mBlastBufferQueue.destroy();
                 mBlastBufferQueue = null;
@@ -947,108 +947,112 @@
                     + " left=" + (mWindowSpaceLeft != mLocation[0])
                     + " top=" + (mWindowSpaceTop != mLocation[1]));
 
-            mVisible = mRequestedVisible;
-            mWindowSpaceLeft = mLocation[0];
-            mWindowSpaceTop = mLocation[1];
-            mSurfaceWidth = myWidth;
-            mSurfaceHeight = myHeight;
-            mFormat = mRequestedFormat;
-            mAlpha = alpha;
-            mLastWindowVisibility = mWindowVisibility;
-            mTransformHint = viewRoot.getBufferTransformHint();
-            mSubLayer = mRequestedSubLayer;
-
-            mScreenRect.left = mWindowSpaceLeft;
-            mScreenRect.top = mWindowSpaceTop;
-            mScreenRect.right = mWindowSpaceLeft + getWidth();
-            mScreenRect.bottom = mWindowSpaceTop + getHeight();
-            if (translator != null) {
-                translator.translateRectInAppWindowToScreen(mScreenRect);
-            }
-
-            final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
-            mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
-            // Collect all geometry changes and apply these changes on the RenderThread worker
-            // via the RenderNode.PositionUpdateListener.
-            final Transaction surfaceUpdateTransaction = new Transaction();
-            if (creating) {
-                updateOpaqueFlag();
-                final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
-                createBlastSurfaceControls(viewRoot, name, surfaceUpdateTransaction);
-            } else if (mSurfaceControl == null) {
-                return;
-            }
-
-            final boolean redrawNeeded = sizeChanged || creating || hintChanged
-                    || (mVisible && !mDrawFinished) || alphaChanged || relativeZChanged;
-            boolean shouldSyncBuffer =
-                    redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInLocalSync();
-            SyncBufferTransactionCallback syncBufferTransactionCallback = null;
-            if (shouldSyncBuffer) {
-                syncBufferTransactionCallback = new SyncBufferTransactionCallback();
-                mBlastBufferQueue.syncNextTransaction(
-                        false /* acquireSingleBuffer */,
-                        syncBufferTransactionCallback::onTransactionReady);
-            }
-
-            final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator,
-                    creating, sizeChanged, hintChanged, relativeZChanged,
-                    surfaceUpdateTransaction);
-
             try {
-                SurfaceHolder.Callback[] callbacks = null;
+                mVisible = mRequestedVisible;
+                mWindowSpaceLeft = mLocation[0];
+                mWindowSpaceTop = mLocation[1];
+                mSurfaceWidth = myWidth;
+                mSurfaceHeight = myHeight;
+                mFormat = mRequestedFormat;
+                mAlpha = alpha;
+                mLastWindowVisibility = mWindowVisibility;
+                mTransformHint = viewRoot.getBufferTransformHint();
+                mSubLayer = mRequestedSubLayer;
 
-                final boolean surfaceChanged = creating;
-                if (mSurfaceCreated && (surfaceChanged || (!mVisible && visibleChanged))) {
-                    mSurfaceCreated = false;
-                    notifySurfaceDestroyed();
+                mScreenRect.left = mWindowSpaceLeft;
+                mScreenRect.top = mWindowSpaceTop;
+                mScreenRect.right = mWindowSpaceLeft + getWidth();
+                mScreenRect.bottom = mWindowSpaceTop + getHeight();
+                if (translator != null) {
+                    translator.translateRectInAppWindowToScreen(mScreenRect);
                 }
 
-                copySurface(creating /* surfaceControlCreated */, sizeChanged);
+                final Rect surfaceInsets = viewRoot.mWindowAttributes.surfaceInsets;
+                mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
+                // Collect all geometry changes and apply these changes on the RenderThread worker
+                // via the RenderNode.PositionUpdateListener.
+                final Transaction surfaceUpdateTransaction = new Transaction();
+                if (creating) {
+                    updateOpaqueFlag();
+                    final String name = "SurfaceView[" + viewRoot.getTitle().toString() + "]";
+                    createBlastSurfaceControls(viewRoot, name, surfaceUpdateTransaction);
+                } else if (mSurfaceControl == null) {
+                    return;
+                }
 
-                if (mVisible && mSurface.isValid()) {
-                    if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
-                        mSurfaceCreated = true;
-                        mIsCreating = true;
-                        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                                + "visibleChanged -- surfaceCreated");
-                        callbacks = getSurfaceCallbacks();
-                        for (SurfaceHolder.Callback c : callbacks) {
-                            c.surfaceCreated(mSurfaceHolder);
-                        }
+                final boolean redrawNeeded = sizeChanged || creating || hintChanged
+                        || (mVisible && !mDrawFinished) || alphaChanged || relativeZChanged;
+                boolean shouldSyncBuffer =
+                        redrawNeeded && viewRoot.wasRelayoutRequested() && viewRoot.isInLocalSync();
+                SyncBufferTransactionCallback syncBufferTransactionCallback = null;
+                if (shouldSyncBuffer) {
+                    syncBufferTransactionCallback = new SyncBufferTransactionCallback();
+                    mBlastBufferQueue.syncNextTransaction(
+                            false /* acquireSingleBuffer */,
+                            syncBufferTransactionCallback::onTransactionReady);
+                }
+
+                final boolean realSizeChanged = performSurfaceTransaction(viewRoot, translator,
+                        creating, sizeChanged, hintChanged, relativeZChanged,
+                        surfaceUpdateTransaction);
+
+                try {
+                    SurfaceHolder.Callback[] callbacks = null;
+
+                    final boolean surfaceChanged = creating;
+                    if (mSurfaceCreated && (surfaceChanged || (!mVisible && visibleChanged))) {
+                        mSurfaceCreated = false;
+                        notifySurfaceDestroyed();
                     }
-                    if (creating || formatChanged || sizeChanged || hintChanged
-                            || visibleChanged || realSizeChanged) {
-                        if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
-                                + "surfaceChanged -- format=" + mFormat
-                                + " w=" + myWidth + " h=" + myHeight);
-                        if (callbacks == null) {
+
+                    copySurface(creating /* surfaceControlCreated */, sizeChanged);
+
+                    if (mVisible && mSurface.isValid()) {
+                        if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
+                            mSurfaceCreated = true;
+                            mIsCreating = true;
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "visibleChanged -- surfaceCreated");
                             callbacks = getSurfaceCallbacks();
+                            for (SurfaceHolder.Callback c : callbacks) {
+                                c.surfaceCreated(mSurfaceHolder);
+                            }
                         }
-                        for (SurfaceHolder.Callback c : callbacks) {
-                            c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
+                        if (creating || formatChanged || sizeChanged || hintChanged
+                                || visibleChanged || realSizeChanged) {
+                            if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+                                    + "surfaceChanged -- format=" + mFormat
+                                    + " w=" + myWidth + " h=" + myHeight);
+                            if (callbacks == null) {
+                                callbacks = getSurfaceCallbacks();
+                            }
+                            for (SurfaceHolder.Callback c : callbacks) {
+                                c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
+                            }
                         }
-                    }
-                    if (redrawNeeded) {
-                        if (DEBUG) {
-                            Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded");
-                        }
-                        if (callbacks == null) {
-                            callbacks = getSurfaceCallbacks();
-                        }
+                        if (redrawNeeded) {
+                            if (DEBUG) {
+                                Log.i(TAG, System.identityHashCode(this) + " surfaceRedrawNeeded");
+                            }
+                            if (callbacks == null) {
+                                callbacks = getSurfaceCallbacks();
+                            }
 
-                        if (shouldSyncBuffer) {
-                            handleSyncBufferCallback(callbacks, syncBufferTransactionCallback);
-                        } else {
-                            handleSyncNoBuffer(callbacks);
+                            if (shouldSyncBuffer) {
+                                handleSyncBufferCallback(callbacks, syncBufferTransactionCallback);
+                            } else {
+                                handleSyncNoBuffer(callbacks);
+                            }
                         }
                     }
+                } finally {
+                    mIsCreating = false;
+                    if (mSurfaceControl != null && !mSurfaceCreated) {
+                        releaseSurfaces(false /* releaseSurfacePackage*/);
+                    }
                 }
-            } finally {
-                mIsCreating = false;
-                if (mSurfaceControl != null && !mSurfaceCreated) {
-                    releaseSurfaces(false /* releaseSurfacePackage*/);
-                }
+            } catch (Exception ex) {
+                Log.e(TAG, "Exception configuring surface", ex);
             }
             if (DEBUG) Log.v(
                 TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 0f970bf..09a9d46 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -853,7 +853,12 @@
 
     private SurfaceSyncGroup mSyncGroup;
     private SurfaceSyncGroup.TransactionReadyCallback mTransactionReadyCallback;
-    private int mNumSyncsInProgress = 0;
+
+    private static final Object sSyncProgressLock = new Object();
+    // The count needs to be static since it's used to enable or disable RT animations which is
+    // done at a global level per process. If any VRI syncs are in progress, we can't enable RT
+    // animations until all are done.
+    private static int sNumSyncsInProgress = 0;
 
     private HashSet<ScrollCaptureCallback> mRootScrollCaptureCallbacks;
 
@@ -11229,13 +11234,6 @@
         });
     }
 
-    private final Executor mPostAtFrontExecutor = new Executor() {
-        @Override
-        public void execute(Runnable command) {
-            mHandler.postAtFrontOfQueue(command);
-        }
-    };
-
     public final SurfaceSyncGroup.SyncTarget mSyncTarget = new SurfaceSyncGroup.SyncTarget() {
         @Override
         public void onAddedToSyncGroup(SurfaceSyncGroup parentSyncGroup,
@@ -11245,9 +11243,6 @@
                 // Always sync the buffer if the sync request did not come from VRI.
                 mSyncBuffer = true;
             }
-            if (mAttachInfo.mThreadedRenderer != null) {
-                HardwareRenderer.setRtAnimationsEnabled(false);
-            }
 
             if (mTransactionReadyCallback != null) {
                 Log.d(mTag, "Already set sync for the next draw.");
@@ -11261,16 +11256,29 @@
                 scheduleTraversals();
             }
         }
+    };
 
-        private void updateSyncInProgressCount(SurfaceSyncGroup parentSyncGroup) {
-            mNumSyncsInProgress++;
-            parentSyncGroup.addSyncCompleteCallback(mPostAtFrontExecutor, () -> {
-                if (--mNumSyncsInProgress == 0 && mAttachInfo.mThreadedRenderer != null) {
+    private final Executor mSimpleExecutor = Runnable::run;
+
+    private void updateSyncInProgressCount(SurfaceSyncGroup syncGroup) {
+        if (mAttachInfo.mThreadedRenderer == null) {
+            return;
+        }
+
+        synchronized (sSyncProgressLock) {
+            if (sNumSyncsInProgress++ == 0) {
+                HardwareRenderer.setRtAnimationsEnabled(false);
+            }
+        }
+
+        syncGroup.addSyncCompleteCallback(mSimpleExecutor, () -> {
+            synchronized (sSyncProgressLock) {
+                if (--sNumSyncsInProgress == 0) {
                     HardwareRenderer.setRtAnimationsEnabled(true);
                 }
-            });
-        }
-    };
+            }
+        });
+    }
 
     @Override
     public SurfaceSyncGroup.SyncTarget getSyncTarget() {
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index d77e499..fd55d8d 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -29,6 +29,7 @@
 import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
 import static android.view.WindowInsets.Type.TAPPABLE_ELEMENT;
 import static android.view.WindowInsets.Type.all;
+import static android.view.WindowInsets.Type.displayCutout;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowInsets.Type.indexOf;
 import static android.view.WindowInsets.Type.systemBars;
@@ -41,7 +42,6 @@
 import android.content.Intent;
 import android.graphics.Insets;
 import android.graphics.Rect;
-import android.util.SparseArray;
 import android.view.View.OnApplyWindowInsetsListener;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.inputmethod.EditorInfo;
@@ -82,6 +82,7 @@
     @Nullable private final DisplayCutout mDisplayCutout;
     @Nullable private final RoundedCorners mRoundedCorners;
     @Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
+    @Nullable private final DisplayShape mDisplayShape;
 
     /**
      * In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -114,24 +115,9 @@
     public static final @NonNull WindowInsets CONSUMED;
 
     static {
-        CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
-    }
-
-    /**
-     * Construct a new WindowInsets from individual insets.
-     *
-     * A {@code null} inset indicates that the respective inset is consumed.
-     *
-     * @hide
-     * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
-     */
-    @Deprecated
-    public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound,
-            boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
-        this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
-                createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
-                isRound, alwaysConsumeSystemBars, displayCutout, null, null,
-                systemBars(), false /* compatIgnoreVisibility */);
+        CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
+                createCompatVisibilityMap(createCompatTypeMap(null)), false, false, null, null,
+                null, null, systemBars(), false);
     }
 
     /**
@@ -153,6 +139,7 @@
             boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
             RoundedCorners roundedCorners,
             PrivacyIndicatorBounds privacyIndicatorBounds,
+            DisplayShape displayShape,
             @InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
         mSystemWindowInsetsConsumed = typeInsetsMap == null;
         mTypeInsetsMap = mSystemWindowInsetsConsumed
@@ -176,6 +163,7 @@
 
         mRoundedCorners = roundedCorners;
         mPrivacyIndicatorBounds = privacyIndicatorBounds;
+        mDisplayShape = displayShape;
     }
 
     /**
@@ -190,6 +178,7 @@
                 src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
                 src.mRoundedCorners,
                 src.mPrivacyIndicatorBounds,
+                src.mDisplayShape,
                 src.mCompatInsetsTypes,
                 src.mCompatIgnoreVisibility);
     }
@@ -243,15 +232,18 @@
     @UnsupportedAppUsage
     public WindowInsets(Rect systemWindowInsets) {
         this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
-                null, null, systemBars(), false /* compatIgnoreVisibility */);
+                null, null, null, systemBars(), false /* compatIgnoreVisibility */);
     }
 
     /**
      * Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
      * {@link Type#statusBars()} and {@link Type#navigationBars()}, depending on the
      * location of the inset.
+     *
+     * @hide
      */
-    private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
+    @VisibleForTesting
+    public static Insets[] createCompatTypeMap(@Nullable Rect insets) {
         if (insets == null) {
             return null;
         }
@@ -270,6 +262,10 @@
                 Insets.of(insets.left, 0, insets.right, insets.bottom);
     }
 
+    /**
+     * @hide
+     */
+    @VisibleForTesting
     private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetsMap) {
         boolean[] typeVisibilityMap = new boolean[SIZE];
         if (typeInsetsMap == null) {
@@ -532,6 +528,17 @@
     }
 
     /**
+     * Returns the display shape in the coordinate space of the window.
+     *
+     * @return the display shape
+     * @see DisplayShape
+     */
+    @Nullable
+    public DisplayShape getDisplayShape() {
+        return mDisplayShape;
+    }
+
+    /**
      * Returns a copy of this WindowInsets with the cutout fully consumed.
      *
      * @return A modified copy of this WindowInsets
@@ -546,7 +553,7 @@
                 mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
                 mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeSystemBars,
-                null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds,
+                null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape,
                 mCompatInsetsTypes, mCompatIgnoreVisibility);
     }
 
@@ -597,8 +604,11 @@
         return new WindowInsets(null, null,
                 mTypeVisibilityMap,
                 mIsRound, mAlwaysConsumeSystemBars,
-                displayCutoutCopyConstructorArgument(this),
-                mRoundedCorners, mPrivacyIndicatorBounds, mCompatInsetsTypes,
+                // If the system window insets types contain displayCutout, we should also consume
+                // it.
+                (mCompatInsetsTypes & displayCutout()) != 0
+                        ? null : displayCutoutCopyConstructorArgument(this),
+                mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
                 mCompatIgnoreVisibility);
     }
 
@@ -907,6 +917,8 @@
         result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
                 + mPrivacyIndicatorBounds : "");
         result.append("\n    ");
+        result.append(mDisplayShape != null ? "displayShape=" + mDisplayShape : "");
+        result.append("\n    ");
         result.append("compatInsetsTypes=" + mCompatInsetsTypes);
         result.append("\n    ");
         result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
@@ -1014,6 +1026,7 @@
                 mPrivacyIndicatorBounds == null
                         ? null
                         : mPrivacyIndicatorBounds.inset(left, top, right, bottom),
+                mDisplayShape,
                 mCompatInsetsTypes, mCompatIgnoreVisibility);
     }
 
@@ -1033,7 +1046,8 @@
                 && Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
                 && Objects.equals(mDisplayCutout, that.mDisplayCutout)
                 && Objects.equals(mRoundedCorners, that.mRoundedCorners)
-                && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds);
+                && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds)
+                && Objects.equals(mDisplayShape, that.mDisplayShape);
     }
 
     @Override
@@ -1041,7 +1055,7 @@
         return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
                 Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
                 mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
-                mDisplayCutoutConsumed, mPrivacyIndicatorBounds);
+                mDisplayCutoutConsumed, mPrivacyIndicatorBounds, mDisplayShape);
     }
 
 
@@ -1102,6 +1116,7 @@
 
         private DisplayCutout mDisplayCutout;
         private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
+        private DisplayShape mDisplayShape = DisplayShape.NONE;
 
         private boolean mIsRound;
         private boolean mAlwaysConsumeSystemBars;
@@ -1133,6 +1148,7 @@
             mIsRound = insets.mIsRound;
             mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
             mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
+            mDisplayShape = insets.mDisplayShape;
         }
 
         /**
@@ -1377,6 +1393,19 @@
             return this;
         }
 
+        /**
+         * Sets the display shape.
+         *
+         * @see #getDisplayShape().
+         * @param displayShape the display shape.
+         * @return itself.
+         */
+        @NonNull
+        public Builder setDisplayShape(@NonNull DisplayShape displayShape) {
+            mDisplayShape = displayShape;
+            return this;
+        }
+
         /** @hide */
         @NonNull
         public Builder setRound(boolean round) {
@@ -1401,7 +1430,8 @@
             return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
                     mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
                     mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
-                    mPrivacyIndicatorBounds, systemBars(), false /* compatIgnoreVisibility */);
+                    mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
+                    false /* compatIgnoreVisibility */);
         }
     }
 
@@ -1463,37 +1493,37 @@
         public static String toString(@InsetsType int types) {
             StringBuilder result = new StringBuilder();
             if ((types & STATUS_BARS) != 0) {
-                result.append("statusBars |");
+                result.append("statusBars ");
             }
             if ((types & NAVIGATION_BARS) != 0) {
-                result.append("navigationBars |");
+                result.append("navigationBars ");
             }
             if ((types & CAPTION_BAR) != 0) {
-                result.append("captionBar |");
+                result.append("captionBar ");
             }
             if ((types & IME) != 0) {
-                result.append("ime |");
+                result.append("ime ");
             }
             if ((types & SYSTEM_GESTURES) != 0) {
-                result.append("systemGestures |");
+                result.append("systemGestures ");
             }
             if ((types & MANDATORY_SYSTEM_GESTURES) != 0) {
-                result.append("mandatorySystemGestures |");
+                result.append("mandatorySystemGestures ");
             }
             if ((types & TAPPABLE_ELEMENT) != 0) {
-                result.append("tappableElement |");
+                result.append("tappableElement ");
             }
             if ((types & DISPLAY_CUTOUT) != 0) {
-                result.append("displayCutout |");
+                result.append("displayCutout ");
             }
             if ((types & WINDOW_DECOR) != 0) {
-                result.append("windowDecor |");
+                result.append("windowDecor ");
             }
             if ((types & SYSTEM_OVERLAYS) != 0) {
-                result.append("systemOverlays |");
+                result.append("systemOverlays ");
             }
             if (result.length() > 0) {
-                result.delete(result.length() - 2, result.length());
+                result.delete(result.length() - 1, result.length());
             }
             return result.toString();
         }
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6dc9011..5c4305c 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -366,7 +366,7 @@
         List<DisplayInfo> possibleDisplayInfos;
         try {
             possibleDisplayInfos = WindowManagerGlobal.getWindowManagerService()
-                    .getPossibleDisplayInfo(displayId, mContext.getPackageName());
+                    .getPossibleDisplayInfo(displayId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
index 85f5056..44b6deb 100644
--- a/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
+++ b/core/java/android/view/accessibility/AccessibilityDisplayProxy.java
@@ -20,13 +20,18 @@
 import android.accessibilityservice.AccessibilityService;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.accessibilityservice.IAccessibilityServiceConnection;
 import android.accessibilityservice.MagnificationConfig;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.pm.ResolveInfo;
 import android.graphics.Region;
 import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.inputmethod.EditorInfo;
@@ -34,14 +39,15 @@
 import com.android.internal.inputmethod.IAccessibilityInputMethodSessionCallback;
 import com.android.internal.inputmethod.RemoteAccessibilityInputConnection;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.Executor;
 
 /**
  * Allows a privileged app - an app with MANAGE_ACCESSIBILITY permission and SystemAPI access - to
  * interact with the windows in the display that this proxy represents. Proxying the default display
- * or a display that is not tracked will throw an exception. Only the real user has access to global
- * clients like SystemUI.
+ * or a display that is not tracked by accessibility, such as private displays, will throw an
+ * exception. Only the real user has access to global clients like SystemUI.
  *
  * <p>
  * To register and unregister a proxy, use
@@ -49,7 +55,16 @@
  * and {@link AccessibilityManager#unregisterDisplayProxy(AccessibilityDisplayProxy)}. If the app
  * that has registered the proxy dies, the system will remove the proxy.
  *
- * TODO(241429275): Complete proxy impl and add additional support (if necessary) like cache methods
+ * <p>
+ * Avoid using the app's main thread. Proxy methods such as {@link #getWindows} and node methods
+ * like {@link AccessibilityNodeInfo#getChild(int)} will happen frequently. Node methods may also
+ * wait on the displayed app's UI thread to obtain accurate screen data.
+ *
+ * <p>
+ * To get a list of {@link AccessibilityServiceInfo}s that have populated {@link ComponentName}s and
+ * {@link ResolveInfo}s, retrieve the list using {@link #getInstalledAndEnabledServices()} after
+ * {@link #onProxyConnected()} has been called.
+ *
  * @hide
  */
 @SystemApi
@@ -91,7 +106,134 @@
     }
 
     /**
-     * An IAccessibilityServiceClient that handles interrupts and accessibility events.
+     * Handles {@link android.view.accessibility.AccessibilityEvent}s.
+     * <p>
+     * AccessibilityEvents represent changes to the UI, or what parts of the node tree have changed.
+     * AccessibilityDisplayProxy should use these to query new UI and send appropriate feedback
+     * to their users.
+     * <p>
+     * For example, a {@link AccessibilityEvent#TYPE_WINDOWS_CHANGED} indicates a change in windows,
+     * so a proxy may query {@link #getWindows} to obtain updated UI and potentially inform of a new
+     * window title. Or a proxy may emit an earcon on a
+     * {@link AccessibilityEvent#TYPE_VIEW_SCROLLED} event.
+     */
+    public void onAccessibilityEvent(@NonNull AccessibilityEvent event) {
+        // Default no-op
+    }
+
+    /**
+     * Handles a successful system connection after
+     * {@link AccessibilityManager#registerDisplayProxy(AccessibilityDisplayProxy)} is called.
+     *
+     * <p>
+     * At this point, querying for UI is available and {@link AccessibilityEvent}s will begin being
+     * sent. An AccessibilityDisplayProxy may instantiate core infrastructure components here.
+     */
+    public void onProxyConnected() {
+        // Default no-op
+    }
+
+    /**
+     * Handles a request to interrupt the accessibility feedback.
+     * <p>
+     * AccessibilityDisplayProxy should interrupt the accessibility activity occurring on its
+     * display. For example, a screen reader may interrupt speech.
+     *
+     * @see AccessibilityManager#interrupt()
+     * @see AccessibilityService#onInterrupt()
+     */
+    public void interrupt() {
+        // Default no-op
+    }
+
+    /**
+     * Gets the focus of the window specified by {@code windowInfo}.
+     *
+     * @param windowInfo the window to search
+     * @param focus The focus to find. One of {@link AccessibilityNodeInfo#FOCUS_INPUT} or
+     * {@link AccessibilityNodeInfo#FOCUS_ACCESSIBILITY}.
+     * @return The node info of the focused view or null.
+     * @hide
+     * TODO(254545943): Do not expose until support for accessibility focus and/or input is in place
+     */
+    @Nullable
+    public AccessibilityNodeInfo findFocus(@NonNull AccessibilityWindowInfo windowInfo, int focus) {
+        AccessibilityNodeInfo windowRoot = windowInfo.getRoot();
+        return windowRoot != null ? windowRoot.findFocus(focus) : null;
+    }
+
+    /**
+     * Gets the windows of the tracked display.
+     *
+     * @see AccessibilityService#getWindows()
+     */
+    @NonNull
+    public List<AccessibilityWindowInfo> getWindows() {
+        return AccessibilityInteractionClient.getInstance().getWindowsOnDisplay(mConnectionId,
+                mDisplayId);
+    }
+
+    /**
+     * Sets the list of {@link AccessibilityServiceInfo}s describing the services interested in the
+     * {@link AccessibilityDisplayProxy}'s display.
+     *
+     * <p>These represent a11y features and services that are installed and running. These should
+     * not include {@link AccessibilityService}s installed on the phone.
+     *
+     * @param installedAndEnabledServices the list of installed and running a11y services.
+     */
+    public void setInstalledAndEnabledServices(
+            @NonNull List<AccessibilityServiceInfo> installedAndEnabledServices) {
+        mInstalledAndEnabledServices = installedAndEnabledServices;
+        sendServiceInfos();
+    }
+
+    /**
+     * Sets the {@link AccessibilityServiceInfo} for this service if the latter is
+     * properly set and there is an {@link IAccessibilityServiceConnection} to the
+     * AccessibilityManagerService.
+     */
+    private void sendServiceInfos() {
+        IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (mInstalledAndEnabledServices != null && mInstalledAndEnabledServices.size() > 0
+                && connection != null) {
+            try {
+                connection.setInstalledAndEnabledServices(mInstalledAndEnabledServices);
+                AccessibilityInteractionClient.getInstance().clearCache(mConnectionId);
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while setting AccessibilityServiceInfos", re);
+                re.rethrowFromSystemServer();
+            }
+        }
+        mInstalledAndEnabledServices = null;
+    }
+
+    /**
+     * Gets the list of {@link AccessibilityServiceInfo}s describing the services interested in the
+     * {@link AccessibilityDisplayProxy}'s display.
+     *
+     * @return The {@link AccessibilityServiceInfo}s of interested services.
+     * @see AccessibilityServiceInfo
+     */
+    @NonNull
+    public final List<AccessibilityServiceInfo> getInstalledAndEnabledServices() {
+        IAccessibilityServiceConnection connection =
+                AccessibilityInteractionClient.getInstance().getConnection(mConnectionId);
+        if (connection != null) {
+            try {
+                return connection.getInstalledAndEnabledServices();
+            } catch (RemoteException re) {
+                Log.w(LOG_TAG, "Error while getting AccessibilityServiceInfo", re);
+                re.rethrowFromSystemServer();
+            }
+        }
+        return Collections.emptyList();
+    }
+
+    /**
+     * An IAccessibilityServiceClient that handles interrupts, accessibility events, and system
+     * connection.
      */
     private class IAccessibilityServiceClientImpl extends
             AccessibilityService.IAccessibilityServiceClientWrapper {
@@ -100,17 +242,24 @@
             super(context, executor, new AccessibilityService.Callbacks() {
                 @Override
                 public void onAccessibilityEvent(AccessibilityEvent event) {
-                    // TODO: call AccessiiblityProxy.onAccessibilityEvent
+                    // TODO(254545943): Remove check when event processing is done more upstream in
+                    // AccessibilityManagerService.
+                    if (event.getDisplayId() == mDisplayId) {
+                        AccessibilityDisplayProxy.this.onAccessibilityEvent(event);
+                    }
                 }
 
                 @Override
                 public void onInterrupt() {
-                    // TODO: call AccessiiblityProxy.onInterrupt
+                    AccessibilityDisplayProxy.this.interrupt();
                 }
+
                 @Override
                 public void onServiceConnected() {
-                    // TODO: send service infos and call AccessiiblityProxy.onProxyConnected
+                    AccessibilityDisplayProxy.this.sendServiceInfos();
+                    AccessibilityDisplayProxy.this.onProxyConnected();
                 }
+
                 @Override
                 public void init(int connectionId, IBinder windowToken) {
                     mConnectionId = connectionId;
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 7030ab5..06a6de9 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -458,15 +458,21 @@
      * @return The {@link AccessibilityWindowInfo} list.
      */
     public List<AccessibilityWindowInfo> getWindows(int connectionId) {
-        final SparseArray<List<AccessibilityWindowInfo>> windows =
-                getWindowsOnAllDisplays(connectionId);
-        if (windows.size() > 0) {
-            return windows.valueAt(Display.DEFAULT_DISPLAY);
-        }
-        return Collections.emptyList();
+        return getWindowsOnDisplay(connectionId, Display.DEFAULT_DISPLAY);
     }
 
     /**
+     * Gets the info for all windows of the specified display.
+     *
+     * @param connectionId The id of a connection for interacting with the system.
+     * @return The {@link AccessibilityWindowInfo} list belonging to {@code displayId}.
+     */
+    public List<AccessibilityWindowInfo> getWindowsOnDisplay(int connectionId, int displayId) {
+        final SparseArray<List<AccessibilityWindowInfo>> windows =
+                getWindowsOnAllDisplays(connectionId);
+        return windows.get(displayId, Collections.emptyList());
+    }
+    /**
      * Gets the info for all windows of all displays.
      *
      * @param connectionId The id of a connection for interacting with the system.
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index c067955..b91199d 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -67,6 +67,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -881,7 +882,7 @@
     private long mTraversalBefore = UNDEFINED_NODE_ID;
     private long mTraversalAfter = UNDEFINED_NODE_ID;
 
-    private int mMinMillisBetweenContentChanges;
+    private long mMinDurationBetweenContentChanges = 0;
 
     private int mBooleanProperties;
     private final Rect mBoundsInParent = new Rect();
@@ -1797,18 +1798,21 @@
      * </p>
      *
      * @see AccessibilityEvent#getContentChangeTypes for all content change types.
-     * @param minMillisBetweenContentChanges the minimum duration between content change events.
+     * @param minDurationBetweenContentChanges the minimum duration between content change events.
+     *                                         Negative duration would be treated as zero.
      */
-    public void setMinMillisBetweenContentChanges(int minMillisBetweenContentChanges) {
+    public void setMinDurationBetweenContentChanges(
+            @NonNull Duration minDurationBetweenContentChanges) {
         enforceNotSealed();
-        mMinMillisBetweenContentChanges = minMillisBetweenContentChanges;
+        mMinDurationBetweenContentChanges = minDurationBetweenContentChanges.toMillis();
     }
 
     /**
      * Gets the minimum time duration between two content change events.
      */
-    public int getMinMillisBetweenContentChanges() {
-        return mMinMillisBetweenContentChanges;
+    @NonNull
+    public Duration getMinDurationBetweenContentChanges() {
+        return Duration.ofMillis(mMinDurationBetweenContentChanges);
     }
 
     /**
@@ -4013,8 +4017,8 @@
         fieldIndex++;
         if (mTraversalAfter != DEFAULT.mTraversalAfter) nonDefaultFields |= bitAt(fieldIndex);
         fieldIndex++;
-        if (mMinMillisBetweenContentChanges
-                != DEFAULT.mMinMillisBetweenContentChanges) {
+        if (mMinDurationBetweenContentChanges
+                != DEFAULT.mMinDurationBetweenContentChanges) {
             nonDefaultFields |= bitAt(fieldIndex);
         }
         fieldIndex++;
@@ -4148,7 +4152,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalBefore);
         if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeLong(mTraversalAfter);
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
-            parcel.writeInt(mMinMillisBetweenContentChanges);
+            parcel.writeLong(mMinDurationBetweenContentChanges);
         }
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) parcel.writeInt(mConnectionId);
@@ -4305,7 +4309,7 @@
         mLabeledById = other.mLabeledById;
         mTraversalBefore = other.mTraversalBefore;
         mTraversalAfter = other.mTraversalAfter;
-        mMinMillisBetweenContentChanges = other.mMinMillisBetweenContentChanges;
+        mMinDurationBetweenContentChanges = other.mMinDurationBetweenContentChanges;
         mWindowId = other.mWindowId;
         mConnectionId = other.mConnectionId;
         mUniqueId = other.mUniqueId;
@@ -4410,7 +4414,7 @@
         if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalBefore = parcel.readLong();
         if (isBitSet(nonDefaultFields, fieldIndex++)) mTraversalAfter = parcel.readLong();
         if (isBitSet(nonDefaultFields, fieldIndex++)) {
-            mMinMillisBetweenContentChanges = parcel.readInt();
+            mMinDurationBetweenContentChanges = parcel.readLong();
         }
 
         if (isBitSet(nonDefaultFields, fieldIndex++)) mConnectionId = parcel.readInt();
@@ -4760,8 +4764,8 @@
             builder.append("; mParentNodeId: 0x").append(Long.toHexString(mParentNodeId));
             builder.append("; traversalBefore: 0x").append(Long.toHexString(mTraversalBefore));
             builder.append("; traversalAfter: 0x").append(Long.toHexString(mTraversalAfter));
-            builder.append("; minMillisBetweenContentChanges: ")
-                    .append(mMinMillisBetweenContentChanges);
+            builder.append("; minDurationBetweenContentChanges: ")
+                    .append(mMinDurationBetweenContentChanges);
 
             int granularities = mMovementGranularities;
             builder.append("; MovementGranularities: [");
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index a251948..364c7c8 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -27,6 +27,7 @@
 import android.view.accessibility.IAccessibilityManagerClient;
 import android.view.accessibility.AccessibilityWindowAttributes;
 import android.view.accessibility.IWindowMagnificationConnection;
+import android.view.InputEvent;
 import android.view.IWindow;
 
 /**
@@ -114,4 +115,7 @@
 
     @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MANAGE_ACCESSIBILITY)")
     boolean unregisterProxyForDisplay(int displayId);
+
+    // Used by UiAutomation for tests on the InputFilter
+    void injectInputEventToInputFilter(in InputEvent event);
 }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 5265840..e6379cf 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -968,7 +968,8 @@
         final int position = getSelectedItemPosition();
         if (position >= 0) {
             // we fire selection events here not in View
-            sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+            // posting the event should delay it long enough for UI changes to take effect.
+            post(() -> sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED));
         }
     }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 5740f86..0a3ea8a 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2054,7 +2054,10 @@
         }
     }
 
-    void onDraw(Canvas canvas, Layout layout, Path highlight, Paint highlightPaint,
+    void onDraw(Canvas canvas, Layout layout,
+            List<Path> highlightPaths,
+            List<Paint> highlightPaints,
+            Path selectionHighlight, Paint selectionHighlightPaint,
             int cursorOffsetVertical) {
         final int selectionStart = mTextView.getSelectionStart();
         final int selectionEnd = mTextView.getSelectionEnd();
@@ -2078,37 +2081,41 @@
             mCorrectionHighlighter.draw(canvas, cursorOffsetVertical);
         }
 
-        if (highlight != null && selectionStart == selectionEnd && mDrawableForCursor != null) {
+        if (selectionHighlight != null && selectionStart == selectionEnd
+                && mDrawableForCursor != null
+                && !mTextView.hasGesturePreviewHighlight()) {
             drawCursor(canvas, cursorOffsetVertical);
             // Rely on the drawable entirely, do not draw the cursor line.
             // Has to be done after the IMM related code above which relies on the highlight.
-            highlight = null;
+            selectionHighlight = null;
         }
 
         if (mSelectionActionModeHelper != null) {
             mSelectionActionModeHelper.onDraw(canvas);
             if (mSelectionActionModeHelper.isDrawingHighlight()) {
-                highlight = null;
+                selectionHighlight = null;
             }
         }
 
         if (mTextView.canHaveDisplayList() && canvas.isHardwareAccelerated()) {
-            drawHardwareAccelerated(canvas, layout, highlight, highlightPaint,
-                    cursorOffsetVertical);
+            drawHardwareAccelerated(canvas, layout, highlightPaths, highlightPaints,
+                    selectionHighlight, selectionHighlightPaint, cursorOffsetVertical);
         } else {
-            layout.draw(canvas, highlight, highlightPaint, cursorOffsetVertical);
+            layout.draw(canvas, highlightPaths, highlightPaints, selectionHighlight,
+                    selectionHighlightPaint, cursorOffsetVertical);
         }
     }
 
-    private void drawHardwareAccelerated(Canvas canvas, Layout layout, Path highlight,
-            Paint highlightPaint, int cursorOffsetVertical) {
+    private void drawHardwareAccelerated(Canvas canvas, Layout layout,
+            List<Path> highlightPaths, List<Paint> highlightPaints,
+            Path selectionHighlight, Paint selectionHighlightPaint, int cursorOffsetVertical) {
         final long lineRange = layout.getLineRangeForDraw(canvas);
         int firstLine = TextUtils.unpackRangeStartFromLong(lineRange);
         int lastLine = TextUtils.unpackRangeEndFromLong(lineRange);
         if (lastLine < 0) return;
 
-        layout.drawBackground(canvas, highlight, highlightPaint, cursorOffsetVertical,
-                firstLine, lastLine);
+        layout.drawWithoutText(canvas, highlightPaths, highlightPaints, selectionHighlight,
+                selectionHighlightPaint, cursorOffsetVertical, firstLine, lastLine);
 
         if (layout instanceof DynamicLayout) {
             if (mTextRenderNodes == null) {
@@ -2154,8 +2161,9 @@
                     continue;
                 }
                 startIndexToFindAvailableRenderNode = drawHardwareAcceleratedInner(canvas, layout,
-                        highlight, highlightPaint, cursorOffsetVertical, blockEndLines,
-                        blockIndices, i, numberOfBlocks, startIndexToFindAvailableRenderNode);
+                        selectionHighlight, selectionHighlightPaint, cursorOffsetVertical,
+                        blockEndLines, blockIndices, i, numberOfBlocks,
+                        startIndexToFindAvailableRenderNode);
                 if (blockEndLines[i] >= lastLine) {
                     lastIndex = Math.max(indexFirstChangedBlock, i + 1);
                     break;
@@ -2169,9 +2177,9 @@
                             || mTextRenderNodes[blockIndex] == null
                             || mTextRenderNodes[blockIndex].needsToBeShifted) {
                         startIndexToFindAvailableRenderNode = drawHardwareAcceleratedInner(canvas,
-                                layout, highlight, highlightPaint, cursorOffsetVertical,
-                                blockEndLines, blockIndices, block, numberOfBlocks,
-                                startIndexToFindAvailableRenderNode);
+                                layout, selectionHighlight, selectionHighlightPaint,
+                                cursorOffsetVertical, blockEndLines, blockIndices, block,
+                                numberOfBlocks, startIndexToFindAvailableRenderNode);
                     }
                 }
             }
@@ -2707,7 +2715,7 @@
         unregisterOnBackInvokedCallback();
     }
 
-    private void stopTextActionModeWithPreservingSelection() {
+    void stopTextActionModeWithPreservingSelection() {
         if (mTextActionMode != null) {
             mRestartActionModeOnNextRefresh = true;
         }
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index ba6fa19..ad431ef 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -802,6 +802,21 @@
         dialog.dismiss();
     }
 
+    /**
+     * Sets selection and dismisses the spinner's popup if it can be dismissed.
+     * For ease of use in tests, where publicly obtaining the spinner's popup is difficult.
+     *
+     * @param which index of the item to be selected.
+     * @hide
+     */
+    @TestApi
+    public void onClick(int which) {
+        setSelection(which);
+        if (mPopup != null && mPopup.isShowing()) {
+            mPopup.dismiss();
+        }
+    }
+
     @Override
     public CharSequence getAccessibilityClassName() {
         return Spinner.class.getName();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index bf1a2bd..b9b928e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -68,6 +68,7 @@
 import android.graphics.BaseCanvas;
 import android.graphics.BlendMode;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Paint;
@@ -87,6 +88,7 @@
 import android.os.Build;
 import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.LocaleList;
 import android.os.Parcel;
@@ -102,6 +104,7 @@
 import android.text.GetChars;
 import android.text.GraphemeClusterSegmentFinder;
 import android.text.GraphicsOperations;
+import android.text.Highlights;
 import android.text.InputFilter;
 import android.text.InputType;
 import android.text.Layout;
@@ -147,6 +150,7 @@
 import android.text.style.URLSpan;
 import android.text.style.UpdateAppearance;
 import android.text.util.Linkify;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.util.FeatureFlagUtils;
@@ -198,6 +202,7 @@
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InsertGesture;
 import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.PreviewableHandwritingGesture;
 import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
 import android.view.inputmethod.SelectRangeGesture;
@@ -221,6 +226,7 @@
 
 import com.android.internal.accessibility.util.AccessibilityUtils;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.graphics.ColorUtils;
 import com.android.internal.inputmethod.EditableInputConnection;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -238,8 +244,10 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
@@ -926,6 +934,15 @@
     @UnsupportedAppUsage
     private boolean mHighlightPathBogus = true;
 
+    private List<Path> mHighlightPaths;
+    private List<Paint> mHighlightPaints;
+    private Highlights mHighlights;
+    private int mGesturePreviewHighlightStart = -1;
+    private int mGesturePreviewHighlightEnd = -1;
+    private Paint mGesturePreviewHighlightPaint;
+    private final List<Path> mPathRecyclePool = new ArrayList<>();
+    private boolean mHighlightPathsBogus = true;
+
     // Although these fields are specific to editable text, they are not added to Editor because
     // they are defined by the TextView's style and are theme-dependent.
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@@ -6131,6 +6148,87 @@
     }
 
     /**
+     * Set Highlights
+     *
+     * @param highlights A highlight object. Call with null for reset.
+     *
+     * @see #getHighlights()
+     * @see Highlights
+     */
+    public void setHighlights(@Nullable Highlights highlights) {
+        mHighlights = highlights;
+        mHighlightPathsBogus = true;
+        invalidate();
+    }
+
+    /**
+     * Returns highlights
+     *
+     * @return a highlight to be drawn. null if no highlight was set.
+     *
+     * @see #setHighlights(Highlights)
+     * @see Highlights
+     *
+     */
+    @Nullable
+    public Highlights getHighlights() {
+        return mHighlights;
+    }
+
+    /**
+     * Highlights the text range (from inclusive start offset to exclusive end offset) to show what
+     * will be selected by the ongoing select handwriting gesture. While the gesture preview
+     * highlight is shown, the selection or cursor is hidden. If the text or selection is changed,
+     * the gesture preview highlight will be cleared.
+     */
+    private void setSelectGesturePreviewHighlight(int start, int end) {
+        // Selection preview highlight color is the same as selection highlight color.
+        setGesturePreviewHighlight(start, end, mHighlightColor);
+    }
+
+    /**
+     * Highlights the text range (from inclusive start offset to exclusive end offset) to show what
+     * will be deleted by the ongoing delete handwriting gesture. While the gesture preview
+     * highlight is shown, the selection or cursor is hidden. If the text or selection is changed,
+     * the gesture preview highlight will be cleared.
+     */
+    private void setDeleteGesturePreviewHighlight(int start, int end) {
+        // Deletion preview highlight color is 20% opacity of the default text color.
+        int color = mTextColor.getDefaultColor();
+        color = ColorUtils.setAlphaComponent(color, (int) (0.2f * Color.alpha(color)));
+        setGesturePreviewHighlight(start, end, color);
+    }
+
+    private void setGesturePreviewHighlight(int start, int end, int color) {
+        mGesturePreviewHighlightStart = start;
+        mGesturePreviewHighlightEnd = end;
+        if (mGesturePreviewHighlightPaint == null) {
+            mGesturePreviewHighlightPaint = new Paint();
+            mGesturePreviewHighlightPaint.setStyle(Paint.Style.FILL);
+        }
+        mGesturePreviewHighlightPaint.setColor(color);
+
+        if (mEditor != null) {
+            mEditor.hideCursorAndSpanControllers();
+            mEditor.stopTextActionModeWithPreservingSelection();
+        }
+
+        mHighlightPathsBogus = true;
+        invalidate();
+    }
+
+    private void clearGesturePreviewHighlight() {
+        mGesturePreviewHighlightStart = -1;
+        mGesturePreviewHighlightEnd = -1;
+        mHighlightPathsBogus = true;
+        invalidate();
+    }
+
+    boolean hasGesturePreviewHighlight() {
+        return mGesturePreviewHighlightStart > 0;
+    }
+
+    /**
      * Convenience method to append the specified text to the TextView's
      * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
      * if it was not already editable.
@@ -8219,6 +8317,70 @@
         return drawableState;
     }
 
+    private void maybeUpdateHighlightPaths() {
+        if (!mHighlightPathsBogus) {
+            return;
+        }
+
+        if (mHighlightPaths != null) {
+            mPathRecyclePool.addAll(mHighlightPaths);
+            mHighlightPaths.clear();
+            mHighlightPaints.clear();
+        } else {
+            mHighlightPaths = new ArrayList<>();
+            mHighlightPaints = new ArrayList<>();
+        }
+
+        if (mHighlights != null) {
+            for (int i = 0; i < mHighlights.getSize(); ++i) {
+                final int[] ranges = mHighlights.getRanges(i);
+                final Paint paint = mHighlights.getPaint(i);
+
+                final Path path;
+                if (mPathRecyclePool.isEmpty()) {
+                    path = new Path();
+                } else {
+                    path = mPathRecyclePool.get(mPathRecyclePool.size() - 1);
+                    mPathRecyclePool.remove(mPathRecyclePool.size() - 1);
+                    path.reset();
+                }
+
+                boolean atLeastOnePathAdded = false;
+                for (int j = 0; j < ranges.length / 2; ++j) {
+                    final int start = ranges[2 * j];
+                    final int end = ranges[2 * j + 1];
+                    if (start < end) {
+                        mLayout.getSelection(start, end, (left, top, right, bottom, layout) ->
+                                path.addRect(left, top, right, bottom, Path.Direction.CW)
+                        );
+                        atLeastOnePathAdded = true;
+                    }
+                }
+                if (atLeastOnePathAdded) {
+                    mHighlightPaths.add(path);
+                    mHighlightPaints.add(paint);
+                }
+            }
+        }
+
+        if (hasGesturePreviewHighlight()) {
+            final Path path;
+            if (mPathRecyclePool.isEmpty()) {
+                path = new Path();
+            } else {
+                path = mPathRecyclePool.get(mPathRecyclePool.size() - 1);
+                mPathRecyclePool.remove(mPathRecyclePool.size() - 1);
+                path.reset();
+            }
+            mLayout.getSelectionPath(
+                    mGesturePreviewHighlightStart, mGesturePreviewHighlightEnd, path);
+            mHighlightPaths.add(path);
+            mHighlightPaints.add(mGesturePreviewHighlightPaint);
+        }
+
+        mHighlightPathsBogus = false;
+    }
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     private Path getUpdatedHighlightPath() {
         Path highlight = null;
@@ -8418,17 +8580,22 @@
 
         final int cursorOffsetVertical = voffsetCursor - voffsetText;
 
-        Path highlight = getUpdatedHighlightPath();
+        maybeUpdateHighlightPaths();
+        // If there is a gesture preview highlight, then the selection or cursor is not drawn.
+        Path highlight = hasGesturePreviewHighlight() ? null : getUpdatedHighlightPath();
         if (mEditor != null) {
-            mEditor.onDraw(canvas, layout, highlight, mHighlightPaint, cursorOffsetVertical);
+            mEditor.onDraw(canvas, layout, mHighlightPaths, mHighlightPaints, highlight,
+                    mHighlightPaint, cursorOffsetVertical);
         } else {
-            layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
+            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                    cursorOffsetVertical);
         }
 
         if (mMarquee != null && mMarquee.shouldDrawGhost()) {
             final float dx = mMarquee.getGhostOffset();
             canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
-            layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
+            layout.draw(canvas, mHighlightPaths, mHighlightPaints, highlight, mHighlightPaint,
+                    cursorOffsetVertical);
         }
 
         canvas.restore();
@@ -9112,6 +9279,14 @@
                 gestures.add(RemoveSpaceGesture.class);
                 gestures.add(JoinOrSplitGesture.class);
                 outAttrs.setSupportedHandwritingGestures(gestures);
+
+                Set<Class<? extends PreviewableHandwritingGesture>> previews = new ArraySet<>();
+                previews.add(SelectGesture.class);
+                previews.add(SelectRangeGesture.class);
+                previews.add(DeleteGesture.class);
+                previews.add(DeleteRangeGesture.class);
+                outAttrs.setSupportedHandwritingGesturePreviews(previews);
+
                 return ic;
             }
         }
@@ -9323,83 +9498,130 @@
     }
 
     /** @hide */
+    public boolean previewHandwritingGesture(
+            @NonNull PreviewableHandwritingGesture gesture,
+            @Nullable CancellationSignal cancellationSignal) {
+        if (gesture instanceof SelectGesture) {
+            performHandwritingSelectGesture((SelectGesture) gesture, /* isPreview= */ true);
+        } else if (gesture instanceof SelectRangeGesture) {
+            performHandwritingSelectRangeGesture(
+                    (SelectRangeGesture) gesture, /* isPreview= */ true);
+        } else if (gesture instanceof DeleteGesture) {
+            performHandwritingDeleteGesture((DeleteGesture) gesture, /* isPreview= */ true);
+        } else if (gesture instanceof DeleteRangeGesture) {
+            performHandwritingDeleteRangeGesture(
+                    (DeleteRangeGesture) gesture, /* isPreview= */ true);
+        } else {
+            return false;
+        }
+        if (cancellationSignal != null) {
+            cancellationSignal.setOnCancelListener(this::clearGesturePreviewHighlight);
+        }
+        return true;
+    }
+
+    /** @hide */
     public int performHandwritingSelectGesture(@NonNull SelectGesture gesture) {
+        return performHandwritingSelectGesture(gesture, /* isPreview= */ false);
+    }
+
+    private int performHandwritingSelectGesture(@NonNull SelectGesture gesture, boolean isPreview) {
         int[] range = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getSelectionArea()),
                 gesture.getGranularity());
         if (range == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
-        Selection.setSelection(getEditableText(), range[0], range[1]);
-        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
+        return performHandwritingSelectGesture(range, isPreview);
+    }
+
+    private int performHandwritingSelectGesture(int[] range, boolean isPreview) {
+        if (isPreview) {
+            setSelectGesturePreviewHighlight(range[0], range[1]);
+        } else {
+            Selection.setSelection(getEditableText(), range[0], range[1]);
+            mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
+        }
         return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
     }
 
     /** @hide */
     public int performHandwritingSelectRangeGesture(@NonNull SelectRangeGesture gesture) {
+        return performHandwritingSelectRangeGesture(gesture, /* isPreview= */ false);
+    }
+
+    private int performHandwritingSelectRangeGesture(
+            @NonNull SelectRangeGesture gesture, boolean isPreview) {
         int[] startRange = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getSelectionStartArea()),
                 gesture.getGranularity());
         if (startRange == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
         int[] endRange = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getSelectionEndArea()),
                 gesture.getGranularity());
         if (endRange == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
         int[] range = new int[] {
                 Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
         };
-        Selection.setSelection(getEditableText(), range[0], range[1]);
-        mEditor.startSelectionActionModeAsync(/* adjustSelection= */ false);
-        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+        return performHandwritingSelectGesture(range, isPreview);
     }
 
     /** @hide */
     public int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture) {
+        return performHandwritingDeleteGesture(gesture, /* isPreview= */ false);
+    }
+
+    private int performHandwritingDeleteGesture(@NonNull DeleteGesture gesture, boolean isPreview) {
         int[] range = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getDeletionArea()),
                 gesture.getGranularity());
         if (range == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
+        return performHandwritingDeleteGesture(range, gesture.getGranularity(), isPreview);
+    }
 
-        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
-            range = adjustHandwritingDeleteGestureRange(range);
+    private int performHandwritingDeleteGesture(int[] range, int granularity, boolean isPreview) {
+        if (isPreview) {
+            setDeleteGesturePreviewHighlight(range[0], range[1]);
+        } else {
+            if (granularity == HandwritingGesture.GRANULARITY_WORD) {
+                range = adjustHandwritingDeleteGestureRange(range);
+            }
+
+            getEditableText().delete(range[0], range[1]);
+            Selection.setSelection(getEditableText(), range[0]);
         }
-
-        getEditableText().delete(range[0], range[1]);
-        Selection.setSelection(getEditableText(), range[0]);
         return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
     }
 
     /** @hide */
     public int performHandwritingDeleteRangeGesture(@NonNull DeleteRangeGesture gesture) {
+        return performHandwritingDeleteRangeGesture(gesture, /* isPreview= */ false);
+    }
+
+    private int performHandwritingDeleteRangeGesture(
+            @NonNull DeleteRangeGesture gesture, boolean isPreview) {
         int[] startRange = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getDeletionStartArea()),
                 gesture.getGranularity());
         if (startRange == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
         int[] endRange = getRangeForRect(
                 convertFromScreenToContentCoordinates(gesture.getDeletionEndArea()),
                 gesture.getGranularity());
         if (endRange == null) {
-            return handleGestureFailure(gesture);
+            return handleGestureFailure(gesture, isPreview);
         }
         int[] range = new int[] {
                 Math.min(startRange[0], endRange[0]), Math.max(startRange[1], endRange[1])
         };
-
-        if (gesture.getGranularity() == HandwritingGesture.GRANULARITY_WORD) {
-            range = adjustHandwritingDeleteGestureRange(range);
-        }
-
-        getEditableText().delete(range[0], range[1]);
-        Selection.setSelection(getEditableText(), range[0]);
-        return InputConnection.HANDWRITING_GESTURE_RESULT_SUCCESS;
+        return performHandwritingDeleteGesture(range, gesture.getGranularity(), isPreview);
     }
 
     private int[] adjustHandwritingDeleteGestureRange(int[] range) {
@@ -9577,7 +9799,12 @@
     }
 
     private int handleGestureFailure(HandwritingGesture gesture) {
-        if (!TextUtils.isEmpty(gesture.getFallbackText())) {
+        return handleGestureFailure(gesture, /* isPreview= */ false);
+    }
+
+    private int handleGestureFailure(HandwritingGesture gesture, boolean isPreview) {
+        clearGesturePreviewHighlight();
+        if (!isPreview && !TextUtils.isEmpty(gesture.getFallbackText())) {
             getEditableText()
                     .replace(getSelectionStart(), getSelectionEnd(), gesture.getFallbackText());
             return InputConnection.HANDWRITING_GESTURE_RESULT_FALLBACK;
@@ -9750,6 +9977,7 @@
         mOldMaxMode = mMaxMode;
 
         mHighlightPathBogus = true;
+        mHighlightPathsBogus = true;
 
         if (wantWidth < 0) {
             wantWidth = 0;
@@ -11610,6 +11838,8 @@
         resetErrorChangedFlag();
         sendOnTextChanged(buffer, start, before, after);
         onTextChanged(buffer, start, before, after);
+
+        clearGesturePreviewHighlight();
     }
 
     /**
@@ -11648,6 +11878,7 @@
         }
 
         if (selChanged) {
+            clearGesturePreviewHighlight();
             mHighlightPathBogus = true;
             if (mEditor != null && !isFocused()) mEditor.mSelectionMoved = true;
 
diff --git a/core/java/android/window/BackEvent.aidl b/core/java/android/window/BackEvent.aidl
deleted file mode 100644
index 821f1fa..0000000
--- a/core/java/android/window/BackEvent.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.window;
-
-/**
- * @hide
- */
-parcelable BackEvent;
diff --git a/core/java/android/window/BackEvent.java b/core/java/android/window/BackEvent.java
index 85b2881..40c0fee 100644
--- a/core/java/android/window/BackEvent.java
+++ b/core/java/android/window/BackEvent.java
@@ -16,29 +16,24 @@
 
 package android.window;
 
+import android.annotation.FloatRange;
 import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.view.RemoteAnimationTarget;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
 /**
- * Represents an event that is sent out by the system during back navigation gesture.
- * Holds information about the touch event, swipe direction and overall progress of the gesture
- * interaction.
- *
- * @hide
+ * Object used to report back gesture progress.
+ * Holds information about the touch event, swipe direction and the animation progress that
+ * predictive back animations should seek to.
  */
-public class BackEvent implements Parcelable {
+public final class BackEvent {
     /** Indicates that the edge swipe starts from the left edge of the screen */
     public static final int EDGE_LEFT = 0;
     /** Indicates that the edge swipe starts from the right edge of the screen */
     public static final int EDGE_RIGHT = 1;
 
+    /** @hide */
     @IntDef({
             EDGE_LEFT,
             EDGE_RIGHT,
@@ -52,78 +47,52 @@
 
     @SwipeEdge
     private final int mSwipeEdge;
-    @Nullable
-    private final RemoteAnimationTarget mDepartingAnimationTarget;
 
     /**
-     * Creates a new {@link BackEvent} instance.
+     * Creates a new {@link BackMotionEvent} instance.
      *
      * @param touchX Absolute X location of the touch point of this event.
      * @param touchY Absolute Y location of the touch point of this event.
      * @param progress Value between 0 and 1 on how far along the back gesture is.
      * @param swipeEdge Indicates which edge the swipe starts from.
-     * @param departingAnimationTarget The remote animation target of the departing
-     *                                 application window.
      */
-    public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge,
-            @Nullable RemoteAnimationTarget departingAnimationTarget) {
+    public BackEvent(float touchX, float touchY, float progress, @SwipeEdge int swipeEdge) {
         mTouchX = touchX;
         mTouchY = touchY;
         mProgress = progress;
         mSwipeEdge = swipeEdge;
-        mDepartingAnimationTarget = departingAnimationTarget;
-    }
-
-    private BackEvent(@NonNull Parcel in) {
-        mTouchX = in.readFloat();
-        mTouchY = in.readFloat();
-        mProgress = in.readFloat();
-        mSwipeEdge = in.readInt();
-        mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
-    }
-
-    public static final Creator<BackEvent> CREATOR = new Creator<BackEvent>() {
-        @Override
-        public BackEvent createFromParcel(Parcel in) {
-            return new BackEvent(in);
-        }
-
-        @Override
-        public BackEvent[] newArray(int size) {
-            return new BackEvent[size];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(@NonNull Parcel dest, int flags) {
-        dest.writeFloat(mTouchX);
-        dest.writeFloat(mTouchY);
-        dest.writeFloat(mProgress);
-        dest.writeInt(mSwipeEdge);
-        dest.writeTypedObject(mDepartingAnimationTarget, flags);
     }
 
     /**
-     * Returns a value between 0 and 1 on how far along the back gesture is.
+     * Returns a value between 0 and 1 on how far along the back gesture is. This value is
+     * driven by the horizontal location of the touch point, and should be used as the fraction to
+     * seek the predictive back animation with. Specifically,
+     * <ol>
+     * <li>The progress is 0 when the touch is at the starting edge of the screen (left or right),
+     * and animation should seek to its start state.
+     * <li>The progress is approximately 1 when the touch is at the opposite side of the screen,
+     * and animation should seek to its end state. Exact end value may vary depending on
+     * screen size.
+     * </ol>
+     * In-between locations are linearly interpolated based on horizontal distance from the starting
+     * edge and smooth clamped to 1 when the distance exceeds a system-wide threshold.
      */
+    @FloatRange(from = 0, to = 1)
     public float getProgress() {
         return mProgress;
     }
 
     /**
-     * Returns the absolute X location of the touch point.
+     * Returns the absolute X location of the touch point, or NaN if the event is from
+     * a button press.
      */
     public float getTouchX() {
         return mTouchX;
     }
 
     /**
-     * Returns the absolute Y location of the touch point.
+     * Returns the absolute Y location of the touch point, or NaN if the event is from
+     * a button press.
      */
     public float getTouchY() {
         return mTouchY;
@@ -132,20 +101,11 @@
     /**
      * Returns the screen edge that the swipe starts from.
      */
+    @SwipeEdge
     public int getSwipeEdge() {
         return mSwipeEdge;
     }
 
-    /**
-     * Returns the {@link RemoteAnimationTarget} of the top departing application window,
-     * or {@code null} if the top window should not be moved for the current type of back
-     * destination.
-     */
-    @Nullable
-    public RemoteAnimationTarget getDepartingAnimationTarget() {
-        return mDepartingAnimationTarget;
-    }
-
     @Override
     public String toString() {
         return "BackEvent{"
diff --git a/core/java/android/window/BackMotionEvent.aidl b/core/java/android/window/BackMotionEvent.aidl
new file mode 100644
index 0000000..7c675c3
--- /dev/null
+++ b/core/java/android/window/BackMotionEvent.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.window;
+
+/**
+ * @hide
+ */
+parcelable BackMotionEvent;
diff --git a/core/java/android/window/BackMotionEvent.java b/core/java/android/window/BackMotionEvent.java
new file mode 100644
index 0000000..8012a1c
--- /dev/null
+++ b/core/java/android/window/BackMotionEvent.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.window;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.RemoteAnimationTarget;
+
+/**
+ * Object used to report back gesture progress. Holds information about a {@link BackEvent} plus
+ * any {@link RemoteAnimationTarget} the gesture manipulates.
+ *
+ * @see BackEvent
+ * @hide
+ */
+public final class BackMotionEvent implements Parcelable {
+    private final float mTouchX;
+    private final float mTouchY;
+    private final float mProgress;
+
+    @BackEvent.SwipeEdge
+    private final int mSwipeEdge;
+    @Nullable
+    private final RemoteAnimationTarget mDepartingAnimationTarget;
+
+    /**
+     * Creates a new {@link BackMotionEvent} instance.
+     *
+     * @param touchX Absolute X location of the touch point of this event.
+     * @param touchY Absolute Y location of the touch point of this event.
+     * @param progress Value between 0 and 1 on how far along the back gesture is.
+     * @param swipeEdge Indicates which edge the swipe starts from.
+     * @param departingAnimationTarget The remote animation target of the departing
+     *                                 application window.
+     */
+    public BackMotionEvent(float touchX, float touchY, float progress,
+            @BackEvent.SwipeEdge int swipeEdge,
+            @Nullable RemoteAnimationTarget departingAnimationTarget) {
+        mTouchX = touchX;
+        mTouchY = touchY;
+        mProgress = progress;
+        mSwipeEdge = swipeEdge;
+        mDepartingAnimationTarget = departingAnimationTarget;
+    }
+
+    private BackMotionEvent(@NonNull Parcel in) {
+        mTouchX = in.readFloat();
+        mTouchY = in.readFloat();
+        mProgress = in.readFloat();
+        mSwipeEdge = in.readInt();
+        mDepartingAnimationTarget = in.readTypedObject(RemoteAnimationTarget.CREATOR);
+    }
+
+    @NonNull
+    public static final Creator<BackMotionEvent> CREATOR = new Creator<BackMotionEvent>() {
+        @Override
+        public BackMotionEvent createFromParcel(Parcel in) {
+            return new BackMotionEvent(in);
+        }
+
+        @Override
+        public BackMotionEvent[] newArray(int size) {
+            return new BackMotionEvent[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeFloat(mTouchX);
+        dest.writeFloat(mTouchY);
+        dest.writeFloat(mProgress);
+        dest.writeInt(mSwipeEdge);
+        dest.writeTypedObject(mDepartingAnimationTarget, flags);
+    }
+
+    /**
+     * Returns the progress of a {@link BackEvent}.
+     *
+     * @see BackEvent#getProgress()
+     */
+    @FloatRange(from = 0, to = 1)
+    public float getProgress() {
+        return mProgress;
+    }
+
+    /**
+     * Returns the absolute X location of the touch point.
+     */
+    public float getTouchX() {
+        return mTouchX;
+    }
+
+    /**
+     * Returns the absolute Y location of the touch point.
+     */
+    public float getTouchY() {
+        return mTouchY;
+    }
+
+    /**
+     * Returns the screen edge that the swipe starts from.
+     */
+    @BackEvent.SwipeEdge
+    public int getSwipeEdge() {
+        return mSwipeEdge;
+    }
+
+    /**
+     * Returns the {@link RemoteAnimationTarget} of the top departing application window,
+     * or {@code null} if the top window should not be moved for the current type of back
+     * destination.
+     */
+    @Nullable
+    public RemoteAnimationTarget getDepartingAnimationTarget() {
+        return mDepartingAnimationTarget;
+    }
+
+    @Override
+    public String toString() {
+        return "BackMotionEvent{"
+                + "mTouchX=" + mTouchX
+                + ", mTouchY=" + mTouchY
+                + ", mProgress=" + mProgress
+                + ", mSwipeEdge" + mSwipeEdge
+                + ", mDepartingAnimationTarget" + mDepartingAnimationTarget
+                + "}";
+    }
+}
diff --git a/core/java/android/window/BackProgressAnimator.java b/core/java/android/window/BackProgressAnimator.java
index 2e3afde..14a57e0 100644
--- a/core/java/android/window/BackProgressAnimator.java
+++ b/core/java/android/window/BackProgressAnimator.java
@@ -40,7 +40,7 @@
     private final SpringAnimation mSpring;
     private ProgressCallback mCallback;
     private float mProgress = 0;
-    private BackEvent mLastBackEvent;
+    private BackMotionEvent mLastBackEvent;
     private boolean mStarted = false;
 
     private void setProgress(float progress) {
@@ -82,9 +82,9 @@
     /**
      * Sets a new target position for the back progress.
      *
-     * @param event the {@link BackEvent} containing the latest target progress.
+     * @param event the {@link BackMotionEvent} containing the latest target progress.
      */
-    public void onBackProgressed(BackEvent event) {
+    public void onBackProgressed(BackMotionEvent event) {
         if (!mStarted) {
             return;
         }
@@ -98,11 +98,11 @@
     /**
      * Starts the back progress animation.
      *
-     * @param event the {@link BackEvent} that started the gesture.
+     * @param event the {@link BackMotionEvent} that started the gesture.
      * @param callback the back callback to invoke for the gesture. It will receive back progress
      *                 dispatches as the progress animation updates.
      */
-    public void onBackStarted(BackEvent event, ProgressCallback callback) {
+    public void onBackStarted(BackMotionEvent event, ProgressCallback callback) {
         reset();
         mLastBackEvent = event;
         mCallback = callback;
@@ -132,8 +132,7 @@
         }
         mCallback.onProgressUpdate(
                 new BackEvent(mLastBackEvent.getTouchX(), mLastBackEvent.getTouchY(),
-                        progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge(),
-                        mLastBackEvent.getDepartingAnimationTarget()));
+                        progress / SCALE_FACTOR, mLastBackEvent.getSwipeEdge()));
     }
 
 }
diff --git a/core/java/android/window/IOnBackInvokedCallback.aidl b/core/java/android/window/IOnBackInvokedCallback.aidl
index 6af8ddd..159c0e8 100644
--- a/core/java/android/window/IOnBackInvokedCallback.aidl
+++ b/core/java/android/window/IOnBackInvokedCallback.aidl
@@ -17,7 +17,7 @@
 
 package android.window;
 
-import android.window.BackEvent;
+import android.window.BackMotionEvent;
 
 /**
  * Interface that wraps a {@link OnBackInvokedCallback} object, to be stored in window manager
@@ -30,18 +30,19 @@
     * Called when a back gesture has been started, or back button has been pressed down.
     * Wraps {@link OnBackInvokedCallback#onBackStarted(BackEvent)}.
     *
-    * @param backEvent The {@link BackEvent} containing information about the touch or button press.
+    * @param backMotionEvent The {@link BackMotionEvent} containing information about the touch
+    *        or button press.
     */
-    void onBackStarted(in BackEvent backEvent);
+    void onBackStarted(in BackMotionEvent backMotionEvent);
 
     /**
      * Called on back gesture progress.
      * Wraps {@link OnBackInvokedCallback#onBackProgressed(BackEvent)}.
      *
-     * @param backEvent The {@link BackEvent} containing information about the latest touch point
-     *                  and the progress that the back animation should seek to.
+     * @param backMotionEvent The {@link BackMotionEvent} containing information about the latest
+     *                        touch point and the progress that the back animation should seek to.
      */
-    void onBackProgressed(in BackEvent backEvent);
+    void onBackProgressed(in BackMotionEvent backMotionEvent);
 
     /**
      * Called when a back gesture or back button press has been cancelled.
diff --git a/core/java/android/window/OnBackAnimationCallback.java b/core/java/android/window/OnBackAnimationCallback.java
index c05809b..9119e71 100644
--- a/core/java/android/window/OnBackAnimationCallback.java
+++ b/core/java/android/window/OnBackAnimationCallback.java
@@ -18,6 +18,8 @@
 import android.app.Activity;
 import android.app.Dialog;
 import android.view.View;
+import android.view.Window;
+
 /**
  * Interface for applications to register back animation callbacks along their custom back
  * handling.
@@ -25,24 +27,29 @@
  * This allows the client to customize various back behaviors by overriding the corresponding
  * callback methods.
  * <p>
- * Callback instances can be added to and removed from {@link OnBackInvokedDispatcher}, held
- * by classes that implement {@link OnBackInvokedDispatcherOwner} (such as {@link Activity},
- * {@link Dialog} and {@link View}).
+ * Callback instances can be added to and removed from {@link OnBackInvokedDispatcher}, which
+ * is held at window level and accessible through {@link Activity#getOnBackInvokedDispatcher()},
+ * {@link Dialog#getOnBackInvokedDispatcher()}, {@link Window#getOnBackInvokedDispatcher()}
+ * and {@link View#findOnBackInvokedDispatcher()}.
  * <p>
  * When back is triggered, callbacks on the in-focus window are invoked in reverse order in which
  * they are added within the same priority. Between different priorities, callbacks with higher
  * priority are invoked first.
  * <p>
  * @see OnBackInvokedCallback
- * @hide
  */
 public interface OnBackAnimationCallback extends OnBackInvokedCallback {
     /**
      * Called when a back gesture has been started, or back button has been pressed down.
+     *
+     * @param backEvent The {@link BackEvent} containing information about the touch or
+     *                  button press.
+     * @see BackEvent
      */
-    default void onBackStarted() { }
+    default void onBackStarted(@NonNull BackEvent backEvent) {}
+
     /**
-     * Called on back gesture progress.
+     * Called when a back gesture progresses.
      *
      * @param backEvent An {@link BackEvent} object describing the progress event.
      *
diff --git a/core/java/android/window/OnBackInvokedCallback.java b/core/java/android/window/OnBackInvokedCallback.java
index 62c41bf..6beaad3 100644
--- a/core/java/android/window/OnBackInvokedCallback.java
+++ b/core/java/android/window/OnBackInvokedCallback.java
@@ -16,9 +16,9 @@
 
 package android.window;
 
-import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.Dialog;
+import android.view.View;
 import android.view.Window;
 
 /**
@@ -26,7 +26,8 @@
  * <p>
  * Callback instances can be added to and removed from {@link OnBackInvokedDispatcher}, which
  * is held at window level and accessible through {@link Activity#getOnBackInvokedDispatcher()},
- * {@link Dialog#getOnBackInvokedDispatcher()} and {@link Window#getOnBackInvokedDispatcher()}.
+ * {@link Dialog#getOnBackInvokedDispatcher()}, {@link Window#getOnBackInvokedDispatcher()}
+ * and {@link View#findOnBackInvokedDispatcher()}.
  * <p>
  * When back is triggered, callbacks on the in-focus window are invoked in reverse order in which
  * they are added within the same priority. Between different priorities, callbacks with higher
@@ -35,6 +36,9 @@
  * This replaces {@link Activity#onBackPressed()}, {@link Dialog#onBackPressed()} and
  * {@link android.view.KeyEvent#KEYCODE_BACK}
  * <p>
+ * If you want to customize back animation behaviors, in addition to handling back invocations,
+ * register its subclass instances {@link OnBackAnimationCallback} instead.
+ * <p>
  * @see OnBackInvokedDispatcher#registerOnBackInvokedCallback(int, OnBackInvokedCallback)
  * registerOnBackInvokedCallback(priority, OnBackInvokedCallback)
  * to specify callback priority.
@@ -42,35 +46,8 @@
 @SuppressWarnings("deprecation")
 public interface OnBackInvokedCallback {
     /**
-     * Called when a back gesture has been started, or back button has been pressed down.
-     *
-     * @param backEvent The {@link BackEvent} containing information about the touch or
-     *                  button press.
-     *
-     * @hide
-     */
-    default void onBackStarted(@NonNull BackEvent backEvent) {}
-
-    /**
-     * Called when a back gesture has been progressed.
-     *
-     * @param backEvent The {@link BackEvent} containing information about the latest touch point
-     *                  and the progress that the back animation should seek to.
-     *
-     * @hide
-     */
-    default void onBackProgressed(@NonNull BackEvent backEvent) {}
-
-    /**
      * Called when a back gesture has been completed and committed, or back button pressed
      * has been released and committed.
      */
     void onBackInvoked();
-
-    /**
-     * Called when a back gesture or button press has been cancelled.
-     *
-     * @hide
-     */
-    default void onBackCancelled() {}
 }
diff --git a/core/java/android/window/SnapshotDrawerUtils.java b/core/java/android/window/SnapshotDrawerUtils.java
new file mode 100644
index 0000000..1a58fd5
--- /dev/null
+++ b/core/java/android/window/SnapshotDrawerUtils.java
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.window;
+
+import static android.graphics.Color.WHITE;
+import static android.graphics.Color.alpha;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
+import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
+import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
+import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
+
+import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
+import static com.android.internal.policy.DecorView.getNavigationBarRect;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityThread;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.GraphicBuffer;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.hardware.HardwareBuffer;
+import android.os.IBinder;
+import android.util.Log;
+import android.view.InsetsState;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+import android.view.ViewGroup;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.policy.DecorView;
+
+/**
+ * Utils class to help draw a snapshot on a surface.
+ * @hide
+ */
+public class SnapshotDrawerUtils {
+    private static final String TAG = "SnapshotDrawerUtils";
+
+    /**
+     * When creating the starting window, we use the exact same layout flags such that we end up
+     * with a window with the exact same dimensions etc. However, these flags are not used in layout
+     * and might cause other side effects so we exclude them.
+     */
+    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
+            | FLAG_NOT_TOUCHABLE
+            | FLAG_NOT_TOUCH_MODAL
+            | FLAG_ALT_FOCUSABLE_IM
+            | FLAG_NOT_FOCUSABLE
+            | FLAG_HARDWARE_ACCELERATED
+            | FLAG_IGNORE_CHEEK_PRESSES
+            | FLAG_LOCAL_FOCUS_MODE
+            | FLAG_SLIPPERY
+            | FLAG_WATCH_OUTSIDE_TOUCH
+            | FLAG_SPLIT_TOUCH
+            | FLAG_SCALED
+            | FLAG_SECURE;
+
+    private static final RectF sTmpSnapshotSize = new RectF();
+    private static final RectF sTmpDstFrame = new RectF();
+
+    private static final Matrix sSnapshotMatrix = new Matrix();
+    private static final float[] sTmpFloat9 = new float[9];
+    private static final Paint sBackgroundPaint = new Paint();
+
+    /**
+     * The internal object to hold the surface and drawing on it.
+     */
+    @VisibleForTesting
+    public static class SnapshotSurface {
+        private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+        private final SurfaceControl mRootSurface;
+        private final TaskSnapshot mSnapshot;
+        private final CharSequence mTitle;
+
+        private SystemBarBackgroundPainter mSystemBarBackgroundPainter;
+        private final Rect mTaskBounds;
+        private final Rect mFrame = new Rect();
+        private final Rect mSystemBarInsets = new Rect();
+        private boolean mSizeMismatch;
+
+        public SnapshotSurface(SurfaceControl rootSurface, TaskSnapshot snapshot,
+                CharSequence title,
+                Rect taskBounds) {
+            mRootSurface = rootSurface;
+            mSnapshot = snapshot;
+            mTitle = title;
+            mTaskBounds = taskBounds;
+        }
+
+        /**
+         * Initiate system bar painter to draw the system bar background.
+         */
+        void initiateSystemBarPainter(int windowFlags, int windowPrivateFlags,
+                int appearance, ActivityManager.TaskDescription taskDescription,
+                @WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+            mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
+                    windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes);
+            int backgroundColor = taskDescription.getBackgroundColor();
+            sBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
+        }
+
+        /**
+         * Set frame size.
+         */
+        void setFrames(Rect frame, Rect systemBarInsets) {
+            mFrame.set(frame);
+            mSystemBarInsets.set(systemBarInsets);
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            mSizeMismatch = (mFrame.width() != snapshot.getWidth()
+                    || mFrame.height() != snapshot.getHeight());
+            mSystemBarBackgroundPainter.setInsets(systemBarInsets);
+        }
+
+        private void drawSnapshot(boolean releaseAfterDraw) {
+            Log.v(TAG, "Drawing snapshot surface sizeMismatch=" + mSizeMismatch);
+            if (mSizeMismatch) {
+                // The dimensions of the buffer and the window don't match, so attaching the buffer
+                // will fail. Better create a child window with the exact dimensions and fill the
+                // parent window with the background color!
+                drawSizeMismatchSnapshot();
+            } else {
+                drawSizeMatchSnapshot();
+            }
+
+            // In case window manager leaks us, make sure we don't retain the snapshot.
+            if (mSnapshot.getHardwareBuffer() != null) {
+                mSnapshot.getHardwareBuffer().close();
+            }
+            if (releaseAfterDraw) {
+                mRootSurface.release();
+            }
+        }
+
+        private void drawSizeMatchSnapshot() {
+            mTransaction.setBuffer(mRootSurface, mSnapshot.getHardwareBuffer())
+                    .setColorSpace(mRootSurface, mSnapshot.getColorSpace())
+                    .apply();
+        }
+
+        private void drawSizeMismatchSnapshot() {
+            final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
+            final SurfaceSession session = new SurfaceSession();
+
+            // We consider nearly matched dimensions as there can be rounding errors and the user
+            // won't notice very minute differences from scaling one dimension more than the other
+            final boolean aspectRatioMismatch = !isAspectRatioMatch(mFrame, mSnapshot);
+
+            // Keep a reference to it such that it doesn't get destroyed when finalized.
+            SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session)
+                    .setName(mTitle + " - task-snapshot-surface")
+                    .setBLASTLayer()
+                    .setFormat(buffer.getFormat())
+                    .setParent(mRootSurface)
+                    .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
+                    .build();
+
+            final Rect frame;
+            // We can just show the surface here as it will still be hidden as the parent is
+            // still hidden.
+            mTransaction.show(childSurfaceControl);
+            if (aspectRatioMismatch) {
+                // Clip off ugly navigation bar.
+                final Rect crop = calculateSnapshotCrop();
+                frame = calculateSnapshotFrame(crop);
+                mTransaction.setWindowCrop(childSurfaceControl, crop);
+                mTransaction.setPosition(childSurfaceControl, frame.left, frame.top);
+                sTmpSnapshotSize.set(crop);
+                sTmpDstFrame.set(frame);
+            } else {
+                frame = null;
+                sTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
+                sTmpDstFrame.set(mFrame);
+                sTmpDstFrame.offsetTo(0, 0);
+            }
+
+            // Scale the mismatch dimensions to fill the task bounds
+            sSnapshotMatrix.setRectToRect(sTmpSnapshotSize, sTmpDstFrame, Matrix.ScaleToFit.FILL);
+            mTransaction.setMatrix(childSurfaceControl, sSnapshotMatrix, sTmpFloat9);
+            mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace());
+            mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer());
+
+            if (aspectRatioMismatch) {
+                GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(),
+                        PixelFormat.RGBA_8888,
+                        GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
+                                | GraphicBuffer.USAGE_SW_WRITE_RARELY);
+                // TODO: Support this on HardwareBuffer
+                final Canvas c = background.lockCanvas();
+                drawBackgroundAndBars(c, frame);
+                background.unlockCanvasAndPost(c);
+                mTransaction.setBuffer(mRootSurface,
+                        HardwareBuffer.createFromGraphicBuffer(background));
+            }
+            mTransaction.apply();
+            childSurfaceControl.release();
+        }
+
+        /**
+         * Calculates the snapshot crop in snapshot coordinate space.
+         *
+         * @return crop rect in snapshot coordinate space.
+         */
+        Rect calculateSnapshotCrop() {
+            final Rect rect = new Rect();
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
+            final Rect insets = mSnapshot.getContentInsets();
+
+            final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+            final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+            // Let's remove all system decorations except the status bar, but only if the task is at
+            // the very top of the screen.
+            final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
+            rect.inset((int) (insets.left * scaleX),
+                    isTop ? 0 : (int) (insets.top * scaleY),
+                    (int) (insets.right * scaleX),
+                    (int) (insets.bottom * scaleY));
+            return rect;
+        }
+
+        /**
+         * Calculates the snapshot frame in window coordinate space from crop.
+         *
+         * @param crop rect that is in snapshot coordinate space.
+         */
+        Rect calculateSnapshotFrame(Rect crop) {
+            final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
+            final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
+            final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
+
+            // Rescale the frame from snapshot to window coordinate space
+            final Rect frame = new Rect(0, 0,
+                    (int) (crop.width() / scaleX + 0.5f),
+                    (int) (crop.height() / scaleY + 0.5f)
+            );
+
+            // However, we also need to make space for the navigation bar on the left side.
+            frame.offset(mSystemBarInsets.left, 0);
+            return frame;
+        }
+
+        /**
+         * Draw status bar and navigation bar background.
+         */
+        void drawBackgroundAndBars(Canvas c, Rect frame) {
+            final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
+            final boolean fillHorizontally = c.getWidth() > frame.right;
+            final boolean fillVertically = c.getHeight() > frame.bottom;
+            if (fillHorizontally) {
+                c.drawRect(frame.right, alpha(mSystemBarBackgroundPainter.mStatusBarColor) == 0xFF
+                        ? statusBarHeight : 0, c.getWidth(), fillVertically
+                        ? frame.bottom : c.getHeight(), sBackgroundPaint);
+            }
+            if (fillVertically) {
+                c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), sBackgroundPaint);
+            }
+            mSystemBarBackgroundPainter.drawDecors(c, frame);
+        }
+
+        /**
+         * Ask system bar background painter to draw status bar background.
+         *
+         */
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
+                    mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
+        }
+
+        /**
+         * Ask system bar background painter to draw navigation bar background.
+         *
+         */
+        void drawNavigationBarBackground(Canvas c) {
+            mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
+        }
+    }
+
+    /**
+     * @return true if the aspect ratio match between a frame and a snapshot buffer.
+     */
+    public static boolean isAspectRatioMatch(Rect frame, TaskSnapshot snapshot) {
+        if (frame.isEmpty()) {
+            return false;
+        }
+        final HardwareBuffer buffer = snapshot.getHardwareBuffer();
+        return Math.abs(
+                ((float) buffer.getWidth() / buffer.getHeight())
+                        - ((float) frame.width() / frame.height())) <= 0.01f;
+    }
+
+    /**
+     * Help method to draw the snapshot on a surface.
+     */
+    public static void drawSnapshotOnSurface(StartingWindowInfo info, WindowManager.LayoutParams lp,
+            SurfaceControl rootSurface, TaskSnapshot snapshot,
+            Rect configBounds, Rect windowBounds, InsetsState topWindowInsetsState,
+            boolean releaseAfterDraw) {
+        if (windowBounds.isEmpty()) {
+            Log.e(TAG, "Unable to draw snapshot on an empty windowBounds");
+            return;
+        }
+        final SnapshotSurface drawSurface = new SnapshotSurface(
+                rootSurface, snapshot, lp.getTitle(), configBounds);
+
+        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+        final ActivityManager.RunningTaskInfo runningTaskInfo = info.taskInfo;
+        final ActivityManager.TaskDescription taskDescription;
+        if (runningTaskInfo.taskDescription != null) {
+            taskDescription = runningTaskInfo.taskDescription;
+        } else {
+            taskDescription = new ActivityManager.TaskDescription();
+            taskDescription.setBackgroundColor(WHITE);
+        }
+        drawSurface.initiateSystemBarPainter(lp.flags, lp.privateFlags,
+                attrs.insetsFlags.appearance, taskDescription, info.requestedVisibleTypes);
+        final Rect systemBarInsets = getSystemBarInsets(windowBounds, topWindowInsetsState);
+        drawSurface.setFrames(windowBounds, systemBarInsets);
+        drawSurface.drawSnapshot(releaseAfterDraw);
+    }
+
+    /**
+     * Help method to create a layout parameters for a window.
+     */
+    public static WindowManager.LayoutParams createLayoutParameters(StartingWindowInfo info,
+            CharSequence title, @WindowManager.LayoutParams.WindowType int windowType,
+            int pixelFormat, IBinder token) {
+        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
+        final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
+        final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
+        if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
+            Log.w(TAG, "unable to create taskSnapshot surface ");
+            return null;
+        }
+        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
+
+        final int appearance = attrs.insetsFlags.appearance;
+        final int windowFlags = attrs.flags;
+        final int windowPrivateFlags = attrs.privateFlags;
+
+        layoutParams.packageName = mainWindowParams.packageName;
+        layoutParams.windowAnimations = mainWindowParams.windowAnimations;
+        layoutParams.dimAmount = mainWindowParams.dimAmount;
+        layoutParams.type = windowType;
+        layoutParams.format = pixelFormat;
+        layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
+                | FLAG_NOT_FOCUSABLE
+                | FLAG_NOT_TOUCHABLE;
+        // Setting as trusted overlay to let touches pass through. This is safe because this
+        // window is controlled by the system.
+        layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
+                | PRIVATE_FLAG_TRUSTED_OVERLAY | PRIVATE_FLAG_USE_BLAST;
+        layoutParams.token = token;
+        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        layoutParams.insetsFlags.appearance = appearance;
+        layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
+        layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
+        layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+        layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+        layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
+        layoutParams.setTitle(title);
+        return layoutParams;
+    }
+
+    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
+        return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
+                false /* ignoreVisibility */).toRect();
+    }
+
+    /**
+     * Helper class to draw the background of the system bars in regions the task snapshot isn't
+     * filling the window.
+     */
+    public static class SystemBarBackgroundPainter {
+        private final Paint mStatusBarPaint = new Paint();
+        private final Paint mNavigationBarPaint = new Paint();
+        private final int mStatusBarColor;
+        private final int mNavigationBarColor;
+        private final int mWindowFlags;
+        private final int mWindowPrivateFlags;
+        private final float mScale;
+        private final @WindowInsets.Type.InsetsType int mRequestedVisibleTypes;
+        private final Rect mSystemBarInsets = new Rect();
+
+        public SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
+                ActivityManager.TaskDescription taskDescription, float scale,
+                @WindowInsets.Type.InsetsType int requestedVisibleTypes) {
+            mWindowFlags = windowFlags;
+            mWindowPrivateFlags = windowPrivateFlags;
+            mScale = scale;
+            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
+            final int semiTransparent = context.getColor(
+                    R.color.system_bar_background_semi_transparent);
+            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
+                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
+                    APPEARANCE_LIGHT_STATUS_BARS,
+                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
+            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
+                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
+                    taskDescription.getNavigationBarColor(), appearance,
+                    APPEARANCE_LIGHT_NAVIGATION_BARS,
+                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
+                            && context.getResources().getBoolean(
+                            R.bool.config_navBarNeedsScrim));
+            mStatusBarPaint.setColor(mStatusBarColor);
+            mNavigationBarPaint.setColor(mNavigationBarColor);
+            mRequestedVisibleTypes = requestedVisibleTypes;
+        }
+
+        /**
+         * Set system bar insets.
+         */
+        public void setInsets(Rect systemBarInsets) {
+            mSystemBarInsets.set(systemBarInsets);
+        }
+
+        int getStatusBarColorViewHeight() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags,
+                    forceBarBackground)) {
+                return (int) (mSystemBarInsets.top * mScale);
+            } else {
+                return 0;
+            }
+        }
+
+        private boolean isNavigationBarColorViewVisible() {
+            final boolean forceBarBackground =
+                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
+            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
+                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags,
+                    forceBarBackground);
+        }
+
+        /**
+         * Draw bar colors to a canvas.
+         */
+        public void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
+            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
+            drawNavigationBarBackground(c);
+        }
+
+        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
+                int statusBarHeight) {
+            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
+                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
+                final int rightInset = (int) (mSystemBarInsets.right * mScale);
+                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
+                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight,
+                        mStatusBarPaint);
+            }
+        }
+
+        void drawNavigationBarBackground(Canvas c) {
+            final Rect navigationBarRect = new Rect();
+            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
+                    mScale);
+            final boolean visible = isNavigationBarColorViewVisible();
+            if (visible && Color.alpha(mNavigationBarColor) != 0
+                    && !navigationBarRect.isEmpty()) {
+                c.drawRect(navigationBarRect, mNavigationBarPaint);
+            }
+        }
+    }
+}
diff --git a/core/java/android/window/StartingWindowRemovalInfo.java b/core/java/android/window/StartingWindowRemovalInfo.java
index 573db0d..384dacf 100644
--- a/core/java/android/window/StartingWindowRemovalInfo.java
+++ b/core/java/android/window/StartingWindowRemovalInfo.java
@@ -61,6 +61,12 @@
      */
     public boolean deferRemoveForIme;
 
+    /**
+     * The rounded corner radius
+     * @hide
+     */
+    public float roundedCornerRadius;
+
     public StartingWindowRemovalInfo() {
 
     }
@@ -80,6 +86,7 @@
         mainFrame = source.readTypedObject(Rect.CREATOR);
         playRevealAnimation = source.readBoolean();
         deferRemoveForIme = source.readBoolean();
+        roundedCornerRadius = source.readFloat();
     }
 
     @Override
@@ -89,6 +96,7 @@
         dest.writeTypedObject(mainFrame, flags);
         dest.writeBoolean(playRevealAnimation);
         dest.writeBoolean(deferRemoveForIme);
+        dest.writeFloat(roundedCornerRadius);
     }
 
     @Override
@@ -96,6 +104,7 @@
         return "StartingWindowRemovalInfo{taskId=" + taskId
                 + " frame=" + mainFrame
                 + " playRevealAnimation=" + playRevealAnimation
+                + " roundedCornerRadius=" + roundedCornerRadius
                 + " deferRemoveForIme=" + deferRemoveForIme + "}";
     }
 
diff --git a/core/java/android/window/TransitionInfo.java b/core/java/android/window/TransitionInfo.java
index c2da638..a35e13e 100644
--- a/core/java/android/window/TransitionInfo.java
+++ b/core/java/android/window/TransitionInfo.java
@@ -421,6 +421,53 @@
         return false;
     }
 
+    /**
+     * Releases temporary-for-animation surfaces referenced by this to potentially free up memory.
+     * This includes root-leash and snapshots.
+     */
+    public void releaseAnimSurfaces() {
+        for (int i = mChanges.size() - 1; i >= 0; --i) {
+            final Change c = mChanges.get(i);
+            if (c.mSnapshot != null) {
+                c.mSnapshot.release();
+                c.mSnapshot = null;
+            }
+        }
+        if (mRootLeash != null) {
+            mRootLeash.release();
+        }
+    }
+
+    /**
+     * Releases ALL the surfaces referenced by this to potentially free up memory. Do NOT use this
+     * if the surface-controls get stored and used elsewhere in the process. To just release
+     * temporary-for-animation surfaces, use {@link #releaseAnimSurfaces}.
+     */
+    public void releaseAllSurfaces() {
+        releaseAnimSurfaces();
+        for (int i = mChanges.size() - 1; i >= 0; --i) {
+            mChanges.get(i).getLeash().release();
+        }
+    }
+
+    /**
+     * Makes a copy of this as if it were parcel'd and unparcel'd. This implies that surfacecontrol
+     * refcounts are incremented which allows the "remote" receiver to release them without breaking
+     * the caller's references. Use this only if you need to "send" this to a local function which
+     * assumes it is being called from a remote caller.
+     */
+    public TransitionInfo localRemoteCopy() {
+        final TransitionInfo out = new TransitionInfo(mType, mFlags);
+        for (int i = 0; i < mChanges.size(); ++i) {
+            out.mChanges.add(mChanges.get(i).localRemoteCopy());
+        }
+        out.mRootLeash = mRootLeash != null ? new SurfaceControl(mRootLeash, "localRemote") : null;
+        // Doesn't have any native stuff, so no need for actual copy
+        out.mOptions = mOptions;
+        out.mRootOffset.set(mRootOffset);
+        return out;
+    }
+
     /** Represents the change a WindowContainer undergoes during a transition */
     public static final class Change implements Parcelable {
         private final WindowContainerToken mContainer;
@@ -473,6 +520,27 @@
             mSnapshotLuma = in.readFloat();
         }
 
+        private Change localRemoteCopy() {
+            final Change out = new Change(mContainer, new SurfaceControl(mLeash, "localRemote"));
+            out.mParent = mParent;
+            out.mLastParent = mLastParent;
+            out.mMode = mMode;
+            out.mFlags = mFlags;
+            out.mStartAbsBounds.set(mStartAbsBounds);
+            out.mEndAbsBounds.set(mEndAbsBounds);
+            out.mEndRelOffset.set(mEndRelOffset);
+            out.mTaskInfo = mTaskInfo;
+            out.mAllowEnterPip = mAllowEnterPip;
+            out.mStartRotation = mStartRotation;
+            out.mEndRotation = mEndRotation;
+            out.mEndFixedRotation = mEndFixedRotation;
+            out.mRotationAnimation = mRotationAnimation;
+            out.mBackgroundColor = mBackgroundColor;
+            out.mSnapshot = mSnapshot != null ? new SurfaceControl(mSnapshot, "localRemote") : null;
+            out.mSnapshotLuma = mSnapshotLuma;
+            return out;
+        }
+
         /** Sets the parent of this change's container. The parent must be a participant or null. */
         public void setParent(@Nullable WindowContainerToken parent) {
             mParent = parent;
diff --git a/core/java/android/window/WindowContainerToken.java b/core/java/android/window/WindowContainerToken.java
index 22b90b2..b914cb0 100644
--- a/core/java/android/window/WindowContainerToken.java
+++ b/core/java/android/window/WindowContainerToken.java
@@ -48,7 +48,6 @@
     }
 
     @Override
-    /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeStrongBinder(mRealToken.asBinder());
     }
@@ -68,7 +67,6 @@
             };
 
     @Override
-    /** @hide */
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 1063532..5793674 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -827,6 +827,26 @@
     }
 
     /**
+     * Sets/removes the reparent leaf task flag for this {@code windowContainer}.
+     * When this is set, the server side will try to reparent the leaf task to task display area
+     * if there is an existing activity in history during the activity launch. This operation only
+     * support on the organized root task.
+     * @hide
+     */
+    @NonNull
+    public WindowContainerTransaction setReparentLeafTaskIfRelaunch(
+            @NonNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch) {
+        final HierarchyOp hierarchyOp =
+                new HierarchyOp.Builder(
+                        HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH)
+                        .setContainer(windowContainer.asBinder())
+                        .setReparentLeafTaskIfRelaunch(reparentLeafTaskIfRelaunch)
+                        .build();
+        mHierarchyOps.add(hierarchyOp);
+        return this;
+    }
+
+    /**
      * Merges another WCT into this one.
      * @param transfer When true, this will transfer everything from other potentially leaving
      *                 other in an unusable state. When false, other is left alone, but
@@ -905,7 +925,6 @@
     }
 
     @Override
-    /** @hide */
     public void writeToParcel(@NonNull Parcel dest, int flags) {
         dest.writeMap(mChanges);
         dest.writeTypedList(mHierarchyOps);
@@ -914,7 +933,6 @@
     }
 
     @Override
-    /** @hide */
     public int describeContents() {
         return 0;
     }
@@ -1242,6 +1260,7 @@
         public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21;
         public static final int HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 22;
         public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 23;
+        public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 24;
 
         // The following key(s) are for use with mLaunchOptions:
         // When launching a task (eg. from recents), this is the taskId to be launched.
@@ -1294,6 +1313,8 @@
 
         private boolean mAlwaysOnTop;
 
+        private boolean mReparentLeafTaskIfRelaunch;
+
         public static HierarchyOp createForReparent(
                 @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) {
             return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT)
@@ -1406,6 +1427,7 @@
             mPendingIntent = copy.mPendingIntent;
             mShortcutInfo = copy.mShortcutInfo;
             mAlwaysOnTop = copy.mAlwaysOnTop;
+            mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch;
         }
 
         protected HierarchyOp(Parcel in) {
@@ -1428,6 +1450,7 @@
             mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
             mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR);
             mAlwaysOnTop = in.readBoolean();
+            mReparentLeafTaskIfRelaunch = in.readBoolean();
         }
 
         public int getType() {
@@ -1502,6 +1525,10 @@
             return mAlwaysOnTop;
         }
 
+        public boolean isReparentLeafTaskIfRelaunch() {
+            return mReparentLeafTaskIfRelaunch;
+        }
+
         @Nullable
         public TaskFragmentCreationParams getTaskFragmentCreationOptions() {
             return mTaskFragmentCreationOptions;
@@ -1582,6 +1609,9 @@
                             + mReparent + "}";
                 case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS:
                     return "{ClearAdjacentRoot: container=" + mContainer + "}";
+                case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH:
+                    return "{setReparentLeafTaskIfRelaunch: container= " + mContainer
+                            + " reparentLeafTaskIfRelaunch= " + mReparentLeafTaskIfRelaunch + "}";
                 default:
                     return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent
                             + " mToTop=" + mToTop
@@ -1612,6 +1642,7 @@
             dest.writeTypedObject(mPendingIntent, flags);
             dest.writeTypedObject(mShortcutInfo, flags);
             dest.writeBoolean(mAlwaysOnTop);
+            dest.writeBoolean(mReparentLeafTaskIfRelaunch);
         }
 
         @Override
@@ -1672,6 +1703,8 @@
 
             private boolean mAlwaysOnTop;
 
+            private boolean mReparentLeafTaskIfRelaunch;
+
             Builder(int type) {
                 mType = type;
             }
@@ -1742,6 +1775,11 @@
                 return this;
             }
 
+            Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
+                mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
+                return this;
+            }
+
             Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) {
                 mShortcutInfo = shortcutInfo;
                 return this;
@@ -1767,6 +1805,7 @@
                 hierarchyOp.mAlwaysOnTop = mAlwaysOnTop;
                 hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions;
                 hierarchyOp.mShortcutInfo = mShortcutInfo;
+                hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch;
 
                 return hierarchyOp;
             }
diff --git a/core/java/android/window/WindowOnBackInvokedDispatcher.java b/core/java/android/window/WindowOnBackInvokedDispatcher.java
index fda39c1..dd9483a 100644
--- a/core/java/android/window/WindowOnBackInvokedDispatcher.java
+++ b/core/java/android/window/WindowOnBackInvokedDispatcher.java
@@ -229,19 +229,21 @@
         }
 
         @Override
-        public void onBackStarted(BackEvent backEvent) {
+        public void onBackStarted(BackMotionEvent backEvent) {
             Handler.getMain().post(() -> {
                 final OnBackAnimationCallback callback = getBackAnimationCallback();
                 if (callback != null) {
                     mProgressAnimator.onBackStarted(backEvent, event ->
                             callback.onBackProgressed(event));
-                    callback.onBackStarted(backEvent);
+                    callback.onBackStarted(new BackEvent(
+                            backEvent.getTouchX(), backEvent.getTouchY(),
+                            backEvent.getProgress(), backEvent.getSwipeEdge()));
                 }
             });
         }
 
         @Override
-        public void onBackProgressed(BackEvent backEvent) {
+        public void onBackProgressed(BackMotionEvent backEvent) {
             Handler.getMain().post(() -> {
                 final OnBackAnimationCallback callback = getBackAnimationCallback();
                 if (callback != null) {
diff --git a/core/java/android/window/WindowProviderService.java b/core/java/android/window/WindowProviderService.java
index fdc3e5a..f2ae973 100644
--- a/core/java/android/window/WindowProviderService.java
+++ b/core/java/android/window/WindowProviderService.java
@@ -146,7 +146,7 @@
 
     @SuppressLint("OnNameExpected")
     @Override
-    public void onConfigurationChanged(@Nullable Configuration configuration) {
+    public void onConfigurationChanged(@NonNull Configuration configuration) {
         // This is only called from WindowTokenClient.
         mCallbacksController.dispatchConfigurationChanged(configuration);
     }
diff --git a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
index fc52620..2316738 100644
--- a/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/AbstractMultiProfilePagerAdapter.java
@@ -17,18 +17,15 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
 import android.app.AppGlobals;
-import android.app.admin.DevicePolicyEventLogger;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.IPackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.AsyncTask;
 import android.os.Trace;
 import android.os.UserHandle;
-import android.os.UserManager;
-import android.stats.devicepolicy.DevicePolicyEnums;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.Button;
@@ -60,73 +57,31 @@
     private final Context mContext;
     private int mCurrentPage;
     private OnProfileSelectedListener mOnProfileSelectedListener;
-    private OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
     private Set<Integer> mLoadedPages;
-    private final UserHandle mPersonalProfileUserHandle;
+    private final EmptyStateProvider mEmptyStateProvider;
     private final UserHandle mWorkProfileUserHandle;
-    private Injector mInjector;
-    private boolean mIsWaitingToEnableWorkProfile;
+    private final QuietModeManager mQuietModeManager;
 
     AbstractMultiProfilePagerAdapter(Context context, int currentPage,
-            UserHandle personalProfileUserHandle,
+            EmptyStateProvider emptyStateProvider,
+            QuietModeManager quietModeManager,
             UserHandle workProfileUserHandle) {
         mContext = Objects.requireNonNull(context);
         mCurrentPage = currentPage;
         mLoadedPages = new HashSet<>();
-        mPersonalProfileUserHandle = personalProfileUserHandle;
         mWorkProfileUserHandle = workProfileUserHandle;
-        UserManager userManager = context.getSystemService(UserManager.class);
-        mInjector = new Injector() {
-            @Override
-            public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
-                    int targetUserId) {
-                return AbstractMultiProfilePagerAdapter.this
-                        .hasCrossProfileIntents(intents, sourceUserId, targetUserId);
-            }
-
-            @Override
-            public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
-                return userManager.isQuietModeEnabled(workProfileUserHandle);
-            }
-
-            @Override
-            public void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle) {
-                AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
-                    userManager.requestQuietModeEnabled(enabled, workProfileUserHandle);
-                });
-                mIsWaitingToEnableWorkProfile = true;
-            }
-        };
+        mEmptyStateProvider = emptyStateProvider;
+        mQuietModeManager = quietModeManager;
     }
 
-    protected void markWorkProfileEnabledBroadcastReceived() {
-        mIsWaitingToEnableWorkProfile = false;
-    }
-
-    protected boolean isWaitingToEnableWorkProfile() {
-        return mIsWaitingToEnableWorkProfile;
-    }
-
-    /**
-     * Overrides the default {@link Injector} for testing purposes.
-     */
-    @VisibleForTesting
-    public void setInjector(Injector injector) {
-        mInjector = injector;
-    }
-
-    protected boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
-        return mInjector.isQuietModeEnabled(workProfileUserHandle);
+    private boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
+        return mQuietModeManager.isQuietModeEnabled(workProfileUserHandle);
     }
 
     void setOnProfileSelectedListener(OnProfileSelectedListener listener) {
         mOnProfileSelectedListener = listener;
     }
 
-    void setOnSwitchOnWorkSelectedListener(OnSwitchOnWorkSelectedListener listener) {
-        mOnSwitchOnWorkSelectedListener = listener;
-    }
-
     Context getContext() {
         return mContext;
     }
@@ -280,8 +235,6 @@
 
     abstract @Nullable ViewGroup getInactiveAdapterView();
 
-    abstract String getMetricsCategory();
-
     /**
      * Rebuilds the tab that is currently visible to the user.
      * <p>Returns {@code true} if rebuild has completed.
@@ -317,41 +270,18 @@
     }
 
     private boolean rebuildTab(ResolverListAdapter activeListAdapter, boolean doPostProcessing) {
-        if (shouldShowNoCrossProfileIntentsEmptyState(activeListAdapter)) {
+        if (shouldSkipRebuild(activeListAdapter)) {
             activeListAdapter.postListReadyRunnable(doPostProcessing, /* rebuildCompleted */ true);
             return false;
         }
         return activeListAdapter.rebuildList(doPostProcessing);
     }
 
-    private boolean shouldShowNoCrossProfileIntentsEmptyState(
-            ResolverListAdapter activeListAdapter) {
-        UserHandle listUserHandle = activeListAdapter.getUserHandle();
-        return UserHandle.myUserId() != listUserHandle.getIdentifier()
-                && allowShowNoCrossProfileIntentsEmptyState()
-                && !mInjector.hasCrossProfileIntents(activeListAdapter.getIntents(),
-                        UserHandle.myUserId(), listUserHandle.getIdentifier());
+    private boolean shouldSkipRebuild(ResolverListAdapter activeListAdapter) {
+        EmptyState emptyState = mEmptyStateProvider.getEmptyState(activeListAdapter);
+        return emptyState != null && emptyState.shouldSkipDataRebuild();
     }
 
-    boolean allowShowNoCrossProfileIntentsEmptyState() {
-        return true;
-    }
-
-    protected abstract void showWorkProfileOffEmptyState(
-            ResolverListAdapter activeListAdapter, View.OnClickListener listener);
-
-    protected abstract void showNoPersonalToWorkIntentsEmptyState(
-            ResolverListAdapter activeListAdapter);
-
-    protected abstract void showNoPersonalAppsAvailableEmptyState(
-            ResolverListAdapter activeListAdapter);
-
-    protected abstract void showNoWorkAppsAvailableEmptyState(
-            ResolverListAdapter activeListAdapter);
-
-    protected abstract void showNoWorkToPersonalIntentsEmptyState(
-            ResolverListAdapter activeListAdapter);
-
     /**
      * The empty state screens are shown according to their priority:
      * <ol>
@@ -366,103 +296,88 @@
      * anyway.
      */
     void showEmptyResolverListEmptyState(ResolverListAdapter listAdapter) {
-        if (maybeShowNoCrossProfileIntentsEmptyState(listAdapter)) {
-            return;
-        }
-        if (maybeShowWorkProfileOffEmptyState(listAdapter)) {
-            return;
-        }
-        maybeShowNoAppsAvailableEmptyState(listAdapter);
-    }
+        final EmptyState emptyState = mEmptyStateProvider.getEmptyState(listAdapter);
 
-    private boolean maybeShowNoCrossProfileIntentsEmptyState(ResolverListAdapter listAdapter) {
-        if (!shouldShowNoCrossProfileIntentsEmptyState(listAdapter)) {
-            return false;
+        if (emptyState == null) {
+            return;
         }
-        if (listAdapter.getUserHandle().equals(mPersonalProfileUserHandle)) {
-            DevicePolicyEventLogger.createEvent(
-                    DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL)
-                    .setStrings(getMetricsCategory())
-                    .write();
-            showNoWorkToPersonalIntentsEmptyState(listAdapter);
-        } else {
-            DevicePolicyEventLogger.createEvent(
-                    DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK)
-                    .setStrings(getMetricsCategory())
-                    .write();
-            showNoPersonalToWorkIntentsEmptyState(listAdapter);
+
+        emptyState.onEmptyStateShown();
+
+        View.OnClickListener clickListener = null;
+
+        if (emptyState.getButtonClickListener() != null) {
+            clickListener = v -> emptyState.getButtonClickListener().onClick(() -> {
+                ProfileDescriptor descriptor = getItem(
+                        userHandleToPageIndex(listAdapter.getUserHandle()));
+                AbstractMultiProfilePagerAdapter.this.showSpinner(descriptor.getEmptyStateView());
+            });
         }
-        return true;
+
+        showEmptyState(listAdapter, emptyState, clickListener);
     }
 
     /**
-     * Returns {@code true} if the work profile off empty state screen is shown.
+     * Class to get user id of the current process
      */
-    private boolean maybeShowWorkProfileOffEmptyState(ResolverListAdapter listAdapter) {
-        UserHandle listUserHandle = listAdapter.getUserHandle();
-        if (!listUserHandle.equals(mWorkProfileUserHandle)
-                || !mInjector.isQuietModeEnabled(mWorkProfileUserHandle)
-                || listAdapter.getCount() == 0) {
-            return false;
-        }
-        DevicePolicyEventLogger
-                .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
-                .setStrings(getMetricsCategory())
-                .write();
-        showWorkProfileOffEmptyState(listAdapter,
-                v -> {
-                    ProfileDescriptor descriptor = getItem(
-                            userHandleToPageIndex(listAdapter.getUserHandle()));
-                    showSpinner(descriptor.getEmptyStateView());
-                    if (mOnSwitchOnWorkSelectedListener != null) {
-                        mOnSwitchOnWorkSelectedListener.onSwitchOnWorkSelected();
-                    }
-                    mInjector.requestQuietModeEnabled(false, mWorkProfileUserHandle);
-                });
-        return true;
-    }
-
-    private void maybeShowNoAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
-        UserHandle listUserHandle = listAdapter.getUserHandle();
-        if (mWorkProfileUserHandle != null
-                && (UserHandle.myUserId() == listUserHandle.getIdentifier()
-                        || !hasAppsInOtherProfile(listAdapter))) {
-            DevicePolicyEventLogger.createEvent(
-                    DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_APPS_RESOLVED)
-                    .setStrings(getMetricsCategory())
-                    .setBoolean(/*isPersonalProfile*/ listUserHandle == mPersonalProfileUserHandle)
-                    .write();
-            if (listUserHandle == mPersonalProfileUserHandle) {
-                showNoPersonalAppsAvailableEmptyState(listAdapter);
-            } else {
-                showNoWorkAppsAvailableEmptyState(listAdapter);
-            }
-        } else if (mWorkProfileUserHandle == null) {
-            showConsumerUserNoAppsAvailableEmptyState(listAdapter);
+    public static class MyUserIdProvider {
+        /**
+         * @return user id of the current process
+         */
+        public int getMyUserId() {
+            return UserHandle.myUserId();
         }
     }
 
-    protected void showEmptyState(ResolverListAdapter activeListAdapter, String title,
-            String subtitle) {
-        showEmptyState(activeListAdapter, title, subtitle, /* buttonOnClick */ null);
+    /**
+     * Utility class to check if there are cross profile intents, it is in a separate class so
+     * it could be mocked in tests
+     */
+    public static class CrossProfileIntentsChecker {
+
+        private final ContentResolver mContentResolver;
+
+        public CrossProfileIntentsChecker(@NonNull ContentResolver contentResolver) {
+            mContentResolver = contentResolver;
+        }
+
+        /**
+         * Returns {@code true} if at least one of the provided {@code intents} can be forwarded
+         * from {@code source} (user id) to {@code target} (user id).
+         */
+        public boolean hasCrossProfileIntents(List<Intent> intents, @UserIdInt int source,
+                @UserIdInt int target) {
+            IPackageManager packageManager = AppGlobals.getPackageManager();
+
+            return intents.stream().anyMatch(intent ->
+                    null != IntentForwarderActivity.canForward(intent, source, target,
+                            packageManager, mContentResolver));
+        }
     }
 
-    protected void showEmptyState(ResolverListAdapter activeListAdapter,
-            String title, String subtitle, View.OnClickListener buttonOnClick) {
+    protected void showEmptyState(ResolverListAdapter activeListAdapter, EmptyState emptyState,
+            View.OnClickListener buttonOnClick) {
         ProfileDescriptor descriptor = getItem(
                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
         descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.GONE);
         ViewGroup emptyStateView = descriptor.getEmptyStateView();
-        resetViewVisibilitiesForWorkProfileEmptyState(emptyStateView);
+        resetViewVisibilitiesForEmptyState(emptyStateView);
         emptyStateView.setVisibility(View.VISIBLE);
 
         View container = emptyStateView.findViewById(R.id.resolver_empty_state_container);
         setupContainerPadding(container);
 
         TextView titleView = emptyStateView.findViewById(R.id.resolver_empty_state_title);
-        titleView.setText(title);
+        String title = emptyState.getTitle();
+        if (title != null) {
+            titleView.setVisibility(View.VISIBLE);
+            titleView.setText(title);
+        } else {
+            titleView.setVisibility(View.GONE);
+        }
 
         TextView subtitleView = emptyStateView.findViewById(R.id.resolver_empty_state_subtitle);
+        String subtitle = emptyState.getSubtitle();
         if (subtitle != null) {
             subtitleView.setVisibility(View.VISIBLE);
             subtitleView.setText(subtitle);
@@ -470,6 +385,9 @@
             subtitleView.setVisibility(View.GONE);
         }
 
+        View defaultEmptyText = emptyStateView.findViewById(R.id.empty);
+        defaultEmptyText.setVisibility(emptyState.useDefaultEmptyView() ? View.VISIBLE : View.GONE);
+
         Button button = emptyStateView.findViewById(R.id.resolver_empty_state_button);
         button.setVisibility(buttonOnClick != null ? View.VISIBLE : View.GONE);
         button.setOnClickListener(buttonOnClick);
@@ -483,22 +401,6 @@
      */
     protected void setupContainerPadding(View container) {}
 
-    private void showConsumerUserNoAppsAvailableEmptyState(ResolverListAdapter activeListAdapter) {
-        ProfileDescriptor descriptor = getItem(
-                userHandleToPageIndex(activeListAdapter.getUserHandle()));
-        descriptor.rootView.findViewById(R.id.resolver_list).setVisibility(View.GONE);
-        View emptyStateView = descriptor.getEmptyStateView();
-        resetViewVisibilitiesForConsumerUserEmptyState(emptyStateView);
-        emptyStateView.setVisibility(View.VISIBLE);
-
-        activeListAdapter.markTabLoaded();
-    }
-
-    private boolean isSpinnerShowing(View emptyStateView) {
-        return emptyStateView.findViewById(R.id.resolver_empty_state_progress).getVisibility()
-                == View.VISIBLE;
-    }
-
     private void showSpinner(View emptyStateView) {
         emptyStateView.findViewById(R.id.resolver_empty_state_title).setVisibility(View.INVISIBLE);
         emptyStateView.findViewById(R.id.resolver_empty_state_button).setVisibility(View.INVISIBLE);
@@ -506,7 +408,7 @@
         emptyStateView.findViewById(R.id.empty).setVisibility(View.GONE);
     }
 
-    private void resetViewVisibilitiesForWorkProfileEmptyState(View emptyStateView) {
+    private void resetViewVisibilitiesForEmptyState(View emptyStateView) {
         emptyStateView.findViewById(R.id.resolver_empty_state_title).setVisibility(View.VISIBLE);
         emptyStateView.findViewById(R.id.resolver_empty_state_subtitle).setVisibility(View.VISIBLE);
         emptyStateView.findViewById(R.id.resolver_empty_state_button).setVisibility(View.INVISIBLE);
@@ -514,14 +416,6 @@
         emptyStateView.findViewById(R.id.empty).setVisibility(View.GONE);
     }
 
-    private void resetViewVisibilitiesForConsumerUserEmptyState(View emptyStateView) {
-        emptyStateView.findViewById(R.id.resolver_empty_state_title).setVisibility(View.GONE);
-        emptyStateView.findViewById(R.id.resolver_empty_state_subtitle).setVisibility(View.GONE);
-        emptyStateView.findViewById(R.id.resolver_empty_state_button).setVisibility(View.GONE);
-        emptyStateView.findViewById(R.id.resolver_empty_state_progress).setVisibility(View.GONE);
-        emptyStateView.findViewById(R.id.empty).setVisibility(View.VISIBLE);
-    }
-
     protected void showListView(ResolverListAdapter activeListAdapter) {
         ProfileDescriptor descriptor = getItem(
                 userHandleToPageIndex(activeListAdapter.getUserHandle()));
@@ -530,33 +424,6 @@
         emptyStateView.setVisibility(View.GONE);
     }
 
-    private boolean hasCrossProfileIntents(List<Intent> intents, int source, int target) {
-        IPackageManager packageManager = AppGlobals.getPackageManager();
-        ContentResolver contentResolver = mContext.getContentResolver();
-        for (Intent intent : intents) {
-            if (IntentForwarderActivity.canForward(intent, source, target, packageManager,
-                    contentResolver) != null) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) {
-        if (mWorkProfileUserHandle == null) {
-            return false;
-        }
-        List<ResolverActivity.ResolvedComponentInfo> resolversForIntent =
-                adapter.getResolversForUser(UserHandle.of(UserHandle.myUserId()));
-        for (ResolverActivity.ResolvedComponentInfo info : resolversForIntent) {
-            ResolveInfo resolveInfo = info.getResolveInfoAt(0);
-            if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     boolean shouldShowEmptyStateScreen(ResolverListAdapter listAdapter) {
         int count = listAdapter.getUnfilteredCount();
         return (count == 0 && listAdapter.getPlaceholderCount() == 0)
@@ -600,6 +467,98 @@
     }
 
     /**
+     * Returns an empty state to show for the current profile page (tab) if necessary.
+     * This could be used e.g. to show a blocker on a tab if device management policy doesn't
+     * allow to use it or there are no apps available.
+     */
+    public interface EmptyStateProvider {
+        /**
+         * When a non-null empty state is returned the corresponding profile page will show
+         * this empty state
+         * @param resolverListAdapter the current adapter
+         */
+        @Nullable
+        default EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
+            return null;
+        }
+    }
+
+    /**
+     * Empty state provider that combines multiple providers. Providers earlier in the list have
+     * priority, that is if there is a provider that returns non-null empty state then all further
+     * providers will be ignored.
+     */
+    public static class CompositeEmptyStateProvider implements EmptyStateProvider {
+
+        private final EmptyStateProvider[] mProviders;
+
+        public CompositeEmptyStateProvider(EmptyStateProvider... providers) {
+            mProviders = providers;
+        }
+
+        @Nullable
+        @Override
+        public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
+            for (EmptyStateProvider provider : mProviders) {
+                EmptyState emptyState = provider.getEmptyState(resolverListAdapter);
+                if (emptyState != null) {
+                    return emptyState;
+                }
+            }
+            return null;
+        }
+    }
+
+    /**
+     * Describes how the blocked empty state should look like for a profile tab
+     */
+    public interface EmptyState {
+        /**
+         * Title that will be shown on the empty state
+         */
+        @Nullable
+        default String getTitle() { return null; }
+
+        /**
+         * Subtitle that will be shown underneath the title on the empty state
+         */
+        @Nullable
+        default String getSubtitle()  { return null; }
+
+        /**
+         * If non-null then a button will be shown and this listener will be called
+         * when the button is clicked
+         */
+        @Nullable
+        default ClickListener getButtonClickListener()  { return null; }
+
+        /**
+         * If true then default text ('No apps can perform this action') and style for the empty
+         * state will be applied, title and subtitle will be ignored.
+         */
+        default boolean useDefaultEmptyView() { return false; }
+
+        /**
+         * Returns true if for this empty state we should skip rebuilding of the apps list
+         * for this tab.
+         */
+        default boolean shouldSkipDataRebuild() { return false; }
+
+        /**
+         * Called when empty state is shown, could be used e.g. to track analytics events
+         */
+        default void onEmptyStateShown() {}
+
+        interface ClickListener {
+            void onClick(TabControl currentTab);
+        }
+
+        interface TabControl {
+            void showSpinner();
+        }
+    }
+
+    /**
      * Listener for when the user switches on the work profile from the work tab.
      */
     interface OnSwitchOnWorkSelectedListener {
@@ -612,14 +571,7 @@
     /**
      * Describes an injector to be used for cross profile functionality. Overridable for testing.
      */
-    @VisibleForTesting
-    public interface Injector {
-        /**
-         * Returns {@code true} if at least one of the provided {@code intents} can be forwarded
-         * from {@code sourceUserId} to {@code targetUserId}.
-         */
-        boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId, int targetUserId);
-
+    public interface QuietModeManager {
         /**
          * Returns whether the given profile is in quiet mode or not.
          */
@@ -629,5 +581,15 @@
          * Enables or disables quiet mode for a managed profile.
          */
         void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle);
+
+        /**
+         * Should be called when the work profile enabled broadcast received
+         */
+        void markWorkProfileEnabledBroadcastReceived();
+
+        /**
+         * Returns true if enabling of work profile is in progress
+         */
+        boolean isWaitingToEnableWorkProfile();
     }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index d37779b..02cbd41 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -16,6 +16,14 @@
 
 package com.android.internal.app;
 
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
+import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL;
+import static android.stats.devicepolicy.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
+
 import static com.android.internal.util.LatencyTracker.ACTION_LOAD_SHARE_SHEET;
 
 import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -114,6 +122,9 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
+import com.android.internal.app.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
 import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
 import com.android.internal.app.ResolverListAdapter.ViewHolder;
 import com.android.internal.app.chooser.ChooserTargetInfo;
@@ -830,6 +841,41 @@
         return mChooserMultiProfilePagerAdapter;
     }
 
+    @Override
+    protected EmptyStateProvider createBlockerEmptyStateProvider() {
+        final boolean isSendAction = isSendAction(getTargetIntent());
+
+        final EmptyState noWorkToPersonalEmptyState =
+                new DevicePolicyBlockerEmptyState(
+                /* context= */ this,
+                /* devicePolicyStringTitleId= */ RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
+                /* defaultTitleResource= */ R.string.resolver_cross_profile_blocked,
+                /* devicePolicyStringSubtitleId= */
+                isSendAction ? RESOLVER_CANT_SHARE_WITH_PERSONAL : RESOLVER_CANT_ACCESS_PERSONAL,
+                /* defaultSubtitleResource= */
+                isSendAction ? R.string.resolver_cant_share_with_personal_apps_explanation
+                        : R.string.resolver_cant_access_personal_apps_explanation,
+                /* devicePolicyEventId= */ RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL,
+                /* devicePolicyEventCategory= */ ResolverActivity.METRICS_CATEGORY_CHOOSER);
+
+        final EmptyState noPersonalToWorkEmptyState =
+                new DevicePolicyBlockerEmptyState(
+                /* context= */ this,
+                /* devicePolicyStringTitleId= */ RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
+                /* defaultTitleResource= */ R.string.resolver_cross_profile_blocked,
+                /* devicePolicyStringSubtitleId= */
+                isSendAction ? RESOLVER_CANT_SHARE_WITH_WORK : RESOLVER_CANT_ACCESS_WORK,
+                /* defaultSubtitleResource= */
+                isSendAction ? R.string.resolver_cant_share_with_work_apps_explanation
+                        : R.string.resolver_cant_access_work_apps_explanation,
+                /* devicePolicyEventId= */ RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK,
+                /* devicePolicyEventCategory= */ ResolverActivity.METRICS_CATEGORY_CHOOSER);
+
+        return new NoCrossProfileEmptyStateProvider(getPersonalProfileUserHandle(),
+                noWorkToPersonalEmptyState, noPersonalToWorkEmptyState,
+                createCrossProfileIntentsChecker(), createMyUserIdProvider());
+    }
+
     private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForOneProfile(
             Intent[] initialIntents,
             List<ResolveInfo> rList,
@@ -844,9 +890,10 @@
         return new ChooserMultiProfilePagerAdapter(
                 /* context */ this,
                 adapter,
-                getPersonalProfileUserHandle(),
+                createEmptyStateProvider(/* workProfileUserHandle= */ null),
+                mQuietModeManager,
                 /* workProfileUserHandle= */ null,
-                isSendAction(getTargetIntent()), mMaxTargetsPerRow);
+                mMaxTargetsPerRow);
     }
 
     private ChooserMultiProfilePagerAdapter createChooserMultiProfilePagerAdapterForTwoProfiles(
@@ -872,10 +919,11 @@
                 /* context */ this,
                 personalAdapter,
                 workAdapter,
+                createEmptyStateProvider(/* workProfileUserHandle= */ getWorkProfileUserHandle()),
+                mQuietModeManager,
                 selectedProfile,
-                getPersonalProfileUserHandle(),
                 getWorkProfileUserHandle(),
-                isSendAction(getTargetIntent()), mMaxTargetsPerRow);
+                mMaxTargetsPerRow);
     }
 
     private int findSelectedProfile() {
diff --git a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
index df1130b..0509b67 100644
--- a/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ChooserMultiProfilePagerAdapter.java
@@ -16,17 +16,7 @@
 
 package com.android.internal.app;
 
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_SHARE_WITH_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PAUSED_TITLE;
-
 import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
@@ -47,37 +37,37 @@
     private static final int SINGLE_CELL_SPAN_SIZE = 1;
 
     private final ChooserProfileDescriptor[] mItems;
-    private final boolean mIsSendAction;
     private int mBottomOffset;
     private int mMaxTargetsPerRow;
 
     ChooserMultiProfilePagerAdapter(Context context,
             ChooserActivity.ChooserGridAdapter adapter,
-            UserHandle personalProfileUserHandle,
+            EmptyStateProvider emptyStateProvider,
+            QuietModeManager quietModeManager,
             UserHandle workProfileUserHandle,
-            boolean isSendAction, int maxTargetsPerRow) {
-        super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle);
+            int maxTargetsPerRow) {
+        super(context, /* currentPage */ 0, emptyStateProvider, quietModeManager,
+                workProfileUserHandle);
         mItems = new ChooserProfileDescriptor[] {
                 createProfileDescriptor(adapter)
         };
-        mIsSendAction = isSendAction;
         mMaxTargetsPerRow = maxTargetsPerRow;
     }
 
     ChooserMultiProfilePagerAdapter(Context context,
             ChooserActivity.ChooserGridAdapter personalAdapter,
             ChooserActivity.ChooserGridAdapter workAdapter,
+            EmptyStateProvider emptyStateProvider,
+            QuietModeManager quietModeManager,
             @Profile int defaultProfile,
-            UserHandle personalProfileUserHandle,
             UserHandle workProfileUserHandle,
-            boolean isSendAction, int maxTargetsPerRow) {
-        super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
-                workProfileUserHandle);
+            int maxTargetsPerRow) {
+        super(context, /* currentPage */ defaultProfile, emptyStateProvider,
+                quietModeManager, workProfileUserHandle);
         mItems = new ChooserProfileDescriptor[] {
                 createProfileDescriptor(personalAdapter),
                 createProfileDescriptor(workAdapter)
         };
-        mIsSendAction = isSendAction;
         mMaxTargetsPerRow = maxTargetsPerRow;
     }
 
@@ -192,112 +182,6 @@
         return getListViewForIndex(1 - getCurrentPage());
     }
 
-    @Override
-    String getMetricsCategory() {
-        return ResolverActivity.METRICS_CATEGORY_CHOOSER;
-    }
-
-    @Override
-    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
-            View.OnClickListener listener) {
-        showEmptyState(activeListAdapter,
-                getWorkAppPausedTitle(),
-                /* subtitle = */ null,
-                listener);
-    }
-
-    @Override
-    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
-        if (mIsSendAction) {
-            showEmptyState(activeListAdapter,
-                    getCrossProfileBlockedTitle(),
-                    getCantShareWithWorkMessage());
-        } else {
-            showEmptyState(activeListAdapter,
-                    getCrossProfileBlockedTitle(),
-                    getCantAccessWorkMessage());
-        }
-    }
-
-    @Override
-    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
-        if (mIsSendAction) {
-            showEmptyState(activeListAdapter,
-                    getCrossProfileBlockedTitle(),
-                    getCantShareWithPersonalMessage());
-        } else {
-            showEmptyState(activeListAdapter,
-                    getCrossProfileBlockedTitle(),
-                    getCantAccessPersonalMessage());
-        }
-    }
-
-    @Override
-    protected void showNoPersonalAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
-        showEmptyState(listAdapter, getNoPersonalAppsAvailableMessage(), /* subtitle= */ null);
-
-    }
-
-    @Override
-    protected void showNoWorkAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
-        showEmptyState(listAdapter, getNoWorkAppsAvailableMessage(), /* subtitle = */ null);
-    }
-
-    private String getWorkAppPausedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_WORK_PAUSED_TITLE,
-                () -> getContext().getString(R.string.resolver_turn_on_work_apps));
-    }
-
-    private String getCrossProfileBlockedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
-                () -> getContext().getString(R.string.resolver_cross_profile_blocked));
-    }
-
-    private String getCantShareWithWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_SHARE_WITH_WORK,
-                () -> getContext().getString(
-                        R.string.resolver_cant_share_with_work_apps_explanation));
-    }
-
-    private String getCantShareWithPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_SHARE_WITH_PERSONAL,
-                () -> getContext().getString(
-                        R.string.resolver_cant_share_with_personal_apps_explanation));
-    }
-
-    private String getCantAccessWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_ACCESS_WORK,
-                () -> getContext().getString(
-                        R.string.resolver_cant_access_work_apps_explanation));
-    }
-
-    private String getCantAccessPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_ACCESS_PERSONAL,
-                () -> getContext().getString(
-                        R.string.resolver_cant_access_personal_apps_explanation));
-    }
-
-    private String getNoWorkAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_NO_WORK_APPS,
-                () -> getContext().getString(
-                        R.string.resolver_no_work_apps_available));
-    }
-
-    private String getNoPersonalAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_NO_PERSONAL_APPS,
-                () -> getContext().getString(
-                        R.string.resolver_no_personal_apps_available));
-    }
-
-
     void setEmptyStateBottomOffset(int bottomOffset) {
         mBottomOffset = bottomOffset;
     }
diff --git a/core/java/com/android/internal/app/NoAppsAvailableEmptyStateProvider.java b/core/java/com/android/internal/app/NoAppsAvailableEmptyStateProvider.java
new file mode 100644
index 0000000..34249f2
--- /dev/null
+++ b/core/java/com/android/internal/app/NoAppsAvailableEmptyStateProvider.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app;
+
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.DevicePolicyEventLogger;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.stats.devicepolicy.nano.DevicePolicyEnums;
+
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+import com.android.internal.R;
+
+import java.util.List;
+
+/**
+ * Chooser/ResolverActivity empty state provider that returns empty state which is shown when
+ * there are no apps available.
+ */
+public class NoAppsAvailableEmptyStateProvider implements EmptyStateProvider {
+
+    @NonNull
+    private final Context mContext;
+    @Nullable
+    private final UserHandle mWorkProfileUserHandle;
+    @Nullable
+    private final UserHandle mPersonalProfileUserHandle;
+    @NonNull
+    private final String mMetricsCategory;
+    @NonNull
+    private final MyUserIdProvider mMyUserIdProvider;
+
+    public NoAppsAvailableEmptyStateProvider(Context context, UserHandle workProfileUserHandle,
+            UserHandle personalProfileUserHandle, String metricsCategory,
+            MyUserIdProvider myUserIdProvider) {
+        mContext = context;
+        mWorkProfileUserHandle = workProfileUserHandle;
+        mPersonalProfileUserHandle = personalProfileUserHandle;
+        mMetricsCategory = metricsCategory;
+        mMyUserIdProvider = myUserIdProvider;
+    }
+
+    @Nullable
+    @Override
+    @SuppressWarnings("ReferenceEquality")
+    public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
+        UserHandle listUserHandle = resolverListAdapter.getUserHandle();
+
+        if (mWorkProfileUserHandle != null
+                && (mMyUserIdProvider.getMyUserId() == listUserHandle.getIdentifier()
+                || !hasAppsInOtherProfile(resolverListAdapter))) {
+
+            String title;
+            if (listUserHandle == mPersonalProfileUserHandle) {
+                title = mContext.getSystemService(
+                        DevicePolicyManager.class).getResources().getString(
+                        RESOLVER_NO_PERSONAL_APPS,
+                        () -> mContext.getString(R.string.resolver_no_personal_apps_available));
+            } else {
+                title = mContext.getSystemService(
+                        DevicePolicyManager.class).getResources().getString(
+                        RESOLVER_NO_WORK_APPS,
+                        () -> mContext.getString(R.string.resolver_no_work_apps_available));
+            }
+
+            return new NoAppsAvailableEmptyState(
+                    title, mMetricsCategory,
+                    /* isPersonalProfile= */ listUserHandle == mPersonalProfileUserHandle
+            );
+        } else if (mWorkProfileUserHandle == null) {
+            // Return default empty state without tracking
+            return new DefaultEmptyState();
+        }
+
+        return null;
+    }
+
+    private boolean hasAppsInOtherProfile(ResolverListAdapter adapter) {
+        if (mWorkProfileUserHandle == null) {
+            return false;
+        }
+        List<ResolverActivity.ResolvedComponentInfo> resolversForIntent =
+                adapter.getResolversForUser(UserHandle.of(mMyUserIdProvider.getMyUserId()));
+        for (ResolverActivity.ResolvedComponentInfo info : resolversForIntent) {
+            ResolveInfo resolveInfo = info.getResolveInfoAt(0);
+            if (resolveInfo.targetUserId != UserHandle.USER_CURRENT) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static class DefaultEmptyState implements EmptyState {
+        @Override
+        public boolean useDefaultEmptyView() {
+            return true;
+        }
+    }
+
+    public static class NoAppsAvailableEmptyState implements EmptyState {
+
+        @NonNull
+        private String mTitle;
+
+        @NonNull
+        private String mMetricsCategory;
+
+        private boolean mIsPersonalProfile;
+
+        public NoAppsAvailableEmptyState(String title, String metricsCategory,
+                boolean isPersonalProfile) {
+            mTitle = title;
+            mMetricsCategory = metricsCategory;
+            mIsPersonalProfile = isPersonalProfile;
+        }
+
+        @Nullable
+        @Override
+        public String getTitle() {
+            return mTitle;
+        }
+
+        @Override
+        public void onEmptyStateShown() {
+            DevicePolicyEventLogger.createEvent(
+                            DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_APPS_RESOLVED)
+                    .setStrings(mMetricsCategory)
+                    .setBoolean(/*isPersonalProfile*/ mIsPersonalProfile)
+                    .write();
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/NoCrossProfileEmptyStateProvider.java b/core/java/com/android/internal/app/NoCrossProfileEmptyStateProvider.java
new file mode 100644
index 0000000..2e7d5bf
--- /dev/null
+++ b/core/java/com/android/internal/app/NoCrossProfileEmptyStateProvider.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StringRes;
+import android.app.admin.DevicePolicyEventLogger;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserHandle;
+
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+
+/**
+ * Empty state provider that does not allow cross profile sharing, it will return a blocker
+ * in case if the profile of the current tab is not the same as the profile of the calling app.
+ */
+public class NoCrossProfileEmptyStateProvider implements EmptyStateProvider {
+
+    private final UserHandle mPersonalProfileUserHandle;
+    private final EmptyState mNoWorkToPersonalEmptyState;
+    private final EmptyState mNoPersonalToWorkEmptyState;
+    private final CrossProfileIntentsChecker mCrossProfileIntentsChecker;
+    private final MyUserIdProvider mUserIdProvider;
+
+    public NoCrossProfileEmptyStateProvider(UserHandle personalUserHandle,
+            EmptyState noWorkToPersonalEmptyState,
+            EmptyState noPersonalToWorkEmptyState,
+            CrossProfileIntentsChecker crossProfileIntentsChecker,
+            MyUserIdProvider myUserIdProvider) {
+        mPersonalProfileUserHandle = personalUserHandle;
+        mNoWorkToPersonalEmptyState = noWorkToPersonalEmptyState;
+        mNoPersonalToWorkEmptyState = noPersonalToWorkEmptyState;
+        mCrossProfileIntentsChecker = crossProfileIntentsChecker;
+        mUserIdProvider = myUserIdProvider;
+    }
+
+    @Nullable
+    @Override
+    public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
+        boolean shouldShowBlocker =
+                mUserIdProvider.getMyUserId() != resolverListAdapter.getUserHandle().getIdentifier()
+                && !mCrossProfileIntentsChecker
+                        .hasCrossProfileIntents(resolverListAdapter.getIntents(),
+                                mUserIdProvider.getMyUserId(),
+                                resolverListAdapter.getUserHandle().getIdentifier());
+
+        if (!shouldShowBlocker) {
+            return null;
+        }
+
+        if (resolverListAdapter.getUserHandle().equals(mPersonalProfileUserHandle)) {
+            return mNoWorkToPersonalEmptyState;
+        } else {
+            return mNoPersonalToWorkEmptyState;
+        }
+    }
+
+
+    /**
+     * Empty state that gets strings from the device policy manager and tracks events into
+     * event logger of the device policy events.
+     */
+    public static class DevicePolicyBlockerEmptyState implements EmptyState {
+
+        @NonNull
+        private final Context mContext;
+        private final String mDevicePolicyStringTitleId;
+        @StringRes
+        private final int mDefaultTitleResource;
+        private final String mDevicePolicyStringSubtitleId;
+        @StringRes
+        private final int mDefaultSubtitleResource;
+        private final int mEventId;
+        @NonNull
+        private final String mEventCategory;
+
+        public DevicePolicyBlockerEmptyState(Context context, String devicePolicyStringTitleId,
+                @StringRes int defaultTitleResource, String devicePolicyStringSubtitleId,
+                @StringRes int defaultSubtitleResource,
+                int devicePolicyEventId, String devicePolicyEventCategory) {
+            mContext = context;
+            mDevicePolicyStringTitleId = devicePolicyStringTitleId;
+            mDefaultTitleResource = defaultTitleResource;
+            mDevicePolicyStringSubtitleId = devicePolicyStringSubtitleId;
+            mDefaultSubtitleResource = defaultSubtitleResource;
+            mEventId = devicePolicyEventId;
+            mEventCategory = devicePolicyEventCategory;
+        }
+
+        @Nullable
+        @Override
+        public String getTitle() {
+            return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(
+                    mDevicePolicyStringTitleId,
+                    () -> mContext.getString(mDefaultTitleResource));
+        }
+
+        @Nullable
+        @Override
+        public String getSubtitle() {
+            return mContext.getSystemService(DevicePolicyManager.class).getResources().getString(
+                    mDevicePolicyStringSubtitleId,
+                    () -> mContext.getString(mDefaultSubtitleResource));
+        }
+
+        @Override
+        public void onEmptyStateShown() {
+            DevicePolicyEventLogger.createEvent(mEventId)
+                    .setStrings(mEventCategory)
+                    .write();
+        }
+
+        @Override
+        public boolean shouldSkipDataRebuild() {
+            return true;
+        }
+    }
+}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index a237e98..0706ee5 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -19,6 +19,9 @@
 import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
 import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_PERSONAL;
 import static android.app.admin.DevicePolicyResources.Strings.Core.FORWARD_INTENT_TO_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB;
 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_PERSONAL_TAB_ACCESSIBILITY;
 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PROFILE_NOT_SUPPORTED;
@@ -26,6 +29,8 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_TAB_ACCESSIBILITY;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.PermissionChecker.PID_UNKNOWN;
+import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL;
+import static android.stats.devicepolicy.nano.DevicePolicyEnums.RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK;
 import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
 
 import android.annotation.Nullable;
@@ -57,6 +62,7 @@
 import android.graphics.Insets;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.AsyncTask;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.PatternMatcher;
@@ -93,7 +99,14 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CompositeEmptyStateProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
 import com.android.internal.app.AbstractMultiProfilePagerAdapter.Profile;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.QuietModeManager;
+import com.android.internal.app.NoCrossProfileEmptyStateProvider.DevicePolicyBlockerEmptyState;
 import com.android.internal.app.chooser.ChooserTargetInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
 import com.android.internal.app.chooser.TargetInfo;
@@ -186,6 +199,8 @@
     @VisibleForTesting
     protected AbstractMultiProfilePagerAdapter mMultiProfilePagerAdapter;
 
+    protected QuietModeManager mQuietModeManager;
+
     // Intent extra for connected audio devices
     public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device";
 
@@ -217,6 +232,9 @@
 
     private UserHandle mWorkProfileUserHandle;
 
+    @Nullable
+    private OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
+
     protected final LatencyTracker mLatencyTracker = getLatencyTracker();
 
     private LatencyTracker getLatencyTracker() {
@@ -375,6 +393,8 @@
         setTheme(appliedThemeResId());
         super.onCreate(savedInstanceState);
 
+        mQuietModeManager = createQuietModeManager();
+
         // Determine whether we should show that intent is forwarded
         // from managed profile to owner or other way around.
         setProfileSwitchMessage(intent.getContentUserHint());
@@ -475,6 +495,111 @@
         return resolverMultiProfilePagerAdapter;
     }
 
+    @VisibleForTesting
+    protected MyUserIdProvider createMyUserIdProvider() {
+        return new MyUserIdProvider();
+    }
+
+    @VisibleForTesting
+    protected CrossProfileIntentsChecker createCrossProfileIntentsChecker() {
+        return new CrossProfileIntentsChecker(getContentResolver());
+    }
+
+    @VisibleForTesting
+    protected QuietModeManager createQuietModeManager() {
+        UserManager userManager = getSystemService(UserManager.class);
+        return new QuietModeManager() {
+
+            private boolean mIsWaitingToEnableWorkProfile = false;
+
+            @Override
+            public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
+                return userManager.isQuietModeEnabled(workProfileUserHandle);
+            }
+
+            @Override
+            public void requestQuietModeEnabled(boolean enabled, UserHandle workProfileUserHandle) {
+                AsyncTask.THREAD_POOL_EXECUTOR.execute(() -> {
+                    userManager.requestQuietModeEnabled(enabled, workProfileUserHandle);
+                });
+                mIsWaitingToEnableWorkProfile = true;
+            }
+
+            @Override
+            public void markWorkProfileEnabledBroadcastReceived() {
+                mIsWaitingToEnableWorkProfile = false;
+            }
+
+            @Override
+            public boolean isWaitingToEnableWorkProfile() {
+                return mIsWaitingToEnableWorkProfile;
+            }
+        };
+    }
+
+    protected EmptyStateProvider createBlockerEmptyStateProvider() {
+        final boolean shouldShowNoCrossProfileIntentsEmptyState = getUser().equals(getIntentUser());
+
+        if (!shouldShowNoCrossProfileIntentsEmptyState) {
+            // Implementation that doesn't show any blockers
+            return new EmptyStateProvider() {};
+        }
+
+        final AbstractMultiProfilePagerAdapter.EmptyState
+                noWorkToPersonalEmptyState =
+                new DevicePolicyBlockerEmptyState(/* context= */ this,
+                /* devicePolicyStringTitleId= */ RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
+                /* defaultTitleResource= */ R.string.resolver_cross_profile_blocked,
+                /* devicePolicyStringSubtitleId= */ RESOLVER_CANT_ACCESS_PERSONAL,
+                /* defaultSubtitleResource= */
+                R.string.resolver_cant_access_personal_apps_explanation,
+                /* devicePolicyEventId= */ RESOLVER_EMPTY_STATE_NO_SHARING_TO_PERSONAL,
+                /* devicePolicyEventCategory= */ ResolverActivity.METRICS_CATEGORY_RESOLVER);
+
+        final AbstractMultiProfilePagerAdapter.EmptyState noPersonalToWorkEmptyState =
+                new DevicePolicyBlockerEmptyState(/* context= */ this,
+                /* devicePolicyStringTitleId= */ RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
+                /* defaultTitleResource= */ R.string.resolver_cross_profile_blocked,
+                /* devicePolicyStringSubtitleId= */ RESOLVER_CANT_ACCESS_WORK,
+                /* defaultSubtitleResource= */
+                R.string.resolver_cant_access_work_apps_explanation,
+                /* devicePolicyEventId= */ RESOLVER_EMPTY_STATE_NO_SHARING_TO_WORK,
+                /* devicePolicyEventCategory= */ ResolverActivity.METRICS_CATEGORY_RESOLVER);
+
+        return new NoCrossProfileEmptyStateProvider(getPersonalProfileUserHandle(),
+                noWorkToPersonalEmptyState, noPersonalToWorkEmptyState,
+                createCrossProfileIntentsChecker(), createMyUserIdProvider());
+    }
+
+    protected EmptyStateProvider createEmptyStateProvider(
+            @Nullable UserHandle workProfileUserHandle) {
+        final EmptyStateProvider blockerEmptyStateProvider = createBlockerEmptyStateProvider();
+
+        final EmptyStateProvider workProfileOffEmptyStateProvider =
+                new WorkProfilePausedEmptyStateProvider(this, workProfileUserHandle,
+                        mQuietModeManager,
+                        /* onSwitchOnWorkSelectedListener= */
+                        () -> { if (mOnSwitchOnWorkSelectedListener != null) {
+                            mOnSwitchOnWorkSelectedListener.onSwitchOnWorkSelected();
+                        }},
+                        getMetricsCategory());
+
+        final EmptyStateProvider noAppsEmptyStateProvider = new NoAppsAvailableEmptyStateProvider(
+                this,
+                workProfileUserHandle,
+                getPersonalProfileUserHandle(),
+                getMetricsCategory(),
+                createMyUserIdProvider()
+        );
+
+        // Return composite provider, the order matters (the higher, the more priority)
+        return new CompositeEmptyStateProvider(
+                blockerEmptyStateProvider,
+                workProfileOffEmptyStateProvider,
+                noAppsEmptyStateProvider
+        );
+    }
+
     private ResolverMultiProfilePagerAdapter createResolverMultiProfilePagerAdapterForOneProfile(
             Intent[] initialIntents,
             List<ResolveInfo> rList, boolean filterLastUsed) {
@@ -485,10 +610,12 @@
                 rList,
                 filterLastUsed,
                 /* userHandle */ UserHandle.of(UserHandle.myUserId()));
+        QuietModeManager quietModeManager = createQuietModeManager();
         return new ResolverMultiProfilePagerAdapter(
                 /* context */ this,
                 adapter,
-                getPersonalProfileUserHandle(),
+                createEmptyStateProvider(/* workProfileUserHandle= */ null),
+                quietModeManager,
                 /* workProfileUserHandle= */ null);
     }
 
@@ -539,14 +666,15 @@
                 (filterLastUsed && UserHandle.myUserId()
                         == workProfileUserHandle.getIdentifier()),
                 /* userHandle */ workProfileUserHandle);
+        QuietModeManager quietModeManager = createQuietModeManager();
         return new ResolverMultiProfilePagerAdapter(
                 /* context */ this,
                 personalAdapter,
                 workAdapter,
+                createEmptyStateProvider(getWorkProfileUserHandle()),
+                quietModeManager,
                 selectedProfile,
-                getPersonalProfileUserHandle(),
-                getWorkProfileUserHandle(),
-                /* shouldShowNoCrossProfileIntentsEmptyState= */ getUser().equals(intentUser));
+                getWorkProfileUserHandle());
     }
 
     protected int appliedThemeResId() {
@@ -853,9 +981,9 @@
             }
             mRegistered = true;
         }
-        if (shouldShowTabs() && mMultiProfilePagerAdapter.isWaitingToEnableWorkProfile()) {
-            if (mMultiProfilePagerAdapter.isQuietModeEnabled(getWorkProfileUserHandle())) {
-                mMultiProfilePagerAdapter.markWorkProfileEnabledBroadcastReceived();
+        if (shouldShowTabs() && mQuietModeManager.isWaitingToEnableWorkProfile()) {
+            if (mQuietModeManager.isQuietModeEnabled(getWorkProfileUserHandle())) {
+                mQuietModeManager.markWorkProfileEnabledBroadcastReceived();
             }
         }
         mMultiProfilePagerAdapter.getActiveListAdapter().handlePackagesChanged();
@@ -1815,13 +1943,12 @@
                         onHorizontalSwipeStateChanged(state);
                     }
                 });
-        mMultiProfilePagerAdapter.setOnSwitchOnWorkSelectedListener(
-                () -> {
-                    final View workTab = tabHost.getTabWidget().getChildAt(1);
-                    workTab.setFocusable(true);
-                    workTab.setFocusableInTouchMode(true);
-                    workTab.requestFocus();
-                });
+        mOnSwitchOnWorkSelectedListener = () -> {
+            final View workTab = tabHost.getTabWidget().getChildAt(1);
+            workTab.setFocusable(true);
+            workTab.setFocusableInTouchMode(true);
+            workTab.requestFocus();
+        };
     }
 
     private String getPersonalTabLabel() {
@@ -2082,7 +2209,7 @@
     public void onHandlePackagesChanged(ResolverListAdapter listAdapter) {
         if (listAdapter == mMultiProfilePagerAdapter.getActiveListAdapter()) {
             if (listAdapter.getUserHandle().equals(getWorkProfileUserHandle())
-                    && mMultiProfilePagerAdapter.isWaitingToEnableWorkProfile()) {
+                    && mQuietModeManager.isWaitingToEnableWorkProfile()) {
                 // We have just turned on the work profile and entered the pass code to start it,
                 // now we are waiting to receive the ACTION_USER_UNLOCKED broadcast. There is no
                 // point in reloading the list now, since the work profile user is still
@@ -2134,7 +2261,7 @@
                     }
 
                     mWorkProfileHasBeenEnabled = true;
-                    mMultiProfilePagerAdapter.markWorkProfileEnabledBroadcastReceived();
+                    mQuietModeManager.markWorkProfileEnabledBroadcastReceived();
                 } else {
                     // Must be an UNAVAILABLE broadcast, so we watch for the next availability
                     mWorkProfileHasBeenEnabled = false;
@@ -2150,7 +2277,6 @@
         };
     }
 
-    @VisibleForTesting
     public static final class ResolvedComponentInfo {
         public final ComponentName name;
         private final List<Intent> mIntents = new ArrayList<>();
diff --git a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
index 0b33501..9922051 100644
--- a/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
+++ b/core/java/com/android/internal/app/ResolverMultiProfilePagerAdapter.java
@@ -16,15 +16,7 @@
 
 package com.android.internal.app;
 
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_PERSONAL;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CANT_ACCESS_WORK;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_CROSS_PROFILE_BLOCKED_TITLE;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_PERSONAL_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_NO_WORK_APPS;
-import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PAUSED_TITLE;
-
 import android.annotation.Nullable;
-import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.os.UserHandle;
 import android.view.LayoutInflater;
@@ -43,34 +35,33 @@
 public class ResolverMultiProfilePagerAdapter extends AbstractMultiProfilePagerAdapter {
 
     private final ResolverProfileDescriptor[] mItems;
-    private final boolean mShouldShowNoCrossProfileIntentsEmptyState;
     private boolean mUseLayoutWithDefault;
 
     ResolverMultiProfilePagerAdapter(Context context,
             ResolverListAdapter adapter,
-            UserHandle personalProfileUserHandle,
+            EmptyStateProvider emptyStateProvider,
+            QuietModeManager quietModeManager,
             UserHandle workProfileUserHandle) {
-        super(context, /* currentPage */ 0, personalProfileUserHandle, workProfileUserHandle);
+        super(context, /* currentPage */ 0, emptyStateProvider, quietModeManager,
+                workProfileUserHandle);
         mItems = new ResolverProfileDescriptor[] {
                 createProfileDescriptor(adapter)
         };
-        mShouldShowNoCrossProfileIntentsEmptyState = true;
     }
 
     ResolverMultiProfilePagerAdapter(Context context,
             ResolverListAdapter personalAdapter,
             ResolverListAdapter workAdapter,
+            EmptyStateProvider emptyStateProvider,
+            QuietModeManager quietModeManager,
             @Profile int defaultProfile,
-            UserHandle personalProfileUserHandle,
-            UserHandle workProfileUserHandle,
-            boolean shouldShowNoCrossProfileIntentsEmptyState) {
-        super(context, /* currentPage */ defaultProfile, personalProfileUserHandle,
+            UserHandle workProfileUserHandle) {
+        super(context, /* currentPage */ defaultProfile, emptyStateProvider, quietModeManager,
                 workProfileUserHandle);
         mItems = new ResolverProfileDescriptor[] {
                 createProfileDescriptor(personalAdapter),
                 createProfileDescriptor(workAdapter)
         };
-        mShouldShowNoCrossProfileIntentsEmptyState = shouldShowNoCrossProfileIntentsEmptyState;
     }
 
     private ResolverProfileDescriptor createProfileDescriptor(
@@ -170,93 +161,6 @@
         return getListViewForIndex(1 - getCurrentPage());
     }
 
-    @Override
-    String getMetricsCategory() {
-        return ResolverActivity.METRICS_CATEGORY_RESOLVER;
-    }
-
-    @Override
-    boolean allowShowNoCrossProfileIntentsEmptyState() {
-        return mShouldShowNoCrossProfileIntentsEmptyState;
-    }
-
-    @Override
-    protected void showWorkProfileOffEmptyState(ResolverListAdapter activeListAdapter,
-            View.OnClickListener listener) {
-        showEmptyState(activeListAdapter,
-                getWorkAppPausedTitle(),
-                /* subtitle = */ null,
-                listener);
-    }
-
-    @Override
-    protected void showNoPersonalToWorkIntentsEmptyState(ResolverListAdapter activeListAdapter) {
-        showEmptyState(activeListAdapter,
-                getCrossProfileBlockedTitle(),
-                getCantAccessWorkMessage());
-    }
-
-    @Override
-    protected void showNoWorkToPersonalIntentsEmptyState(ResolverListAdapter activeListAdapter) {
-        showEmptyState(activeListAdapter,
-                getCrossProfileBlockedTitle(),
-                getCantAccessPersonalMessage());
-    }
-
-    @Override
-    protected void showNoPersonalAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
-        showEmptyState(listAdapter,
-                getNoPersonalAppsAvailableMessage(),
-                /* subtitle = */ null);
-    }
-
-    @Override
-    protected void showNoWorkAppsAvailableEmptyState(ResolverListAdapter listAdapter) {
-        showEmptyState(listAdapter,
-                getNoWorkAppsAvailableMessage(),
-                /* subtitle= */ null);
-    }
-
-    private String getWorkAppPausedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_WORK_PAUSED_TITLE,
-                () -> getContext().getString(R.string.resolver_turn_on_work_apps));
-    }
-
-    private String getCrossProfileBlockedTitle() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CROSS_PROFILE_BLOCKED_TITLE,
-                () -> getContext().getString(R.string.resolver_cross_profile_blocked));
-    }
-
-    private String getCantAccessWorkMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_ACCESS_WORK,
-                () -> getContext().getString(
-                        R.string.resolver_cant_access_work_apps_explanation));
-    }
-
-    private String getCantAccessPersonalMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_CANT_ACCESS_PERSONAL,
-                () -> getContext().getString(
-                        R.string.resolver_cant_access_personal_apps_explanation));
-    }
-
-    private String getNoWorkAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_NO_WORK_APPS,
-                () -> getContext().getString(
-                        R.string.resolver_no_work_apps_available));
-    }
-
-    private String getNoPersonalAppsAvailableMessage() {
-        return getContext().getSystemService(DevicePolicyManager.class).getResources().getString(
-                RESOLVER_NO_PERSONAL_APPS,
-                () -> getContext().getString(
-                        R.string.resolver_no_personal_apps_available));
-    }
-
     void setUseLayoutWithDefault(boolean useLayoutWithDefault) {
         mUseLayoutWithDefault = useLayoutWithDefault;
     }
diff --git a/core/java/com/android/internal/app/WorkProfilePausedEmptyStateProvider.java b/core/java/com/android/internal/app/WorkProfilePausedEmptyStateProvider.java
new file mode 100644
index 0000000..6a88557
--- /dev/null
+++ b/core/java/com/android/internal/app/WorkProfilePausedEmptyStateProvider.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app;
+
+import static android.app.admin.DevicePolicyResources.Strings.Core.RESOLVER_WORK_PAUSED_TITLE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.admin.DevicePolicyEventLogger;
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.UserHandle;
+import android.stats.devicepolicy.nano.DevicePolicyEnums;
+
+import com.android.internal.R;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyState;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.EmptyStateProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.OnSwitchOnWorkSelectedListener;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.QuietModeManager;
+
+/**
+ * Chooser/ResolverActivity empty state provider that returns empty state which is shown when
+ * work profile is paused and we need to show a button to enable it.
+ */
+public class WorkProfilePausedEmptyStateProvider implements EmptyStateProvider {
+
+    private final UserHandle mWorkProfileUserHandle;
+    private final QuietModeManager mQuietModeManager;
+    private final String mMetricsCategory;
+    private final OnSwitchOnWorkSelectedListener mOnSwitchOnWorkSelectedListener;
+    private final Context mContext;
+
+    public WorkProfilePausedEmptyStateProvider(@NonNull Context context,
+            @Nullable UserHandle workProfileUserHandle,
+            @NonNull QuietModeManager quietModeManager,
+            @Nullable OnSwitchOnWorkSelectedListener onSwitchOnWorkSelectedListener,
+            @NonNull String metricsCategory) {
+        mContext = context;
+        mWorkProfileUserHandle = workProfileUserHandle;
+        mQuietModeManager = quietModeManager;
+        mMetricsCategory = metricsCategory;
+        mOnSwitchOnWorkSelectedListener = onSwitchOnWorkSelectedListener;
+    }
+
+    @Nullable
+    @Override
+    public EmptyState getEmptyState(ResolverListAdapter resolverListAdapter) {
+        if (!resolverListAdapter.getUserHandle().equals(mWorkProfileUserHandle)
+                || !mQuietModeManager.isQuietModeEnabled(mWorkProfileUserHandle)
+                || resolverListAdapter.getCount() == 0) {
+            return null;
+        }
+
+        final String title = mContext.getSystemService(DevicePolicyManager.class)
+                .getResources().getString(RESOLVER_WORK_PAUSED_TITLE,
+                () -> mContext.getString(R.string.resolver_turn_on_work_apps));
+
+        return new WorkProfileOffEmptyState(title, (tab) -> {
+            tab.showSpinner();
+            if (mOnSwitchOnWorkSelectedListener != null) {
+                mOnSwitchOnWorkSelectedListener.onSwitchOnWorkSelected();
+            }
+            mQuietModeManager.requestQuietModeEnabled(false, mWorkProfileUserHandle);
+        }, mMetricsCategory);
+    }
+
+    public static class WorkProfileOffEmptyState implements EmptyState {
+
+        private final String mTitle;
+        private final ClickListener mOnClick;
+        private final String mMetricsCategory;
+
+        public WorkProfileOffEmptyState(String title, @NonNull ClickListener onClick,
+                @NonNull String metricsCategory) {
+            mTitle = title;
+            mOnClick = onClick;
+            mMetricsCategory = metricsCategory;
+        }
+
+        @Nullable
+        @Override
+        public String getTitle() {
+            return mTitle;
+        }
+
+        @Nullable
+        @Override
+        public ClickListener getButtonClickListener() {
+            return mOnClick;
+        }
+
+        @Override
+        public void onEmptyStateShown() {
+            DevicePolicyEventLogger
+                    .createEvent(DevicePolicyEnums.RESOLVER_EMPTY_STATE_WORK_APPS_DISABLED)
+                    .setStrings(mMetricsCategory)
+                    .write();
+        }
+    }
+}
diff --git a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
index 292a50b..4f7f8ba 100644
--- a/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
+++ b/core/java/com/android/internal/config/sysui/SystemUiDeviceConfigFlags.java
@@ -556,6 +556,12 @@
             "show_stop_button_for_user_allowlisted_apps";
 
     /**
+     * (boolean) Whether the task manager should show apps running user-visible jobs.
+     */
+    public static final String TASK_MANAGER_SHOW_USER_VISIBLE_JOBS =
+            "task_manager_show_user_visible_jobs";
+
+    /**
      * (boolean) Whether to show notification volume control slider separate from ring.
      */
     public static final String VOLUME_SEPARATE_NOTIFICATION = "volume_separate_notification";
diff --git a/core/java/com/android/internal/content/om/OverlayConfig.java b/core/java/com/android/internal/content/om/OverlayConfig.java
index 828e5cf..2d04bdb 100644
--- a/core/java/com/android/internal/content/om/OverlayConfig.java
+++ b/core/java/com/android/internal/content/om/OverlayConfig.java
@@ -140,7 +140,6 @@
 
         ArrayMap<Integer, List<String>> activeApexesPerPartition = getActiveApexes(partitions);
 
-        boolean foundConfigFile = false;
         final Map<String, ParsedOverlayInfo> packageManagerOverlayInfos =
                 packageProvider == null ? null : getOverlayPackageInfos(packageProvider);
 
@@ -154,7 +153,6 @@
                             activeApexesPerPartition.getOrDefault(partition.type,
                                     Collections.emptyList()));
             if (partitionOverlays != null) {
-                foundConfigFile = true;
                 overlays.addAll(partitionOverlays);
                 continue;
             }
@@ -191,12 +189,6 @@
             overlays.addAll(partitionConfigs);
         }
 
-        if (!foundConfigFile) {
-            // If no overlay configuration files exist, disregard partition precedence and allow
-            // android:priority to reorder overlays across partition boundaries.
-            overlays.sort(sStaticOverlayComparator);
-        }
-
         for (int i = 0, n = overlays.size(); i < n; i++) {
             // Add the configurations to a map so definitions of an overlay in an earlier
             // partition can be replaced by an overlay with the same package name in a later
diff --git a/core/java/com/android/internal/content/om/OverlayManagerImpl.java b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
new file mode 100644
index 0000000..260d1a2
--- /dev/null
+++ b/core/java/com/android/internal/content/om/OverlayManagerImpl.java
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.om;
+
+import static android.content.Context.MODE_PRIVATE;
+import static android.content.om.OverlayManagerTransaction.Request.BUNDLE_FABRICATED_OVERLAY;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_REGISTER_FABRICATED;
+import static android.content.om.OverlayManagerTransaction.Request.TYPE_UNREGISTER_FABRICATED;
+
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+import static com.android.internal.content.om.OverlayConfig.DEFAULT_PRIORITY;
+
+import android.annotation.NonNull;
+import android.annotation.NonUiContext;
+import android.content.Context;
+import android.content.om.OverlayIdentifier;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.parsing.FrameworkParsingPackageUtils;
+import android.os.FabricatedOverlayInfo;
+import android.os.FabricatedOverlayInternal;
+import android.os.FabricatedOverlayInternalEntry;
+import android.os.FileUtils;
+import android.os.Process;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * This class provides the functionalities of registering an overlay, unregistering an overlay, and
+ * getting the list of overlays information.
+ */
+public class OverlayManagerImpl {
+    private static final String TAG = "OverlayManagerImpl";
+    private static final boolean DEBUG = false;
+
+    private static final String FRRO_EXTENSION = ".frro";
+
+    private static final String IDMAP_EXTENSION = ".idmap";
+
+    @VisibleForTesting(visibility = PRIVATE)
+    public static final String SELF_TARGET = ".self_target";
+
+    @NonNull
+    private final Context mContext;
+    private Path mBasePath;
+
+    /**
+     * Init a OverlayManagerImpl by the context.
+     *
+     * @param context the context to create overlay environment
+     */
+    @VisibleForTesting(visibility = PACKAGE)
+    public OverlayManagerImpl(@NonNull Context context) {
+        mContext = Objects.requireNonNull(context);
+
+        if (!Process.myUserHandle().equals(context.getUser())) {
+            throw new SecurityException("Self-Targeting doesn't support multiple user now!");
+        }
+    }
+
+    private static void cleanExpiredOverlays(Path selfTargetingBasePath,
+            Path folderForCurrentBaseApk) {
+        try {
+            final String currentBaseFolder = folderForCurrentBaseApk.toString();
+            final String selfTargetingDir = selfTargetingBasePath.getFileName().toString();
+            Files.walkFileTree(
+                    selfTargetingBasePath,
+                    new SimpleFileVisitor<>() {
+                        @Override
+                        public FileVisitResult preVisitDirectory(Path dir,
+                                                                 BasicFileAttributes attrs)
+                                throws IOException {
+                            final String fileName = dir.getFileName().toString();
+                            return fileName.equals(currentBaseFolder)
+                                    ? FileVisitResult.SKIP_SUBTREE
+                                    : super.preVisitDirectory(dir, attrs);
+                        }
+
+                        @Override
+                        public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                                throws IOException {
+                            if (!file.toFile().delete()) {
+                                Log.w(TAG, "Failed to delete file " + file);
+                            }
+                            return super.visitFile(file, attrs);
+                        }
+
+                        @Override
+                        public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                                throws IOException {
+                            final String fileName = dir.getFileName().toString();
+                            if (!fileName.equals(currentBaseFolder)
+                                    && !fileName.equals(selfTargetingDir)) {
+                                if (!dir.toFile().delete()) {
+                                    Log.w(TAG, "Failed to delete dir " + dir);
+                                }
+                            }
+                            return super.postVisitDirectory(dir, exc);
+                        }
+                    });
+        } catch (IOException e) {
+            Log.w(TAG, "Unknown fail " + e);
+        }
+    }
+
+    /** Ensure the base dir for self-targeting is valid. */
+    @VisibleForTesting
+    @NonUiContext
+    public void ensureBaseDir() {
+        final String baseApkPath = mContext.getApplicationInfo().getBaseCodePath();
+        final Path baseApkFolderName = Path.of(baseApkPath).getParent().getFileName();
+        final File selfTargetingBaseFile = mContext.getDir(SELF_TARGET, MODE_PRIVATE);
+        Preconditions.checkArgument(
+                selfTargetingBaseFile.isDirectory()
+                        && selfTargetingBaseFile.exists()
+                        && selfTargetingBaseFile.canWrite()
+                        && selfTargetingBaseFile.canRead()
+                        && selfTargetingBaseFile.canExecute(),
+                "Can't work for this context");
+        cleanExpiredOverlays(selfTargetingBaseFile.toPath(), baseApkFolderName);
+
+        final File baseFile = new File(selfTargetingBaseFile, baseApkFolderName.toString());
+        if (!baseFile.exists()) {
+            if (!baseFile.mkdirs()) {
+                Log.w(TAG, "Failed to create directory " + baseFile);
+            }
+
+            // It fails to create frro and idmap files without this setting.
+            FileUtils.setPermissions(
+                    baseFile,
+                    FileUtils.S_IRWXU,
+                    -1 /* uid unchanged */,
+                    -1 /* gid unchanged */);
+        }
+        Preconditions.checkArgument(
+                baseFile.isDirectory()
+                        && baseFile.exists()
+                        && baseFile.canWrite()
+                        && baseFile.canRead()
+                        && baseFile.canExecute(), // 'list' capability
+                "Can't create a workspace for this context");
+
+        mBasePath = baseFile.toPath();
+    }
+
+    private boolean isSameWithTargetSignature(final String targetPackage) {
+        final PackageManager packageManager = mContext.getPackageManager();
+        final String packageName = mContext.getPackageName();
+        if (TextUtils.equals(packageName, targetPackage)) {
+            return true;
+        }
+        return packageManager.checkSignatures(packageName, targetPackage)
+                == PackageManager.SIGNATURE_MATCH;
+    }
+
+    /**
+     * Check if the overlay name is valid or not.
+     *
+     * @param name the non-check overlay name
+     * @return the valid overlay name
+     */
+    public static String checkOverlayNameValid(@NonNull String name) {
+        final String overlayName =
+                Preconditions.checkStringNotEmpty(
+                        name, "overlayName should be neither empty nor null string");
+        final String checkOverlayNameResult =
+                FrameworkParsingPackageUtils.validateName(
+                        overlayName, false /* requireSeparator */, true /* requireFilename */);
+        Preconditions.checkArgument(
+                checkOverlayNameResult == null,
+                TextUtils.formatSimple(
+                        "Invalid overlayName \"%s\". The check result is %s.",
+                        overlayName, checkOverlayNameResult));
+        return overlayName;
+    }
+
+    private void checkPackageName(@NonNull String packageName) {
+        Preconditions.checkStringNotEmpty(packageName);
+        Preconditions.checkArgument(
+                TextUtils.equals(mContext.getPackageName(), packageName),
+                TextUtils.formatSimple(
+                        "UID %d doesn't own the package %s", Process.myUid(), packageName));
+    }
+
+    /**
+     * Save FabricatedOverlay instance as frro and idmap files.
+     *
+     * <p>In order to fill the overlayable policy, it's necessary to collect the information from
+     * app. And then, the information is passed to native layer to fill the overlayable policy
+     *
+     * @param overlayInternal the FabricatedOverlayInternal to be saved.
+     */
+    @NonUiContext
+    public void registerFabricatedOverlay(@NonNull FabricatedOverlayInternal overlayInternal)
+            throws IOException, PackageManager.NameNotFoundException {
+        ensureBaseDir();
+        Objects.requireNonNull(overlayInternal);
+        final List<FabricatedOverlayInternalEntry> entryList =
+                Objects.requireNonNull(overlayInternal.entries);
+        Preconditions.checkArgument(!entryList.isEmpty(), "overlay entries shouldn't be empty");
+        final String overlayName = checkOverlayNameValid(overlayInternal.overlayName);
+        checkPackageName(overlayInternal.packageName);
+        checkPackageName(overlayInternal.targetPackageName);
+        Preconditions.checkStringNotEmpty(
+                overlayInternal.targetOverlayable,
+                "Target overlayable should be neither null nor empty string.");
+
+        final ApplicationInfo applicationInfo = mContext.getApplicationInfo();
+        final String targetPackage = Preconditions.checkStringNotEmpty(
+                applicationInfo.getBaseCodePath());
+        final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION);
+        final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION);
+
+        createFrroFile(frroPath.toString(), overlayInternal);
+        try {
+            createIdmapFile(
+                    targetPackage,
+                    frroPath.toString(),
+                    idmapPath.toString(),
+                    overlayName,
+                    applicationInfo.isSystemApp() || applicationInfo.isSystemExt() /* isSystem */,
+                    applicationInfo.isVendor(),
+                    applicationInfo.isProduct(),
+                    isSameWithTargetSignature(overlayInternal.targetPackageName),
+                    applicationInfo.isOdm(),
+                    applicationInfo.isOem());
+        } catch (IOException e) {
+            if (!frroPath.toFile().delete()) {
+                Log.w(TAG, "Failed to delete file " + frroPath);
+            }
+            throw e;
+        }
+    }
+
+    /**
+     * Remove the overlay with the specific name
+     *
+     * @param overlayName the specific name
+     */
+    @NonUiContext
+    public void unregisterFabricatedOverlay(@NonNull String overlayName) {
+        ensureBaseDir();
+        checkOverlayNameValid(overlayName);
+        final Path frroPath = mBasePath.resolve(overlayName + FRRO_EXTENSION);
+        final Path idmapPath = mBasePath.resolve(overlayName + IDMAP_EXTENSION);
+
+        if (!frroPath.toFile().delete()) {
+            Log.w(TAG, "Failed to delete file " + frroPath);
+        }
+        if (!idmapPath.toFile().delete()) {
+            Log.w(TAG, "Failed to delete file " + idmapPath);
+        }
+    }
+
+    /**
+     * Commit the overlay manager transaction
+     *
+     * @param transaction the overlay manager transaction
+     */
+    @NonUiContext
+    public void commit(@NonNull OverlayManagerTransaction transaction)
+            throws PackageManager.NameNotFoundException, IOException {
+        Objects.requireNonNull(transaction);
+
+        for (Iterator<OverlayManagerTransaction.Request> it = transaction.iterator();
+                it.hasNext(); ) {
+            final OverlayManagerTransaction.Request request = it.next();
+            if (request.type == TYPE_REGISTER_FABRICATED) {
+                final FabricatedOverlayInternal fabricatedOverlayInternal =
+                        Objects.requireNonNull(
+                                request.extras.getParcelable(
+                                        BUNDLE_FABRICATED_OVERLAY,
+                                        FabricatedOverlayInternal.class));
+
+                // populate the mandatory data
+                if (TextUtils.isEmpty(fabricatedOverlayInternal.packageName)) {
+                    fabricatedOverlayInternal.packageName = mContext.getPackageName();
+                } else {
+                    if (!TextUtils.equals(
+                            fabricatedOverlayInternal.packageName, mContext.getPackageName())) {
+                        throw new IllegalArgumentException("Unknown package name in transaction");
+                    }
+                }
+
+                registerFabricatedOverlay(fabricatedOverlayInternal);
+            } else if (request.type == TYPE_UNREGISTER_FABRICATED) {
+                final OverlayIdentifier overlayIdentifier = Objects.requireNonNull(request.overlay);
+                unregisterFabricatedOverlay(overlayIdentifier.getOverlayName());
+            } else {
+                throw new IllegalArgumentException("Unknown request in transaction " + request);
+            }
+        }
+    }
+
+    /**
+     * Get the list of overlays information for the target package name.
+     *
+     * @param targetPackage the target package name
+     * @return the list of overlays information.
+     */
+    @NonNull
+    public List<OverlayInfo> getOverlayInfosForTarget(@NonNull String targetPackage) {
+        ensureBaseDir();
+
+        final File base = mBasePath.toFile();
+        final File[] frroFiles = base.listFiles((dir, name) -> {
+            if (!name.endsWith(FRRO_EXTENSION)) {
+                return false;
+            }
+
+            final String idmapFileName = name.substring(0, name.length() - FRRO_EXTENSION.length())
+                    + IDMAP_EXTENSION;
+            final File idmapFile = new File(dir, idmapFileName);
+            return idmapFile.exists();
+        });
+
+        final ArrayList<OverlayInfo> overlayInfos = new ArrayList<>();
+        for (File file : frroFiles) {
+            final FabricatedOverlayInfo fabricatedOverlayInfo;
+            try {
+                fabricatedOverlayInfo = getFabricatedOverlayInfo(file.getAbsolutePath());
+            } catch (IOException e) {
+                Log.w(TAG, "can't load " + file);
+                continue;
+            }
+            if (!TextUtils.equals(targetPackage, fabricatedOverlayInfo.targetPackageName)) {
+                continue;
+            }
+            if (DEBUG) {
+                Log.i(TAG, "load " + file);
+            }
+
+            final OverlayInfo overlayInfo =
+                    new OverlayInfo(
+                            fabricatedOverlayInfo.packageName,
+                            fabricatedOverlayInfo.overlayName,
+                            fabricatedOverlayInfo.targetPackageName,
+                            fabricatedOverlayInfo.targetOverlayable,
+                            null,
+                            file.getAbsolutePath(),
+                            OverlayInfo.STATE_ENABLED,
+                            UserHandle.myUserId(),
+                            DEFAULT_PRIORITY,
+                            true /* isMutable */,
+                            true /* isFabricated */);
+            overlayInfos.add(overlayInfo);
+        }
+        return overlayInfos;
+    }
+
+    private static native void createFrroFile(
+            @NonNull String frroFile, @NonNull FabricatedOverlayInternal fabricatedOverlayInternal)
+            throws IOException;
+
+    private static native void createIdmapFile(
+            @NonNull String targetPath,
+            @NonNull String overlayPath,
+            @NonNull String idmapPath,
+            @NonNull String overlayName,
+            boolean isSystem,
+            boolean isVendor,
+            boolean isProduct,
+            boolean isSameWithTargetSignature,
+            boolean isOdm,
+            boolean isOem)
+            throws IOException;
+
+    private static native FabricatedOverlayInfo getFabricatedOverlayInfo(
+            @NonNull String overlayPath) throws IOException;
+}
diff --git a/core/java/com/android/internal/inputmethod/EditableInputConnection.java b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
index 330ff8e..52e7471 100644
--- a/core/java/com/android/internal/inputmethod/EditableInputConnection.java
+++ b/core/java/com/android/internal/inputmethod/EditableInputConnection.java
@@ -27,6 +27,7 @@
 import android.annotation.Nullable;
 import android.graphics.RectF;
 import android.os.Bundle;
+import android.os.CancellationSignal;
 import android.text.Editable;
 import android.text.Selection;
 import android.text.method.KeyListener;
@@ -44,6 +45,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InsertGesture;
 import android.view.inputmethod.JoinOrSplitGesture;
+import android.view.inputmethod.PreviewableHandwritingGesture;
 import android.view.inputmethod.RemoveSpaceGesture;
 import android.view.inputmethod.SelectGesture;
 import android.view.inputmethod.SelectRangeGesture;
@@ -321,6 +323,13 @@
     }
 
     @Override
+    public boolean previewHandwritingGesture(
+            @NonNull PreviewableHandwritingGesture gesture,
+            @Nullable CancellationSignal cancellationSignal) {
+        return mTextView.previewHandwritingGesture(gesture, cancellationSignal);
+    }
+
+    @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         CharSequence editableText = mTextView.getText();
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 1e3714e..8cb568d 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -40,7 +40,6 @@
     parcelable InitParams {
         IBinder token;
         IInputMethodPrivilegedOperations privilegedOperations;
-        int configChanges;
         int navigationBarFlags;
     }
 
diff --git a/core/java/com/android/internal/os/TimeoutRecord.java b/core/java/com/android/internal/os/TimeoutRecord.java
index 680f8fe..a587834 100644
--- a/core/java/com/android/internal/os/TimeoutRecord.java
+++ b/core/java/com/android/internal/os/TimeoutRecord.java
@@ -40,7 +40,8 @@
             TimeoutKind.SERVICE_START,
             TimeoutKind.SERVICE_EXEC,
             TimeoutKind.CONTENT_PROVIDER,
-            TimeoutKind.APP_REGISTERED})
+            TimeoutKind.APP_REGISTERED,
+            TimeoutKind.SHORT_FGS_TIMEOUT})
 
     @Retention(RetentionPolicy.SOURCE)
     public @interface TimeoutKind {
@@ -51,6 +52,7 @@
         int SERVICE_EXEC = 5;
         int CONTENT_PROVIDER = 6;
         int APP_REGISTERED = 7;
+        int SHORT_FGS_TIMEOUT = 8;
     }
 
     /** Kind of timeout, e.g. BROADCAST_RECEIVER, etc. */
@@ -144,4 +146,10 @@
     public static TimeoutRecord forApp(@NonNull String reason) {
         return TimeoutRecord.endingApproximatelyNow(TimeoutKind.APP_REGISTERED, reason);
     }
+
+    /** Record for a "short foreground service" timeout. */
+    @NonNull
+    public static TimeoutRecord forShortFgsTimeout(String reason) {
+        return TimeoutRecord.endingNow(TimeoutKind.SHORT_FGS_TIMEOUT, reason);
+    }
 }
diff --git a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
index a182920..2748ded 100644
--- a/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
+++ b/core/java/com/android/internal/os/anr/AnrLatencyTracker.java
@@ -24,6 +24,7 @@
 import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__EXECUTING_SERVICE;
 import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__INPUT_DISPATCHING_TIMEOUT;
 import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__INPUT_DISPATCHING_TIMEOUT_NO_FOCUSED_WINDOW;
+import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__SHORT_FGS_TIMEOUT;
 import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__START_FOREGROUND_SERVICE;
 import static com.android.internal.util.FrameworkStatsLog.ANRLATENCY_REPORTED__ANR_TYPE__UNKNOWN_ANR_TYPE;
 
@@ -400,6 +401,8 @@
                 return ANRLATENCY_REPORTED__ANR_TYPE__EXECUTING_SERVICE;
             case TimeoutKind.CONTENT_PROVIDER:
                 return ANRLATENCY_REPORTED__ANR_TYPE__CONTENT_PROVIDER_NOT_RESPONDING;
+            case TimeoutKind.SHORT_FGS_TIMEOUT:
+                return ANRLATENCY_REPORTED__ANR_TYPE__SHORT_FGS_TIMEOUT;
             default:
                 return ANRLATENCY_REPORTED__ANR_TYPE__UNKNOWN_ANR_TYPE;
         }
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 4b1753a..9cb2e68 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -17,7 +17,7 @@
 package com.android.internal.telephony;
 
 import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
+import android.telephony.CallState;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.DataConnectionRealTimeInfo;
@@ -62,7 +62,7 @@
     void onPhoneCapabilityChanged(in PhoneCapability capability);
     void onActiveDataSubIdChanged(in int subId);
     void onRadioPowerStateChanged(in int state);
-    void onCallAttributesChanged(in CallAttributes callAttributes);
+    void onCallStatesChanged(in List<CallState> callStateList);
     @SuppressWarnings(value={"untyped-collection"})
     void onEmergencyNumberListChanged(in Map emergencyNumberList);
     void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index c7fa757..7ba2686 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -66,8 +66,8 @@
     void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
     @UnsupportedAppUsage
     void notifyCellInfo(in List<CellInfo> cellInfo);
-    void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
-            int foregroundCallState, int backgroundCallState);
+    void notifyPreciseCallState(int phoneId, int subId, in int[] callStates, in String[] imsCallIds,
+            in int[] imsCallServiceTypes, in int[] imsCallTypes);
     void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
             int preciseDisconnectCause);
     void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
diff --git a/core/java/com/android/internal/usb/DumpUtils.java b/core/java/com/android/internal/usb/DumpUtils.java
index 1eb446e..f974d9d 100644
--- a/core/java/com/android/internal/usb/DumpUtils.java
+++ b/core/java/com/android/internal/usb/DumpUtils.java
@@ -174,6 +174,9 @@
         } else {
             dump.write("supported_modes", UsbPortProto.SUPPORTED_MODES, UsbPort.modeToString(mode));
         }
+        dump.write("supports_compliance_warnings",
+                UsbPortProto.SUPPORTS_COMPLIANCE_WARNINGS,
+                port.supportsComplianceWarnings());
 
         dump.end(token);
     }
@@ -250,6 +253,8 @@
                 status.isPowerTransferLimited());
         dump.write("usb_power_brick_status", UsbPortStatusProto.USB_POWER_BRICK_STATUS,
                 UsbPort.powerBrickConnectionStatusToString(status.getPowerBrickConnectionStatus()));
+        dump.write("compliance_warning_status", UsbPortStatusProto.COMPLIANCE_WARNINGS_STRING,
+                UsbPort.complianceWarningsToString(status.getComplianceWarnings()));
         dump.end(token);
     }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index d8b91c7..1bc903a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -40,6 +40,8 @@
 
     cppflags: ["-Wno-conversion-null"],
 
+    cpp_std: "gnu++20",
+
     srcs: [
         "android_animation_PropertyValuesHolder.cpp",
         "android_os_SystemClock.cpp",
@@ -215,6 +217,7 @@
                 "android_content_res_ResourceTimer.cpp",
                 "android_security_Scrypt.cpp",
                 "com_android_internal_content_om_OverlayConfig.cpp",
+                "com_android_internal_content_om_OverlayManagerImpl.cpp",
                 "com_android_internal_expresslog_Counter.cpp",
                 "com_android_internal_net_NetworkUtilsInternal.cpp",
                 "com_android_internal_os_ClassLoaderFactory.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f549cd8..6ceffde 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -198,6 +198,7 @@
 extern int register_com_android_internal_content_F2fsUtils(JNIEnv* env);
 extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
 extern int register_com_android_internal_content_om_OverlayConfig(JNIEnv *env);
+extern int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env);
 extern int register_com_android_internal_expresslog_Counter(JNIEnv* env);
 extern int register_com_android_internal_net_NetworkUtilsInternal(JNIEnv* env);
 extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
@@ -644,7 +645,6 @@
     char jitmaxsizeOptsBuf[sizeof("-Xjitmaxsize:")-1 + PROPERTY_VALUE_MAX];
     char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
     char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
-    char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
     char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
     char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
     char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
@@ -859,10 +859,7 @@
     parseRuntimeOption("dalvik.vm.jitpthreadpriority",
                        jitpthreadpriorityOptsBuf,
                        "-Xjitpthreadpriority:");
-    property_get("dalvik.vm.usejitprofiles", useJitProfilesOptsBuf, "");
-    if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
-        addOption("-Xjitsaveprofilinginfo");
-    }
+    addOption("-Xjitsaveprofilinginfo");
 
     parseRuntimeOption("dalvik.vm.jitprithreadweight",
                        jitprithreadweightOptBuf,
@@ -1587,6 +1584,7 @@
         REG_JNI(register_android_os_SharedMemory),
         REG_JNI(register_android_os_incremental_IncrementalManager),
         REG_JNI(register_com_android_internal_content_om_OverlayConfig),
+        REG_JNI(register_com_android_internal_content_om_OverlayManagerImpl),
         REG_JNI(register_com_android_internal_expresslog_Counter),
         REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
         REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp
index a8d7231..e9ada23 100644
--- a/core/jni/android_content_res_ApkAssets.cpp
+++ b/core/jni/android_content_res_ApkAssets.cpp
@@ -96,7 +96,7 @@
   }
 
   bool ForEachFile(const std::string& /* root_path */,
-                   const std::function<void(const StringPiece&, FileType)>& /* f */) const {
+                   android::base::function_ref<void(StringPiece, FileType)> /* f */) const {
     return true;
   }
 
@@ -402,7 +402,7 @@
     return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool());
 }
 
-static jboolean NativeIsUpToDate(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) {
+static jboolean NativeIsUpToDate(jlong ptr) {
     auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr));
     auto apk_assets = scoped_apk_assets->get();
     return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE;
@@ -500,24 +500,28 @@
 
 // JNI registration.
 static const JNINativeMethod gApkAssetsMethods[] = {
-    {"nativeLoad", "(ILjava/lang/String;ILandroid/content/res/loader/AssetsProvider;)J",
-     (void*)NativeLoad},
-    {"nativeLoadEmpty", "(ILandroid/content/res/loader/AssetsProvider;)J", (void*)NativeLoadEmpty},
-    {"nativeLoadFd",
-     "(ILjava/io/FileDescriptor;Ljava/lang/String;ILandroid/content/res/loader/AssetsProvider;)J",
-     (void*)NativeLoadFromFd},
-    {"nativeLoadFdOffsets",
-     "(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/AssetsProvider;)J",
-     (void*)NativeLoadFromFdOffset},
-    {"nativeDestroy", "(J)V", (void*)NativeDestroy},
-    {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
-    {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
-    {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
-    {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
-    {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
-    {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;",
-     (void*)NativeGetOverlayableInfo},
-    {"nativeDefinesOverlayable", "(J)Z", (void*)NativeDefinesOverlayable},
+        {"nativeLoad", "(ILjava/lang/String;ILandroid/content/res/loader/AssetsProvider;)J",
+         (void*)NativeLoad},
+        {"nativeLoadEmpty", "(ILandroid/content/res/loader/AssetsProvider;)J",
+         (void*)NativeLoadEmpty},
+        {"nativeLoadFd",
+         "(ILjava/io/FileDescriptor;Ljava/lang/String;ILandroid/content/res/loader/"
+         "AssetsProvider;)J",
+         (void*)NativeLoadFromFd},
+        {"nativeLoadFdOffsets",
+         "(ILjava/io/FileDescriptor;Ljava/lang/String;JJILandroid/content/res/loader/"
+         "AssetsProvider;)J",
+         (void*)NativeLoadFromFdOffset},
+        {"nativeDestroy", "(J)V", (void*)NativeDestroy},
+        {"nativeGetAssetPath", "(J)Ljava/lang/String;", (void*)NativeGetAssetPath},
+        {"nativeGetDebugName", "(J)Ljava/lang/String;", (void*)NativeGetDebugName},
+        {"nativeGetStringBlock", "(J)J", (void*)NativeGetStringBlock},
+        // @CriticalNative
+        {"nativeIsUpToDate", "(J)Z", (void*)NativeIsUpToDate},
+        {"nativeOpenXml", "(JLjava/lang/String;)J", (void*)NativeOpenXml},
+        {"nativeGetOverlayableInfo", "(JLjava/lang/String;)Landroid/content/om/OverlayableInfo;",
+         (void*)NativeGetOverlayableInfo},
+        {"nativeDefinesOverlayable", "(J)Z", (void*)NativeDefinesOverlayable},
 };
 
 int register_android_content_res_ApkAssets(JNIEnv* env) {
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index cb97698..939a0e4 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -243,6 +243,23 @@
     }
 }
 
+static void nativeGetRuntimeSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jint deviceId,
+                                    jobject sensorList) {
+    SensorManager *mgr = reinterpret_cast<SensorManager *>(sensorManager);
+    const ListOffsets &listOffsets(gListOffsets);
+
+    Vector<Sensor> nativeList;
+
+    mgr->getRuntimeSensorList(deviceId, nativeList);
+
+    ALOGI("DYNS native SensorManager.getRuntimeSensorList return %zu sensors", nativeList.size());
+    for (size_t i = 0; i < nativeList.size(); ++i) {
+        jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]);
+        // add to list
+        env->CallBooleanMethod(sensorList, listOffsets.add, sensor);
+    }
+}
+
 static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) {
     SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
     return mgr->isDataInjectionEnabled();
@@ -503,40 +520,26 @@
 //----------------------------------------------------------------------------
 
 static const JNINativeMethod gSystemSensorManagerMethods[] = {
-    {"nativeClassInit",
-            "()V",
-            (void*)nativeClassInit },
-    {"nativeCreate",
-             "(Ljava/lang/String;)J",
-             (void*)nativeCreate },
+        {"nativeClassInit", "()V", (void *)nativeClassInit},
+        {"nativeCreate", "(Ljava/lang/String;)J", (void *)nativeCreate},
 
-    {"nativeGetSensorAtIndex",
-            "(JLandroid/hardware/Sensor;I)Z",
-            (void*)nativeGetSensorAtIndex },
+        {"nativeGetSensorAtIndex", "(JLandroid/hardware/Sensor;I)Z",
+         (void *)nativeGetSensorAtIndex},
 
-    {"nativeGetDynamicSensors",
-            "(JLjava/util/List;)V",
-            (void*)nativeGetDynamicSensors },
+        {"nativeGetDynamicSensors", "(JLjava/util/List;)V", (void *)nativeGetDynamicSensors},
 
-    {"nativeIsDataInjectionEnabled",
-            "(J)Z",
-            (void*)nativeIsDataInjectionEnabled },
+        {"nativeGetRuntimeSensors", "(JILjava/util/List;)V", (void *)nativeGetRuntimeSensors},
 
-    {"nativeCreateDirectChannel",
-            "(JJIILandroid/hardware/HardwareBuffer;)I",
-            (void*)nativeCreateDirectChannel },
+        {"nativeIsDataInjectionEnabled", "(J)Z", (void *)nativeIsDataInjectionEnabled},
 
-    {"nativeDestroyDirectChannel",
-            "(JI)V",
-            (void*)nativeDestroyDirectChannel },
+        {"nativeCreateDirectChannel", "(JJIILandroid/hardware/HardwareBuffer;)I",
+         (void *)nativeCreateDirectChannel},
 
-    {"nativeConfigDirectChannel",
-            "(JIII)I",
-            (void*)nativeConfigDirectChannel },
+        {"nativeDestroyDirectChannel", "(JI)V", (void *)nativeDestroyDirectChannel},
 
-    {"nativeSetOperationParameter",
-            "(JII[F[I)I",
-            (void*)nativeSetOperationParameter },
+        {"nativeConfigDirectChannel", "(JIII)I", (void *)nativeConfigDirectChannel},
+
+        {"nativeSetOperationParameter", "(JII[F[I)I", (void *)nativeSetOperationParameter},
 };
 
 static const JNINativeMethod gBaseEventQueueMethods[] = {
diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp
index 03432e9..7f630cb 100644
--- a/core/jni/android_hardware_display_DisplayViewport.cpp
+++ b/core/jni/android_hardware_display_DisplayViewport.cpp
@@ -61,7 +61,8 @@
 
     viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId);
     viewport->isActive = env->GetBooleanField(viewportObj, gDisplayViewportClassInfo.isActive);
-    viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
+    jint orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation);
+    viewport->orientation = static_cast<ui::Rotation>(orientation);
     viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth);
     viewport->deviceHeight = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceHeight);
 
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 80df0ea..403c583 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -763,7 +763,12 @@
 
 static jint android_view_MotionEvent_nativeGetSurfaceRotation(jlong nativePtr) {
     MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
-    return jint(event->getSurfaceRotation());
+    auto rotation = event->getSurfaceRotation();
+    if (rotation) {
+        return static_cast<jint>(rotation.value());
+    } else {
+        return -1;
+    }
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 5a0a84b..2c5386d 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -129,6 +129,7 @@
     jfieldID appVsyncOffsetNanos;
     jfieldID presentationDeadlineNanos;
     jfieldID group;
+    jfieldID supportedHdrTypes;
 } gDisplayModeClassInfo;
 
 // Implements SkMallocPixelRef::ReleaseProc, to delete the screenshot on unref.
@@ -1130,6 +1131,16 @@
     env->SetLongField(object, gDisplayModeClassInfo.presentationDeadlineNanos,
                       config.presentationDeadline);
     env->SetIntField(object, gDisplayModeClassInfo.group, config.group);
+
+    const auto& types = config.supportedHdrTypes;
+    std::vector<jint> intTypes;
+    for (auto type : types) {
+        intTypes.push_back(static_cast<jint>(type));
+    }
+    auto typesArray = env->NewIntArray(types.size());
+    env->SetIntArrayRegion(typesArray, 0, intTypes.size(), intTypes.data());
+    env->SetObjectField(object, gDisplayModeClassInfo.supportedHdrTypes, typesArray);
+
     return object;
 }
 
@@ -2191,6 +2202,8 @@
     gDisplayModeClassInfo.presentationDeadlineNanos =
             GetFieldIDOrDie(env, modeClazz, "presentationDeadlineNanos", "J");
     gDisplayModeClassInfo.group = GetFieldIDOrDie(env, modeClazz, "group", "I");
+    gDisplayModeClassInfo.supportedHdrTypes =
+            GetFieldIDOrDie(env, modeClazz, "supportedHdrTypes", "[I");
 
     jclass frameStatsClazz = FindClassOrDie(env, "android/view/FrameStats");
     jfieldID undefined_time_nano_field = GetStaticFieldIDOrDie(env,
diff --git a/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
new file mode 100644
index 0000000..bba1760
--- /dev/null
+++ b/core/jni/com_android_internal_content_om_OverlayManagerImpl.cpp
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <dlfcn.h>
+
+#include <optional>
+
+#define LOG_TAG "OverlayManagerImpl"
+
+#include "android-base/no_destructor.h"
+#include "androidfw/ResourceTypes.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+
+namespace android {
+
+static struct fabricated_overlay_internal_offsets_t {
+    jclass classObject;
+    jfieldID packageName;
+    jfieldID overlayName;
+    jfieldID targetPackageName;
+    jfieldID targetOverlayable;
+    jfieldID entries;
+} gFabricatedOverlayInternalOffsets;
+
+static struct fabricated_overlay_internal_entry_offsets_t {
+    jclass classObject;
+    jfieldID resourceName;
+    jfieldID dataType;
+    jfieldID data;
+    jfieldID stringData;
+    jfieldID binaryData;
+    jfieldID configuration;
+} gFabricatedOverlayInternalEntryOffsets;
+
+static struct parcel_file_descriptor_offsets_t {
+    jclass classObject;
+    jmethodID getFd;
+} gParcelFileDescriptorOffsets;
+
+static struct List_offsets_t {
+    jclass classObject;
+    jmethodID size;
+    jmethodID get;
+} gListOffsets;
+
+static struct fabricated_overlay_info_offsets_t {
+    jclass classObject;
+    jmethodID constructor;
+    jfieldID packageName;
+    jfieldID overlayName;
+    jfieldID targetPackageName;
+    jfieldID targetOverlayable;
+    jfieldID path;
+} gFabricatedOverlayInfoOffsets;
+
+namespace self_targeting {
+
+constexpr const char kIOException[] = "java/io/IOException";
+constexpr const char IllegalArgumentException[] = "java/lang/IllegalArgumentException";
+
+class DynamicLibraryLoader {
+public:
+    explicit DynamicLibraryLoader(JNIEnv* env) {
+        /* For SelfTargeting, there are 2 types of files to be handled. One is frro and the other is
+         * idmap. For creating frro/idmap files and reading frro files, it needs libandroid_runtime
+         * to do a shared link to libidmap2. However, libidmap2 contains the codes generated from
+         * google protocol buffer. When libandroid_runtime does a shared link to libidmap2, it will
+         * impact the memory for system_server and zygote(a.k.a. all applications).
+         *
+         * Not all applications need to either create/read frro files or create idmap files all the
+         * time. When the apps apply the SelfTargeting overlay effect, it only needs libandroifw
+         * that is loaded. To use dlopen(libidmap2.so) is to make sure that applications don't
+         * impact themselves' memory by loading libidmap2 until they need to create/read frro files
+         * or create idmap files.
+         */
+        handle_ = dlopen("libidmap2.so", RTLD_NOW);
+        if (handle_ == nullptr) {
+            jniThrowNullPointerException(env);
+            return;
+        }
+
+        createIdmapFileFuncPtr_ =
+                reinterpret_cast<CreateIdmapFileFunc>(dlsym(handle_, "CreateIdmapFile"));
+        if (createIdmapFileFuncPtr_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol CreateIdmapFile is not found.");
+            return;
+        }
+        getFabricatedOverlayInfoFuncPtr_ = reinterpret_cast<GetFabricatedOverlayInfoFunc>(
+                dlsym(handle_, "GetFabricatedOverlayInfo"));
+        if (getFabricatedOverlayInfoFuncPtr_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol GetFabricatedOverlayInfo is not found.");
+            return;
+        }
+        createFrroFile_ = reinterpret_cast<CreateFrroFileFunc>(dlsym(handle_, "CreateFrroFile"));
+        if (createFrroFile_ == nullptr) {
+            jniThrowNullPointerException(env, "The symbol CreateFrroFile is not found.");
+            return;
+        }
+    }
+
+    bool callCreateFrroFile(std::string& out_error, const std::string& packageName,
+                            const std::string& overlayName, const std::string& targetPackageName,
+                            const std::optional<std::string>& targetOverlayable,
+                            const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+                            const std::string& frro_file_path) {
+        return createFrroFile_(out_error, packageName, overlayName, targetPackageName,
+                               targetOverlayable, entries_params, frro_file_path);
+    }
+
+    bool callCreateIdmapFile(std::string& out_error, const std::string& targetPath,
+                             const std::string& overlayPath, const std::string& idmapPath,
+                             const std::string& overlayName, const bool isSystem,
+                             const bool isVendor, const bool isProduct,
+                             const bool isTargetSignature, const bool isOdm, const bool isOem) {
+        return createIdmapFileFuncPtr_(out_error, targetPath, overlayPath, idmapPath, overlayName,
+                                       isSystem, isVendor, isProduct, isTargetSignature, isOdm,
+                                       isOem);
+    }
+
+    bool callGetFabricatedOverlayInfo(std::string& out_error, const std::string& overlay_path,
+                                      OverlayManifestInfo& out_overlay_manifest_info) {
+        return getFabricatedOverlayInfoFuncPtr_(out_error, overlay_path, out_overlay_manifest_info);
+    }
+
+    explicit operator bool() const {
+        return handle_ != nullptr && createFrroFile_ != nullptr &&
+                createIdmapFileFuncPtr_ != nullptr && getFabricatedOverlayInfoFuncPtr_ != nullptr;
+    }
+
+    DynamicLibraryLoader(const DynamicLibraryLoader&) = delete;
+
+    DynamicLibraryLoader& operator=(const DynamicLibraryLoader&) = delete;
+
+    ~DynamicLibraryLoader() {
+        if (handle_ != nullptr) {
+            dlclose(handle_);
+        }
+    }
+
+private:
+    typedef bool (*CreateFrroFileFunc)(
+            std::string& out_error, const std::string& packageName, const std::string& overlayName,
+            const std::string& targetPackageName,
+            const std::optional<std::string>& targetOverlayable,
+            const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+            const std::string& frro_file_path);
+
+    typedef bool (*CreateIdmapFileFunc)(std::string& out_error, const std::string& targetPath,
+                                        const std::string& overlayPath,
+                                        const std::string& idmapPath,
+                                        const std::string& overlayName, const jboolean isSystem,
+                                        const jboolean isVendor, const jboolean isProduct,
+                                        const jboolean isSameWithTargetSignature,
+                                        const jboolean isOdm, const jboolean isOem);
+
+    typedef bool (*GetFabricatedOverlayInfoFunc)(std::string& out_error,
+                                                 const std::string& overlay_path,
+                                                 OverlayManifestInfo& out_overlay_manifest_info);
+
+    void* handle_;
+    CreateFrroFileFunc createFrroFile_;
+    CreateIdmapFileFunc createIdmapFileFuncPtr_;
+    GetFabricatedOverlayInfoFunc getFabricatedOverlayInfoFuncPtr_;
+};
+
+static DynamicLibraryLoader& EnsureDynamicLibraryLoader(JNIEnv* env) {
+    static android::base::NoDestructor<DynamicLibraryLoader> loader(env);
+    return *loader;
+}
+
+static std::optional<std::string> getNullableString(JNIEnv* env, jobject object, jfieldID field) {
+    auto javaString = reinterpret_cast<jstring>(env->GetObjectField(object, field));
+    if (javaString == nullptr) {
+        return std::nullopt;
+    }
+
+    const ScopedUtfChars result(env, javaString);
+    if (result.c_str() == nullptr) {
+        return std::nullopt;
+    }
+
+    return std::optional<std::string>{result.c_str()};
+}
+
+static std::optional<android::base::borrowed_fd> getNullableFileDescriptor(JNIEnv* env,
+                                                                           jobject object,
+                                                                           jfieldID field) {
+    auto binaryData = env->GetObjectField(object, field);
+    if (binaryData == nullptr) {
+        return std::nullopt;
+    }
+
+    return env->CallIntMethod(binaryData, gParcelFileDescriptorOffsets.getFd);
+}
+
+static void CreateFrroFile(JNIEnv* env, jclass /*clazz*/, jstring jsFrroFilePath, jobject overlay) {
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        jniThrowNullPointerException(env, "libidmap2 is not loaded");
+        return;
+    }
+
+    if (overlay == nullptr) {
+        jniThrowNullPointerException(env, "overlay is null");
+        return;
+    }
+    auto jsPackageName =
+            (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.packageName);
+    const ScopedUtfChars packageName(env, jsPackageName);
+    if (packageName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "packageName is null");
+        return;
+    }
+    auto jsOverlayName =
+            (jstring)env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.overlayName);
+    const ScopedUtfChars overlayName(env, jsOverlayName);
+    if (overlayName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayName is null");
+        return;
+    }
+    auto jsTargetPackageName =
+            (jstring)env->GetObjectField(overlay,
+                                         gFabricatedOverlayInternalOffsets.targetPackageName);
+    const ScopedUtfChars targetPackageName(env, jsTargetPackageName);
+    if (targetPackageName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "targetPackageName is null");
+        return;
+    }
+    auto overlayable =
+            getNullableString(env, overlay, gFabricatedOverlayInternalOffsets.targetOverlayable);
+    const ScopedUtfChars frroFilePath(env, jsFrroFilePath);
+    if (frroFilePath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "frroFilePath is null");
+        return;
+    }
+    jobject entries = env->GetObjectField(overlay, gFabricatedOverlayInternalOffsets.entries);
+    if (entries == nullptr) {
+        jniThrowNullPointerException(env, "overlay entries is null");
+        return;
+    }
+    const jint size = env->CallIntMethod(entries, gListOffsets.size);
+    ALOGV("frroFilePath = %s, packageName = %s, overlayName = %s, targetPackageName = %s,"
+          " targetOverlayable = %s, size = %d",
+          frroFilePath.c_str(), packageName.c_str(), overlayName.c_str(), targetPackageName.c_str(),
+          overlayable.value_or(std::string()).c_str(), size);
+
+    std::vector<FabricatedOverlayEntryParameters> entries_params;
+    for (jint i = 0; i < size; i++) {
+        jobject entry = env->CallObjectMethod(entries, gListOffsets.get, i);
+        auto jsResourceName = reinterpret_cast<jstring>(
+                env->GetObjectField(entry, gFabricatedOverlayInternalEntryOffsets.resourceName));
+        const ScopedUtfChars resourceName(env, jsResourceName);
+        const auto dataType =
+                env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.dataType);
+
+        // In Java, the data type is int but the maximum value of data Type is less than 0xff.
+        if (dataType >= UCHAR_MAX) {
+            jniThrowException(env, IllegalArgumentException, "Unsupported data type");
+            return;
+        }
+
+        const auto data = env->GetIntField(entry, gFabricatedOverlayInternalEntryOffsets.data);
+        auto configuration =
+                getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.configuration);
+        auto string_data =
+                getNullableString(env, entry, gFabricatedOverlayInternalEntryOffsets.stringData);
+        auto binary_data =
+                getNullableFileDescriptor(env, entry,
+                                          gFabricatedOverlayInternalEntryOffsets.binaryData);
+        entries_params.push_back(
+                FabricatedOverlayEntryParameters{resourceName.c_str(), (DataType)dataType,
+                                                 (DataValue)data,
+                                                 string_data.value_or(std::string()), binary_data,
+                                                 configuration.value_or(std::string())});
+        ALOGV("resourceName = %s, dataType = 0x%08x, data = 0x%08x, dataString = %s,"
+              " binaryData = %d, configuration = %s",
+              resourceName.c_str(), dataType, data, string_data.value_or(std::string()).c_str(),
+              binary_data.has_value(), configuration.value_or(std::string()).c_str());
+    }
+
+    std::string err_result;
+    if (!dlLoader.callCreateFrroFile(err_result, packageName.c_str(), overlayName.c_str(),
+                                     targetPackageName.c_str(), overlayable, entries_params,
+                                     frroFilePath.c_str())) {
+        jniThrowException(env, IllegalArgumentException, err_result.c_str());
+        return;
+    }
+}
+
+static void CreateIdmapFile(JNIEnv* env, jclass /* clazz */, jstring jsTargetPath,
+                            jstring jsOverlayPath, jstring jsIdmapPath, jstring jsOverlayName,
+                            jboolean isSystem, jboolean isVendor, jboolean isProduct,
+                            jboolean isTargetSignature, jboolean isOdm, jboolean isOem) {
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        jniThrowNullPointerException(env, "libidmap2 is not loaded");
+        return;
+    }
+
+    const ScopedUtfChars targetPath(env, jsTargetPath);
+    if (targetPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "targetPath is null");
+        return;
+    }
+    const ScopedUtfChars overlayPath(env, jsOverlayPath);
+    if (overlayPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayPath is null");
+        return;
+    }
+    const ScopedUtfChars idmapPath(env, jsIdmapPath);
+    if (idmapPath.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "idmapPath is null");
+        return;
+    }
+    const ScopedUtfChars overlayName(env, jsOverlayName);
+    if (overlayName.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlayName is null");
+        return;
+    }
+    ALOGV("target_path = %s, overlay_path = %s, idmap_path = %s, overlay_name = %s",
+          targetPath.c_str(), overlayPath.c_str(), idmapPath.c_str(), overlayName.c_str());
+
+    std::string err_result;
+    if (!dlLoader.callCreateIdmapFile(err_result, targetPath.c_str(), overlayPath.c_str(),
+                                      idmapPath.c_str(), overlayName.c_str(),
+                                      (isSystem == JNI_TRUE), (isVendor == JNI_TRUE),
+                                      (isProduct == JNI_TRUE), (isTargetSignature == JNI_TRUE),
+                                      (isOdm == JNI_TRUE), (isOem == JNI_TRUE))) {
+        jniThrowException(env, kIOException, err_result.c_str());
+        return;
+    }
+}
+
+static jobject GetFabricatedOverlayInfo(JNIEnv* env, jclass /* clazz */, jstring jsOverlayPath) {
+    const ScopedUtfChars overlay_path(env, jsOverlayPath);
+    if (overlay_path.c_str() == nullptr) {
+        jniThrowNullPointerException(env, "overlay_path is null");
+        return nullptr;
+    }
+    ALOGV("overlay_path = %s", overlay_path.c_str());
+
+    DynamicLibraryLoader& dlLoader = EnsureDynamicLibraryLoader(env);
+    if (!dlLoader) {
+        return nullptr;
+    }
+
+    std::string err_result;
+    OverlayManifestInfo overlay_manifest_info;
+    if (!dlLoader.callGetFabricatedOverlayInfo(err_result, overlay_path.c_str(),
+                                               overlay_manifest_info) != 0) {
+        jniThrowException(env, kIOException, err_result.c_str());
+        return nullptr;
+    }
+    jobject info = env->NewObject(gFabricatedOverlayInfoOffsets.classObject,
+                                  gFabricatedOverlayInfoOffsets.constructor);
+    jstring jsOverName = env->NewStringUTF(overlay_manifest_info.name.c_str());
+    jstring jsPackageName = env->NewStringUTF(overlay_manifest_info.package_name.c_str());
+    jstring jsTargetPackage = env->NewStringUTF(overlay_manifest_info.target_package.c_str());
+    jstring jsTargetOverlayable = env->NewStringUTF(overlay_manifest_info.target_name.c_str());
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.overlayName, jsOverName);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.packageName, jsPackageName);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetPackageName, jsTargetPackage);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.targetOverlayable, jsTargetOverlayable);
+    env->SetObjectField(info, gFabricatedOverlayInfoOffsets.path, jsOverlayPath);
+    return info;
+}
+
+} // namespace self_targeting
+
+// JNI registration.
+static const JNINativeMethod gOverlayManagerMethods[] = {
+        {"createFrroFile", "(Ljava/lang/String;Landroid/os/FabricatedOverlayInternal;)V",
+         reinterpret_cast<void*>(self_targeting::CreateFrroFile)},
+        {"createIdmapFile",
+         "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZZZZ)V",
+         reinterpret_cast<void*>(self_targeting::CreateIdmapFile)},
+        {"getFabricatedOverlayInfo", "(Ljava/lang/String;)Landroid/os/FabricatedOverlayInfo;",
+         reinterpret_cast<void*>(self_targeting::GetFabricatedOverlayInfo)},
+};
+
+int register_com_android_internal_content_om_OverlayManagerImpl(JNIEnv* env) {
+    jclass ListClass = FindClassOrDie(env, "java/util/List");
+    gListOffsets.classObject = MakeGlobalRefOrDie(env, ListClass);
+    gListOffsets.size = GetMethodIDOrDie(env, gListOffsets.classObject, "size", "()I");
+    gListOffsets.get =
+            GetMethodIDOrDie(env, gListOffsets.classObject, "get", "(I)Ljava/lang/Object;");
+
+    jclass fabricatedOverlayInternalClass =
+            FindClassOrDie(env, "android/os/FabricatedOverlayInternal");
+    gFabricatedOverlayInternalOffsets.classObject =
+            MakeGlobalRefOrDie(env, fabricatedOverlayInternalClass);
+    gFabricatedOverlayInternalOffsets.packageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "packageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.overlayName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "overlayName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.targetPackageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetPackageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.targetOverlayable =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "targetOverlayable",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalOffsets.entries =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalOffsets.classObject, "entries",
+                            "Ljava/util/List;");
+
+    jclass fabricatedOverlayInternalEntryClass =
+            FindClassOrDie(env, "android/os/FabricatedOverlayInternalEntry");
+    gFabricatedOverlayInternalEntryOffsets.classObject =
+            MakeGlobalRefOrDie(env, fabricatedOverlayInternalEntryClass);
+    gFabricatedOverlayInternalEntryOffsets.resourceName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "resourceName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalEntryOffsets.dataType =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "dataType",
+                            "I");
+    gFabricatedOverlayInternalEntryOffsets.data =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "data", "I");
+    gFabricatedOverlayInternalEntryOffsets.stringData =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "stringData",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInternalEntryOffsets.binaryData =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject, "binaryData",
+                            "Landroid/os/ParcelFileDescriptor;");
+    gFabricatedOverlayInternalEntryOffsets.configuration =
+            GetFieldIDOrDie(env, gFabricatedOverlayInternalEntryOffsets.classObject,
+                            "configuration", "Ljava/lang/String;");
+
+    jclass parcelFileDescriptorClass =
+            android::FindClassOrDie(env, "android/os/ParcelFileDescriptor");
+    gParcelFileDescriptorOffsets.classObject = MakeGlobalRefOrDie(env, parcelFileDescriptorClass);
+    gParcelFileDescriptorOffsets.getFd =
+            GetMethodIDOrDie(env, gParcelFileDescriptorOffsets.classObject, "getFd", "()I");
+
+    jclass fabricatedOverlayInfoClass = FindClassOrDie(env, "android/os/FabricatedOverlayInfo");
+    gFabricatedOverlayInfoOffsets.classObject = MakeGlobalRefOrDie(env, fabricatedOverlayInfoClass);
+    gFabricatedOverlayInfoOffsets.constructor =
+            GetMethodIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "<init>", "()V");
+    gFabricatedOverlayInfoOffsets.packageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "packageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.overlayName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "overlayName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.targetPackageName =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetPackageName",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.targetOverlayable =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "targetOverlayable",
+                            "Ljava/lang/String;");
+    gFabricatedOverlayInfoOffsets.path =
+            GetFieldIDOrDie(env, gFabricatedOverlayInfoOffsets.classObject, "path",
+                            "Ljava/lang/String;");
+
+    return RegisterMethodsOrDie(env, "com/android/internal/content/om/OverlayManagerImpl",
+                                gOverlayManagerMethods, NELEM(gOverlayManagerMethods));
+}
+
+} // namespace android
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 285258a..556636dd 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -88,6 +88,7 @@
         optional SettingProto odi_captions_volume_ui_enabled = 42 [ (android.privacy).dest = DEST_AUTOMATIC ];
         // Setting for accessibility magnification for following typing.
         optional SettingProto accessibility_magnification_follow_typing_enabled = 43 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto contrast_level = 44 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Accessibility accessibility = 2;
 
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 4650000..18d84d5 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -457,6 +457,7 @@
         optional bool stop_if_killed = 3;
         optional bool call_start = 4;
         optional int32 last_start_id = 5;
+        optional int32 start_command_result = 6;
     }
     optional Start start = 19;
 
@@ -499,7 +500,21 @@
     repeated ConnectionRecordProto connections = 26;
 
     optional bool allow_while_in_use_permission_in_fgs = 27;
-    // Next Tag: 28
+
+    message ShortFgsInfo {
+        option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+        optional int64 start_time = 1;
+        optional int32 start_foreground_count = 2;
+        optional int32 start_id = 3;
+        optional int64 timeout_time = 4;
+        optional int64 proc_state_demote_time = 5;
+        optional int64 anr_time = 6;
+    }
+
+    optional ShortFgsInfo short_fgs_info = 28;
+
+    // Next Tag: 29
 }
 
 message ConnectionRecordProto {
@@ -977,12 +992,11 @@
         optional int32 profile = 2;
     }
     repeated UserProfile user_profile_group_ids = 4;
-    repeated int32 visible_users_array = 5;
 
     // current_user contains the id of the current user, while current_profiles contains the ids of
     // both the current user and its profiles (if any)
-    optional int32 current_user = 6;
-    repeated int32 current_profiles = 7;
+    optional int32 current_user = 5;
+    repeated int32 current_profiles = 6;
 }
 
 // sync with com.android.server.am.AppTimeTracker.java
diff --git a/core/proto/android/service/usb.proto b/core/proto/android/service/usb.proto
index df5e0a9..607fd10 100644
--- a/core/proto/android/service/usb.proto
+++ b/core/proto/android/service/usb.proto
@@ -240,6 +240,7 @@
     // ID of the port. A device (eg: Chromebooks) might have multiple ports.
     optional string id = 1;
     repeated Mode supported_modes = 2;
+    optional bool supports_compliance_warnings = 3;
 }
 
 message UsbPortStatusProto {
@@ -268,6 +269,7 @@
     optional string usb_data_status = 7;
     optional bool is_power_transfer_limited = 8;
     optional string usb_power_brick_status = 9;
+    optional string compliance_warnings_string = 10;
 }
 
 message UsbPortStatusRoleCombinationProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5a7abcc..8da91ee 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -293,6 +293,7 @@
 
     <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
+    <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_COMPLIANCE_CHANGED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_HANDSHAKE" />
@@ -6285,13 +6286,22 @@
         android:protectionLevel="normal|instant" />
 
     <!-- Allows a regular application to use {@link android.app.Service#startForeground
+         Service.startForeground} with the type "fileManagement".
+         <p>Protection level: normal|instant
+    -->
+    <permission android:name="android.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT"
+        android:description="@string/permdesc_foregroundServiceFileManagement"
+        android:label="@string/permlab_foregroundServiceFileManagement"
+        android:protectionLevel="normal|instant" />
+
+    <!-- Allows a regular application to use {@link android.app.Service#startForeground
          Service.startForeground} with the type "specialUse".
-         <p>Protection level: signature|appop|instant
+         <p>Protection level: normal|appop|instant
     -->
     <permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE"
         android:description="@string/permdesc_foregroundServiceSpecialUse"
         android:label="@string/permlab_foregroundServiceSpecialUse"
-        android:protectionLevel="signature|appop|instant" />
+        android:protectionLevel="normal|appop|instant" />
 
     <!-- @SystemApi Allows to access all app shortcuts.
          @hide -->
@@ -7290,6 +7300,10 @@
                  android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
+        <service android:name="com.android.server.pm.GentleUpdateHelper$Service"
+            android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
         <service
                 android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
diff --git a/core/res/OWNERS b/core/res/OWNERS
index 6d05e07..a2ef400 100644
--- a/core/res/OWNERS
+++ b/core/res/OWNERS
@@ -8,7 +8,6 @@
 hackbod@google.com
 ilyamaty@google.com
 jaggies@google.com
-jdemeulenaere@google.com
 jsharkey@android.com
 jsharkey@google.com
 juliacr@google.com
diff --git a/core/res/res/layout-watch/alert_dialog_progress_material.xml b/core/res/res/layout-watch/alert_dialog_progress_material.xml
new file mode 100644
index 0000000..686156c
--- /dev/null
+++ b/core/res/res/layout-watch/alert_dialog_progress_material.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="match_parent"
+    android:paddingStart="?attr/dialogPreferredPadding"
+    android:paddingTop="@dimen/dialog_padding_top_material"
+    android:paddingEnd="?attr/dialogPreferredPadding"
+    android:paddingBottom="@dimen/dialog_padding_top_material">
+    <TextView
+        android:id="@+id/progress_dialog_message"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_centerInParent="true"
+        style="@style/ProgressDialogMessage" />
+    <ProgressBar
+        android:id="@+id/progress"
+        style="?attr/progressBarStyleHorizontal"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true" />
+    <TextView
+        android:id="@+id/progress_percent"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentStart="true"
+        android:layout_below="@id/progress" />
+    <TextView
+        android:id="@+id/progress_number"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_alignParentEnd="true"
+        android:layout_below="@id/progress" />
+</RelativeLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 3ad6dc3..f5e3009 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Stemboodskap"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Verbindingsprobleem of ongeldige MMI-kode."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Kenmerk word nie gesteun nie."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Bewerking is beperk tot belbeperking-nommers."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Kan oproep-aanstuurinstellings nie van jou foon af verander tewyl jy swerf nie."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Diens is geaktiveer."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Laat die program toe om dele van ditself deurdringend in die geheue te hou. Dit kan geheue wat aan ander programme beskikbaar is, beperk, en die foon stadiger maak."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"laat loop voorgronddiens"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Laat die program toe om van voorgronddienste gebruik te maak."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"gebruik voorgronddienstipe “kamera”"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Laat die app toe om die voorgronddienstipe “kamera” te gebruik"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"gebruik voorgronddienstipe “gekoppelde toestel”"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Laat die app toe om die voorgronddienstipe “gekoppelde toestel” te gebruik"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"gebruik voorgronddienstipe “datasinkronisering”"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Laat die app toe om die voorgronddienstipe “datasinkronisering” te gebruik"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"gebruik voorgronddienstipe “ligging”"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Laat die app toe om die voorgronddienstipe “ligging” te gebruik"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"gebruik voorgronddienstipe “mediaterugspeel”"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Laat die app toe om die voorgronddienstipe “mediaterugspeel” te gebruik"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"gebruik voorgronddienstipe “mediaprojeksie”"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Laat die app toe om die voorgronddienstipe “mediaprojeksie” te gebruik"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"gebruik voorgronddienstipe “mikrofoon”"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Laat die app toe om die voorgronddienstipe “mikrofoon” te gebruik"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"gebruik voorgronddienstipe “foonoproep”"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Laat die app toe om die voorgronddienstipe “foonoproep” te gebruik"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"gebruik voorgronddienstipe “gesondheid”"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Laat die app toe om die voorgronddienstipe “gesondheid” te gebruik"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"gebruik voorgronddienstipe “afstandboodskappe”"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Laat die app toe om die voorgronddienstipe “afstandboodskappe” te gebruik"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"gebruik voorgronddienstipe “stelselvrystelling”"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Laat die app toe om die voorgronddienstipe “stelselvrystelling” te gebruik"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"gebruik voorgronddienstipe “spesiale gebruik”"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Laat die app toe om die voorgronddienstipe “spesiale gebruik” te gebruik"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"meet programberging-ruimte"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Laat die program toe om sy kode, data en kasgroottes op te haal"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"verander stelsel-instellings"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Hierdie die program kan oudio met die mikrofoon opneem terwyl die program gebruik word."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"neem oudio op die agtergrond op"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Hierdie program kan enige tyd oudio met die mikrofoon opneem."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"bespeur skermskote van appvensters"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Hierdie app sal ingelig word as ’n skermskoot geneem word terwyl die app gebruik word."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"stuur bevele na die SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Laat die program toe om bevele na die SIM te stuur. Dit is baie gevaarlik."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"herken fisieke aktiwiteit"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan nie toegang tot die foon se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan nie toegang tot die tablet se kamera op jou <xliff:g id="DEVICE">%1$s</xliff:g> kry nie"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Jy kan nie toegang hiertoe kry terwyl daar gestroom word nie. Probeer eerder op jou foon."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan nie prent-in-prent sien terwyl jy stroom nie"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Stelselverstek"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9a3cfd0..305cefa 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -28,6 +28,8 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"የድምፅ መልዕክት"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"የተያያዥ ችግር ወይም  ትክከል ያልሆነየMMI ኮድ ባህሪ።"</string>
+    <!-- no translation found for mmiErrorNotSupported (5001803469335286099) -->
+    <skip />
     <string name="mmiFdnError" msgid="3975490266767565852">"ክዋኔ ለቋሚ መደወያ ቁጥሮች ብቻ ተገድቧል።"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Can not change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"አገልግሎት ነቅቶ ነበር።"</string>
@@ -395,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"መተግበሪያው የራሱን ክፍሎች በማህደረ ትውስታ ውስጥ በቋሚነት የሚቀጥሉ እንዲያደርግ ይፈቅድለታል። ይህ ለሌላ መተግበሪያዎች ያለውን ማህደረ ትውስታ በመገደብ ስልኩን ያንቀራፍፈዋል።"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"የፊት አገልግሎትን ማሄድ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"መተግበሪያው ፊት ላይ ያሉ አገልግሎቶችን እንዲጠቀም ያስችለዋል።"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"የፊት አገልግሎትን በ«ካሜራ» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"መተግበሪያው የፊት አገልግሎትን በ«ካሜራ» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"የፊት አገልግሎትን በ«connectedDevice» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"መተግበሪያው የፊት አገልግሎትን በ«connectedDevice» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"የፊት አገልግሎትን በ«dataSync» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"መተግበሪያው የፊት አገልግሎትን በ«dataSync» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"የፊት አገልግሎትን በ«አካባቢ» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"መተግበሪያው የፊት አገልግሎትን በ«አካባቢ» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"የፊት አገልግሎትን በ«mediaPlayback» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"መተግበሪያው የፊት አገልግሎትን በ«mediaPlayback» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"የፊት አገልግሎትን በ«mediaProjection» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"መተግበሪያው የፊት አገልግሎትን በ«mediaProjection» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"የፊት አገልግሎትን በ«ማይክሮፎን» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"መተግበሪያው የፊት አገልግሎትን በ«ማይክሮፎን» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"የፊት አገልግሎትን በ«phoneCall» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"መተግበሪያው የፊት አገልግሎትን በ«phoneCall» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"የፊት አገልግሎትን በ«ጤና» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"መተግበሪያው የፊት አገልግሎትን በ«ጤና» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"የፊት አገልግሎትን በ«remoteMessaging» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"መተግበሪያው የፊት አገልግሎትን በ«remoteMessaging» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"የፊት አገልግሎትን በ«systemExempted» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"መተግበሪያው የፊት አገልግሎትን በ«systemExempted» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"የፊት አገልግሎትን በ«specialUse» ዓይነት ማስሄድ"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"መተግበሪያው የፊት አገልግሎትን በ«specialUse» ዓይነት እንዲጠቀም ይፈቅዳል"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"የመተግበሪያ ማከማቻ ቦታ ለካ"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"የራሱን ኮድ ፣ውሂብ እና መሸጎጫ መጠኖች ሰርስሮ ለማውጣት ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"የስርዓት ቅንብሮችን አስተካክል"</string>
@@ -495,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ይህ መተግበሪያ መተግበሪያው ስራ ላይ ሳለ ማይክሮፎኑን በመጠቀም ኦዲዮን መቅዳት ይችላል።"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"በበስተጀርባ ኦዲዮን ይቅዱ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ይህ መተግበሪያ በማናቸውም ጊዜ ማይክራፎኑን በመጠቀም ኦዲዮን መቅዳት ይችላል።"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"የመተግበሪያ መስኮቶች የማያ ገጽ ቀረጻዎችን ማወቅ"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"መተግበሪያው በጥቅም ላይ ሳለ ቅጽበታዊ ገጽ እይታ ሲነሳ ይህ መተግበሪያ ማሳወቂያ ይደርሰዋል።"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ወደ ሲሙ ትዕዛዞችን መላክ"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"መተግበሪያው ትዕዛዞችን ወደ ሲሙ እንዲልክ ያስችለዋል። ይሄ በጣማ አደገኛ ነው።"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"አካላዊ እንቅስቃሴን ለይቶ ማወቅ"</string>
@@ -2342,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"የስልኩን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ጡባዊውን ካሜራ ከእርስዎ <xliff:g id="DEVICE">%1$s</xliff:g> መድረስ አይቻልም"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ዥረት በመልቀቅ ላይ ሳለ ይህ ሊደረስበት አይችልም። በምትኩ በስልክዎ ላይ ይሞክሩ።"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"በዥረት በመልቀቅ ወቅት በስዕል-ላይ-ስዕል ማየት አይችሉም"</string>
     <string name="system_locale_title" msgid="711882686834677268">"የሥርዓት ነባሪ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ካርድ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d142993..dc8ffda 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"البريد الصوتي"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"‏حدثت مشكلة في الاتصال أو أن رمز MMI غير صحيح."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"الميزة غير متاحة."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"تم تقييد التشغيل لأرقام الاتصال الثابت فقط."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"يتعذر تغيير إعدادات إعادة توجيه المكالمات من هاتفك أثناء التجوال."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"تم تفعيل الخدمة."</string>
@@ -399,54 +400,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"للسماح للتطبيق بجعل أجزاء منه ثابتة في الذاكرة. وقد يؤدي هذا إلى تقييد الذاكرة المتاحة للتطبيقات الأخرى مما يؤدي إلى حدوث بطء في الهاتف."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"تشغيل الخدمة في المقدمة"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"للسماح للتطبيق بالاستفادة من الخدمات التي تعمل في المقدمة."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"camera\"."</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"connectedDevice\"."</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"dataSync\"."</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"location\"."</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"mediaPlayback\"."</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"mediaProjection\"."</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"microphone\"."</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"phoneCall\"."</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"health\"."</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"remoteMessaging\"."</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"systemExempted\"."</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"‏تشغيل الخدمة التي تعمل في المقدّمة ذات النوع \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"‏يسمح هذا الإذن للتطبيق بالاستفادة من الخدمات التي تعمل في المقدّمة ذات النوع \"specialUse\"."</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"قياس مساحة تخزين التطبيق"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"للسماح للتطبيق باسترداد شفرته وبياناته وأحجام ذاكرات التخزين المؤقت"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"تعديل إعدادات النظام"</string>
@@ -499,10 +476,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"يمكن لهذا التطبيق تسجيل الصوت باستخدام الميكروفون عندما يكون التطبيق قيد الاستخدام."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"تسجيل الصوت في الخلفية"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"يمكن لهذا التطبيق تسجيل الصوت باستخدام الميكروفون في أي وقت."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"رصد لقطات الشاشة لنوافذ التطبيق"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"سيتم إشعار هذا التطبيق عند التقاط لقطة شاشة أثناء استخدام التطبيق."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"‏إرسال أوامر إلى شريحة SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"‏السماح للتطبيق بإرسال أوامر إلى شريحة SIM. وهذا أمر بالغ الخطورة."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"التعرّف على النشاط البدني"</string>
@@ -2346,8 +2321,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"يتعذّر الوصول إلى كاميرا الهاتف من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"يتعذّر الوصول إلى كاميرا الجهاز اللوحي من على جهاز <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"لا يمكن الوصول إلى هذا المحتوى أثناء البث. بدلاً من ذلك، جرِّب استخدام هاتفك."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"لا يمكن عرض نافذة ضمن النافذة أثناء البث."</string>
     <string name="system_locale_title" msgid="711882686834677268">"الإعداد التلقائي للنظام"</string>
     <string name="default_card_name" msgid="9198284935962911468">"‏رقم البطاقة ‎<xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 2d740ec..8f2e3f2 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ভইচমেইল"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"সংযোগৰ সমস্যা বা MMI ক\'ড মান্য নহয়।"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"সুবিধাটো সমৰ্থিত নহয়।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"কেৱল ফিক্সড ডায়েলিং নম্বৰৰ বাবে কার্য সীমাবদ্ধ কৰা হৈছে।"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"আপুনি ৰ\'মিঙত থকাৰ সময়ত কল ফৰৱাৰ্ডিঙৰ ছেটিং সলনি কৰিব নোৱাৰি।"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"সেৱা সক্ষম কৰা হ’ল।"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"মেম\'ৰিত নিজৰ বাবে প্ৰয়োজনীয় ঠাই পৃথক কৰিবলৈ এপক অনুমতি দিয়ে। এই কার্যই ফ\'নৰ কার্যক লেহেমীয়া কৰি অন্য এপবোৰৰ বাবে উপলব্ধ মেম\'ৰিক সীমাবদ্ধ কৰে।"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"অগ্ৰভূমিৰ সেৱা চলাব পাৰে"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"এপ্‌টোক অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে।"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"কেমেৰা\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"এপ্‌টোক \"কেমেৰা\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"এপ্‌টোক \"connectedDevice\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"এপ্‌টোক \"dataSync\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"অৱস্থান\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"এপ্‌টোক \"অৱস্থান\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"এপ্‌টোক \"mediaPlayback\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"এপ্‌টোক \"mediaProjection\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"মাইক্ৰ’ফ’ন\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"এপ্‌টোক \"মাইক্ৰ’ফ’ন\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"এপ্‌টোক \"phoneCall\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"স্বাস্থ্য\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"এপ্‌টোক \"স্বাস্থ্য\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"এপ্‌টোক \"remoteMessaging\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"কেমেৰা\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"এপ্‌টোক \"systemExempted\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ চলাওক"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"এপ্‌টোক \"specialUse\" সম্পৰ্কীয় অগ্ৰভূমি সেৱাসমূহ ব্যৱহাৰ কৰিবলৈ অনুমতি দিয়ে"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"এপৰ ষ্ট’ৰেজৰ খালী ঠাই হিচাপ কৰক"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"এপ্‌টোক ইয়াৰ ক\'ড, ডেটা আৰু কেশ্বৰ আকাৰ বিচাৰি উলিয়াবলৈ অনুমতি দিয়ে"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ছিষ্টেম ছেটিংহ সংশোধন কৰক"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"এই এপ্‌টোৱে ইয়াক ব্যৱহাৰ কৰি থাকোঁতে মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰি অডিঅ’ ৰেকর্ড কৰিব পাৰে।"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"নেপথ্যত অডিঅ’ ৰেকৰ্ড কৰক"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"এই এপ্‌টোৱে যিকোনো সময়তে মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰি অডিঅ’ ৰেকৰ্ড কৰিব পাৰে।"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"এপৰ ৱিণ্ড’সমূহৰ স্ক্ৰীনৰ ফট’ তোলাটো চিনাক্ত কৰক"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"এই এপ্‌টো ব্যৱহাৰ হৈ থকাৰ সময়ত কোনো স্ক্ৰীনশ্বট ল’লে, ইয়াক জনোৱা হয়।"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ছিমলৈ নিৰ্দেশ পঠিয়াব পাৰে"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ছিমলৈ নিৰ্দেশসমূহ প্ৰেৰণ কৰিবলৈ এপক অনুমতি দিয়ে। ই অতি ক্ষতিকাৰক।"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"শাৰীৰিক কাৰ্যকলাপ চিনাক্ত কৰক"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা ফ’নটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপোনাৰ <xliff:g id="DEVICE">%1$s</xliff:g>ৰ পৰা টেবলেটটোৰ কেমেৰা এক্সেছ কৰিব নোৱাৰি"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ষ্ট্ৰীম কৰি থকাৰ সময়ত এইটো এক্সেছ কৰিব নোৱাৰি। তাৰ পৰিৱৰ্তে আপোনাৰ ফ’নত চেষ্টা কৰি চাওক।"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ষ্ট্ৰীম কৰি থকাৰ সময়ত picture-in-picture চাব নোৱাৰি"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ছিষ্টেম ডিফ’ল্ট"</string>
     <string name="default_card_name" msgid="9198284935962911468">"কাৰ্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 772bbb4..292f51b3 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Səsli poçt"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Bağlantı problemi və ya yalnış MM kodu."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funksiya dəstəklənmir."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Əməliyyat yalnız sabit nömrələrə yığımla məhdudlaşıb."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Roaminqdə olarkən zəng yönləndirmə ayarlarını telefonunuzdan dəyişə bilməz."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Servis işə salındı."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Tətbiqə öz komponentlərini yaddaşda saxlama icazəsi verir. Bu digər tətbiqlər üçün mövcud olan yaddaşı limitləyə bilər."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ön fon xidmətindən istifadə edin"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Tətbiqə ön fon xidmətlərini işlətmək icazəsi verin."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"kamera\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Tətbiqə \"kamera\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Tətbiqə \"connectedDevice\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Tətbiqə \"dataSync\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"məkan\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Tətbiqə \"məkan\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Tətbiqə \"mediaPlayback\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Tətbiqə \"mediaProjection\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"mikrofon\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Tətbiqə \"mikrofon\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Tətbiqə \"phoneCall\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"sağlamlıq\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Tətbiqə \"sağlamlıq\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Tətbiqə \"remoteMessaging\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tətbiqə \"systemExempted\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" növü olan ön fon xidmətləri işlətmək"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tətbiqə \"specialUse\" növü olan ön fon xidmətlərini işlətmək icazəsi verir"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"tətbiq saxlama yaddaşını ölçmək"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Tətbiqə özünün kodunu, məlumatını və keş ölçüsünü alma icazəsi verir."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"Sistem ayarlarının dəyişdirilməsi"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Bu tətbiq istifadə edilən zaman mikrofondan istifadə edərək audio yaza bilər."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"arxa fonda audio yazmaq"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Bu tətbiq istənilən zaman mikrofondan istifadə edərək audio yaza bilər."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"tətbiq pəncərələrinin ekran şəkillərini aşkar edin"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Tətbiq istifadə edilərkən skrinşot çəkildikdə bu tətbiqə bildiriş göndəriləcək."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"əmrləri SIM\'ə göndərin"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Tətbiqə SIM-ə əmrlər göndərməyə imkan verir. Bu, çox təhlükəlidir."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziki fəaliyyəti tanıyın"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına giriş etmək olmur"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan planşetin kamerasına giriş etmək olmur"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Yayım zamanı buna giriş mümkün deyil. Telefonunuzda sınayın."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayım zamanı şəkildə şəkilə baxmaq mümkün deyil"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistem defoltu"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 13523f8..b1ccdf9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Glasovna pošta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problemi sa vezom ili nevažeći MMI kôd."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcija nije podržana."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Rad je ograničen samo na brojeve fiksnog biranja."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Ne možete da promenite podešavanja preusmeravanja poziva sa telefona dok ste u romingu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Usluga je omogućena."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori telefon."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"pokreni uslugu u prvom planu"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Dozvoljava aplikaciji da koristi usluge u prvom planu."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"pokretanje usluge u prvom planu koja pripada tipu „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"pokretanje usluge u prvom planu koja pripada tipu „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"pokretanje usluge u prvom planu koja pripada tipu „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"pokretanje usluge u prvom planu koja pripada tipu „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"pokretanje usluge u prvom planu koja pripada tipu „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"pokretanje usluge u prvom planu koja pripada tipu „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"pokretanje usluge u prvom planu koja pripada tipu „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"pokretanje usluge u prvom planu koja pripada tipu „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"pokretanje usluge u prvom planu koja pripada tipu „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"pokretanje usluge u prvom planu koja pripada tipu „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"pokretanje usluge u prvom planu koja pripada tipu „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokretanje usluge u prvom planu koja pripada tipu „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Dozvoljava aplikaciji da koristi usluge u prvom planu koje pripadaju tipu „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"merenje memorijskog prostora u aplikaciji"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Dozvoljava aplikaciji da preuzme veličine kôda, podataka i keša."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"izmena podešavanja sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ova aplikacija može da snima zvuk pomoću mikrofona dok se aplikacija koristi."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"da snima zvuk u pozadini"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ova aplikacija može da snima zvuk pomoću mikrofona u bilo kom trenutku."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"otkrivanje snimanja ekrana u prozorima aplikacija"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ako se tokom korišćenja ove aplikacije napravi snimak ekrana, aplikacija će dobiti obaveštenje."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi na SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji da šalje komande SIM kartici. To je veoma opasno."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičkih aktivnosti"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ne može da se pristupi kameri telefona sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ne može da se pristupi kameri tableta sa <xliff:g id="DEVICE">%1$s</xliff:g> uređaja"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete da pristupate tokom strimovanja. Probajte na telefonu."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ne možete da gledate sliku u slici pri strimovanju"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Podrazumevani sistemski"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index e2ee1f4..4cd558d 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Галасавая пошта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Праблема падлучэння ці няправільны код MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функцыя не падтрымліваецца."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Выкарыстанне абмежаванае толькі дазволенымі нумарамі."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Немагчыма змяніць налады пераадрасацыі выклікаў з тэлефона, пакуль вы знаходзіцеся ў роўмінгу."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Служба была ўключана."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Дазваляе прыкладанню захоўваць некаторыя пастаянныя часткi ў памяцi. Гэта можа абмежаваць аб\'ём памяці, даступнай для іншых прыкладанняў, i запаволiць працу тэлефона."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"запусціць актыўныя сэрвісы"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Дазваляе праграме выкарыстоўваць асноўныя сэрвісы."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"запуск актыўнага сэрвісу тыпу \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"запуск актыўнага сэрвісу тыпу \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"запуск актыўнага сэрвісу тыпу \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"запуск актыўнага сэрвісу тыпу \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"запуск актыўнага сэрвісу тыпу \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"запуск актыўнага сэрвісу тыпу \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"запуск актыўнага сэрвісу тыпу \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"запуск актыўнага сэрвісу тыпу \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"запуск актыўнага сэрвісу тыпу \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"запуск актыўнага сэрвісу тыпу \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"запуск актыўнага сэрвісу тыпу \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запуск актыўнага сэрвісу тыпу \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дазваляе праграме выкарыстоўваць актыўныя сэрвісы тыпу \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"вымерыць прастору для захоўвання прыкладання"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Дазваляе прыкладанням атрымліваць яго код, дадзеныя і аб\'ём кэш-памяці"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"змена сістэмных налад"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Гэта праграма падчас яе выкарыстання можа запісваць аўдыя з дапамогай мікрафона."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"запісваць аўдыя ў фонавым рэжыме"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Гэта праграма можа ў любы час запісваць аўдыя з дапамогай мікрафона."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"выяўляць здыманне экрана з вокнамі праграмы"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Калі ў час выкарыстання гэтай праграмы будзе зроблены здымак экрана, паявіцца апавяшчэнне."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"адпраўляць каманды на SIM-карту"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Дазваляе праграме адпраўляць каманды SIM-карце. Гэта вельмі небяспечна."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"распазнаваць фізічную актыўнасць"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не ўдалося атрымаць доступ да камеры тэлефона з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не ўдалося атрымаць доступ да камеры планшэта з прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\""</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Не ўдаецца атрымаць доступ у час перадачы плынню. Паспрабуйце скарыстаць тэлефон."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Падчас перадачы плынню прагляд у рэжыме \"Відарыс у відарысе\" немагчымы"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Стандартная сістэмная налада"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 0c56d0f..d39425b 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Гласова поща"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Има проблем с връзката или MMI кодът е невалиден."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функцията не се поддържа."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Операцията е ограничена само до фиксираните номера за набиране."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Докато сте в режим на роуминг, настройките за пренасочване на обажданията не могат да се променят от телефона ви."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Услугата бе активирана."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Разрешава на приложението да прави части от себе си постоянни в паметта. Това може да ограничи наличната за другите приложения, забавяйки телефона."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"изпълнение на услуги на преден план"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Разрешава на приложението да се възползва от услуги на преден план."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"изпълнение на услуги на преден план от тип camera"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Разрешава на приложението да се възползва от услуги на преден план от тип camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"изпълнение на услуги на преден план от тип connectedDevice"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Разрешава на приложението да се възползва от услуги на преден план от тип connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"изпълнение на услуги на преден план от тип dataSync"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Разрешава на приложението да се възползва от услуги на преден план от тип dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"изпълнение на услуги на преден план от тип location"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Разрешава на приложението да се възползва от услуги на преден план от тип location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"изпълнение на услуги на преден план от тип mediaPlayback"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Разрешава на приложението да се възползва от услуги на преден план от тип mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"изпълнение на услуги на преден план от тип mediaProjection"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Разрешава на приложението да се възползва от услуги на преден план от тип mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"изпълнение на услуги на преден план от тип microphone"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Разрешава на приложението да се възползва от услуги на преден план от тип microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"изпълнение на услуги на преден план от тип phoneCall"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Разрешава на приложението да се възползва от услуги на преден план от тип phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"изпълнение на услуги на преден план от тип health"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Разрешава на приложението да се възползва от услуги на преден план от тип health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"изпълнение на услуги на преден план от тип remoteMessaging"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Разрешава на приложението да се възползва от услуги на преден план от тип remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"изпълнение на услуги на преден план от тип systemExempted"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Разрешава на приложението да се възползва от услуги на преден план от тип systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"изпълнение на услуги на преден план от тип specialUse"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Разрешава на приложението да се възползва от услуги на преден план от тип specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"измерване на ползваното от приложението място в хранилището"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Разрешава на приложението да извлича размера на своя код, данни и кеш"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"промяна на системните настройки"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Когато се използва, това приложение може да записва аудио посредством микрофона."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"записва аудио на заден план"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Това приложение може по всяко време да записва аудио посредством микрофона."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"установяване на заснемания на екрана на прозорците на приложението"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Това приложение ще получава известия, когато по време на използването му бъде направена екранна снимка."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"изпращане на команди до SIM картата"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Разрешава на приложението да изпраща команди до SIM картата. Това е много опасно."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"разпознаване на физическата активност"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Няма достъп до камерата на телефона от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Няма достъп до камерата на таблета от вашия <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"До това съдържание не може да се осъществи достъп при поточно предаване. Вместо това опитайте от телефона си."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Функцията „Картина в картината“ не е налице при поточно предаване"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Стандартно за системата"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 4751df7..2836580 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ভয়েসমেল"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"সংযোগ সমস্যা বা অবৈধ MMI কোড৷"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ফিচার কাজ করে না।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"নির্দিষ্ট নম্বরে ডায়ালযোগ্য হিসেবে প্রক্রিয়াটি সীমিত করা হয়েছে৷"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"আপনি রোমিংয়ে থাকাকালীন আপনার ফোন থেকে \'কল ফরওয়ার্ড করার সেটিংস\' পরিবর্তন করা যাবে না৷"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"পরিষেবা সক্ষম করা ছিল৷"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"মেমরিতে নিজের জন্য প্রয়োজনীয় জায়গা আলাদা করে রাখতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এর ফলে অন্যান্য অ্যাপ্লিকেশানগুলির জায়গা সীমিত হয়ে পড়তে পারে ও ফোনটি অপেক্ষাকৃত ধীরগতির হয়ে পড়তে পারে৷"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ফোরগ্রাউন্ডে পরিষেবা চালানো"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"অ্যাপটিকে ফোরগ্রাউন্ডের পরিষেবা ব্যবহার করতে দেয়।"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"অ্যাপকে \"camera\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"অ্যাপকে \"connectedDevice\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"অ্যাপকে \"dataSync\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"অ্যাপকে \"location\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"অ্যাপকে \"mediaPlayback\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"অ্যাপকে \"mediaProjection\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"অ্যাপকে \"microphone\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"অ্যাপকে \"phoneCall\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"অ্যাপকে \"health\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"অ্যাপকে \"remoteMessaging\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"অ্যাপকে \"systemExempted\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা রান করান"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"অ্যাপকে \"specialUse\" সম্পর্কিত ফোরগ্রাউন্ড পরিষেবা ব্যবহার করার অনুমতি দেয়"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"অ্যাপ্লিকেশন সঞ্চয়স্থানের জায়গা পরিমাপ করে"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"অ্যাপ্লিকেশানকে এটির কোড, ডেটা, এবং ক্যাশে মাপ উদ্ধার করার অনুমতি দেয়"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"সিস্টেম সেটিংস পরিবর্তন করুন"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"এই অ্যাপটি যখন ব্যবহার করা হচ্ছে, তখন মাইক্রোফোন ব্যবহার করে অডিও রেকর্ড করতে পারবে।"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ব্যাকগ্রাউন্ডে অডিও রেকর্ড করতে পারবে"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"এই অ্যাপটি মাইক্রোফোন ব্যবহার করে যেকোনও সময় অডিও রেকর্ড করতে পারবে।"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"অ্যাপ উইন্ডোর স্ক্রিন ক্যাপচার করা হলে তা শনাক্ত করা"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"অ্যাপ ব্যবহার করার সময় স্ক্রিনশট নেওয়া হলে এই অ্যাপে বিজ্ঞপ্তি পাঠানো হবে।"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"সিম এ আদেশগুলি পাঠান"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"অ্যাপ্লিকেশানটিকে সিম কার্ডে কমান্ডগুলি পাঠানোর অনুমতি দেয়৷ এটি খুবই বিপজ্জনক৷"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"শারীরিক অ্যাক্টিভিটি শনাক্ত করুন"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ফোনের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"আপনার <xliff:g id="DEVICE">%1$s</xliff:g> থেকে ট্যাবলেটের ক্যামেরা অ্যাক্সেস করা যাচ্ছে না"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"স্ট্রিমিংয়ের সময় এটি অ্যাক্সেস করা যাবে না। পরিবর্তে আপনার ফোনে ব্যবহার করে দেখুন।"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"স্ট্রিম করার সময় \'ছবির-মধ্যে-ছবি\' দেখা যাবে না"</string>
     <string name="system_locale_title" msgid="711882686834677268">"সিস্টেম ডিফল্ট"</string>
     <string name="default_card_name" msgid="9198284935962911468">"কার্ড <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index acd9aa4..0486932 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Govorna pošta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problem sa povezivanjem ili nevažeći MMI kôd."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcija nije podržana."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacija je ograničena samo na brojeve fiksnog biranja."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nije moguće promijeniti postavke prosljeđivanja poziva s vašeg telefona dok ste u romingu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Usluga je omogućena."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Omogućava aplikaciji da neke svoje dijelove pohrani trajno u memoriji. Ovo može ograničiti veličinu raspoložive memorije za druge aplikacije i tako usporiti telefon."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"pokretanje usluge u prvom planu"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Dopušta aplikaciji korištenje usluga u prvom planu."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"pokreni uslugu u prvom planu s vrstom \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"pokreni uslugu u prvom planu s vrstom \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"pokreni uslugu u prvom planu s vrstom \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"pokreni uslugu u prvom planu s vrstom \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"pokreni uslugu u prvom planu s vrstom \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"pokreni uslugu u prvom planu s vrstom \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"pokreni uslugu u prvom planu s vrstom \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"pokreni uslugu u prvom planu s vrstom \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"pokreni uslugu u prvom planu s vrstom \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"pokreni uslugu u prvom planu s vrstom \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"pokreni uslugu u prvom planu s vrstom \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokreni uslugu u prvom planu s vrstom \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Dozvoljava aplikaciji da koristi usluge u prvom planu s vrstom \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mjerenje prostora kojeg aplikacije zauzimaju u pohrani"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Dozvoljava aplikaciji preuzimanje svog koda, podataka i veličine keš memorije"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"izmjena postavki sistema"</string>
@@ -496,8 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Za vrijeme korištenja, ova aplikacija može snimati zvuk koristeći mikrofon."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"snimanje zvuka u pozadini"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ova aplikacija može u svakom trenutku snimati zvuk koristeći mikrofon."</string>
-    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detektirati snimanja zaslona prozora aplikacije"</string>
-    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ako se tijekom upotrebe ove aplikacije izradi snimka zaslona, aplikacija će dobiti obavijest."</string>
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"otkrivanje snimanja ekrana u prozorima aplikacije"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Aplikacija će dobiti obavještenje kada se kreira snimak ekrana dok se aplikacija koristi."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"slanje komandi SIM kartici"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Omogućava aplikaciji slanje naredbi na SIM. Ovo je vrlo opasno."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje fizičke aktivnosti"</string>
@@ -2341,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nije moguće pristupiti kameri telefona s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nije moguće pristupiti kameri tableta s uređaja <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Ovom ne možete pristupiti tokom prijenosa. Umjesto toga pokušajte na telefonu."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tokom prijenosa nije moguće gledati sliku u slici"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistemski zadano"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 18abb28..8936e4f 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Bústia de veu"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de connexió o codi MMI no vàlid."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"La funció no s\'admet."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"L\'operació està restringida a números de marcatge fixos."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"No es pot canviar la configuració de desviació de trucades del telèfon quan estàs en itinerància."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"El servei s\'ha activat."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permet que l\'aplicació faci que parts de la seva memòria siguin persistents. Aquesta acció pot limitar la memòria disponible per a altres aplicacions i alentir el telèfon."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"executar serveis en primer pla"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permet que l\'aplicació utilitzi serveis en primer pla."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"executa serveis en primer pla amb el tipus \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"executa serveis en primer pla amb el tipus \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"executa serveis en primer pla amb el tipus \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"executa serveis en primer pla amb el tipus \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"executa serveis en primer pla amb el tipus \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"executa serveis en primer pla amb el tipus \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"executa serveis en primer pla amb el tipus \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"executa serveis en primer pla amb el tipus \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"executa serveis en primer pla amb el tipus \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"executa serveis en primer pla amb el tipus \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"executa serveis en primer pla amb el tipus \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executa serveis en primer pla amb el tipus \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permet que l\'aplicació utilitzi serveis en primer pla amb el tipus \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mesura l\'espai d\'emmagatzematge d\'aplicacions"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permet que l\'aplicació recuperi les mides del codi, de les dades i de la memòria cau"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar la configuració del sistema"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aquesta aplicació pot gravar àudio amb el micròfon mentre s\'està utilitzant."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar àudio en segon pla"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aquesta aplicació pot gravar àudio amb el micròfon en qualsevol moment."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detecta les captures de pantalla de les finestres d\'aplicacions"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Aquesta aplicació rebrà una notificació quan es faci una captura de pantalla mentre s\'utilitza l\'aplicació."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar ordres a la SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permet que l\'aplicació enviï ordres a la SIM. Això és molt perillós."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconèixer l\'activitat física"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No es pot accedir a la càmera del telèfon des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No es pot accedir a la càmera de la tauleta des del teu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"No s\'hi pot accedir mentre s\'està reproduint en continu. Prova-ho al telèfon."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"No es pot veure el mode de pantalla en pantalla durant la reproducció en continu"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Valor predeterminat del sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARGETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index eae6dfb..91daf78 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Hlasová schránka"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problém s připojením nebo neplatný kód MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkce není podporována."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operace je omezena pouze na povolená telefonní čísla."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Když je aktivní roaming, nastavení přesměrování hovorů z telefonu nelze změnit."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Služba byla zapnuta."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Umožňuje aplikaci uložit některé své části trvale do paměti. Může to omezit paměť dostupnou pro ostatní aplikace a zpomalit tak telefon."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"spouštění služeb na popředí"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Povolte aplikaci využívání služeb na popředí."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"používat službu v popředí typu „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Umožňuje aplikaci používat služby v popředí typu „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"používat službu v popředí typu „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Umožňuje aplikaci používat služby v popředí typu „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"používat službu v popředí typu „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Umožňuje aplikaci používat služby v popředí typu „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"používat službu v popředí typu „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Umožňuje aplikaci používat služby v popředí typu „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"používat službu v popředí typu „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Umožňuje aplikaci používat služby v popředí typu „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"používat službu v popředí typu „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Umožňuje aplikaci používat služby v popředí typu „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"používat službu v popředí typu „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Umožňuje aplikaci používat služby v popředí typu „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"používat službu v popředí typu „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Umožňuje aplikaci používat služby v popředí typu „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"používat službu v popředí typu „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Umožňuje aplikaci používat služby v popředí typu „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"používat službu v popředí typu „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Umožňuje aplikaci používat služby v popředí typu „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"používat službu v popředí typu „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Umožňuje aplikaci používat služby v popředí typu „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"používat službu v popředí typu „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Umožňuje aplikaci používat služby v popředí typu „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"výpočet místa pro ukládání aplikací"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Umožňuje aplikaci načtení svého kódu, dat a velikostí mezipaměti."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"změna nastavení systému"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Tato aplikace může pomocí mikrofonu během svého používání zaznamenat zvuk."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"zaznamenávat zvuk na pozadí"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Tato aplikace může pomocí mikrofonu kdykoli zaznamenat zvuk."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"zjišťování záznamu obrazovky s okny aplikace"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Tato aplikace dostane oznámení v případě pořízení snímku obrazovky během používání aplikace."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"odesílání příkazů do SIM karty"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikaci odesílat příkazy na kartu SIM. Toto oprávnění je velmi nebezpečné."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávání fyzické aktivity"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu telefonu"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ze zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze získat přístup k fotoaparátu tabletu"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Tento obsah při streamování nelze zobrazit. Zkuste to na telefonu."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Během streamování nelze zobrazit obraz v obraze"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Výchozí nastavení systému"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 5e32ab6..b1f5e2a 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Telefonsvarer"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Forbindelsesproblemer eller ugyldigt MMI-nummer."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funktionen understøttes ikke."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Du kan kun foretage handlinger med dine numre til begrænset opkald."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Det er ikke muligt at ændre indstillingerne for viderestilling af opkald fra din telefon, mens du bruger roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Tjenesten blev aktiveret."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Tillader, at appen gør dele af sig selv vedholdende i hukommelsen. Dette kan begrænse den tilgængelige hukommelse for andre apps, hvilket gør telefonen langsommere."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"kør tjeneste i forgrunden"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Tillad, at appen anvender tjenester i forgrunden."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"kør tjenesten af typen \"camera\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Tillader, at appen benytter tjenester af typen \"camera\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"kør tjenesten af typen \"connectedDevice\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Tillader, at appen benytter tjenester af typen \"connectedDevice\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"kør tjenesten af typen \"dataSync\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Tillader, at appen benytter tjenester af typen \"dataSync\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"kør tjenesten af typen \"location\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Tillader, at appen benytter tjenester af typen \"location\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"kør tjenesten af typen \"mediaPlayback\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Tillader, at appen benytter tjenester af typen \"mediaPlayback\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"kør tjenesten af typen \"mediaProjection\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Tillader, at appen benytter tjenester af typen \"mediaProjection\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"kør tjenesten af typen \"microphone\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Tillader, at appen benytter tjenester af typen \"microphone\" i forgrunden"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"kør tjenesten af typen \"phoneCall\" i forgrunden"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Tillader, at appen benytter tjenester af typen \"phoneCall\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"kør tjenesten af typen \"health\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Tillader, at appen benytter tjenester af typen \"health\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"kør tjenesten af typen \"remoteMessaging\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Tillader, at appen benytter tjenester af typen \"remoteMessaging\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"kør tjenesten af typen \"systemExempted\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tillader, at appen benytter tjenester af typen \"systemExempted\" i forgrunden"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kør tjenesten af typen \"specialUse\" i forgrunden"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tillader, at appen benytter tjenester af typen \"specialUse\" i forgrunden"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"måle appens lagerplads"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Tillader, at en app kan hente sin kode, data og cachestørrelser"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ændre systemindstillinger"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Denne app kan optage lyd med mikrofonen, mens appen er i brug."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"optag lyd i baggrunden"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Denne app kan optage lyd med mikrofonen når som helst."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"registrer screenshots af appvindue"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Denne app får en notifikation, når der tages et screenshot, mens appen er i brug."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"send kommandoer til SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillader, at appen sender kommandoer til SIM-kortet. Dette er meget farligt."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"genkend fysisk aktivitet"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kameraet på din telefon kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kameraet på din tablet kan ikke tilgås via din <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Der er ikke adgang til dette indhold under streaming. Prøv på din telefon i stedet."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktionen Integreret billede er ikke tilgængelig, når der streames"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c4da5c8..9e89501 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Mailbox"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Verbindungsproblem oder ungültiger MMI-Code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funktion nicht unterstützt."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Der Vorgang ist nur für deine zugelassenen Rufnummern möglich."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Die Einstellungen für die Anrufweiterleitung von deinem Smartphone können während des Roamings nicht geändert werden."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Dienst wurde aktiviert."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Ermöglicht der App, Teile der eigenen App dauerhaft im Speicher abzulegen. Dies kann dazu führen, dass anderen Apps weniger Arbeitsspeicher zur Verfügung steht und das Telefon langsamer wird."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"Vordergrunddienst ausführen"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Ermöglicht der App, die Vordergrunddienste zu verwenden."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"Vordergrunddienste mit dem Typ „camera“ ausführen"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Ermöglicht der App, Vordergrunddienste mit dem Typ „camera“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"Vordergrunddienste mit dem Typ „connectedDevice“ ausführen"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Ermöglicht der App, Vordergrunddienste mit dem Typ „connectedDevice“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"Vordergrunddienste mit dem Typ „dataSync“ ausführen"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Ermöglicht der App, Vordergrunddienste mit dem Typ „dataSync“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"Vordergrunddienste mit dem Typ „location“ ausführen"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Ermöglicht der App, Vordergrunddienste mit dem Typ „location“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"Vordergrunddienste mit dem Typ „mediaPlayback“ ausführen"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Ermöglicht der App, Vordergrunddienste mit dem Typ „mediaPlayback“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"Vordergrunddienste mit dem Typ „mediaProjection“ ausführen"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Ermöglicht der App, Vordergrunddienste mit dem Typ „mediaProjection“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"Vordergrunddienste mit dem Typ „microphone“ ausführen"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Ermöglicht der App, Vordergrunddienste mit dem Typ „microphone“ zu verwenden"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"Vordergrunddienste mit dem Typ „phoneCall“ ausführen"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Ermöglicht der App, Vordergrunddienste mit dem Typ „phoneCall“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"Vordergrunddienste mit dem Typ „health“ ausführen"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Ermöglicht der App, Vordergrunddienste mit dem Typ „health“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"Vordergrunddienste mit dem Typ „remoteMessaging“ ausführen"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Ermöglicht der App, Vordergrunddienste mit dem Typ „remoteMessaging“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"Vordergrunddienste mit dem Typ „systemExempted“ ausführen"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ermöglicht der App, Vordergrunddienste mit dem Typ „systemExempted“ zu verwenden"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Vordergrunddienste mit dem Typ „specialUse“ ausführen"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ermöglicht der App, Vordergrunddienste mit dem Typ „specialUse“ zu verwenden"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"Speicherplatz der App ermitteln"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Ermöglicht der App, ihre Code-, Daten- und Cache-Größe abzurufen"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"Systemeinstellungen ändern"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Diese App darf mit dem Mikrofon Audioaufnahmen machen, solange sie verwendet wird."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Audioaufnahmen im Hintergrund machen"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Diese App darf mit dem Mikrofon jederzeit Audioaufnahmen machen."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"Bildschirmaufnahmen von App-Fenstern erkennen"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Diese App wird benachrichtigt, wenn ein Screenshot aufgenommen wird, während du sie verwendest."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"Befehle an die SIM senden"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Ermöglicht der App das Senden von Befehlen an die SIM-Karte. Dies ist äußerst risikoreich."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"Körperliche Aktivitäten erkennen"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Zugriff auf die Kamera des Smartphones über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Zugriff auf die Kamera des Tablets über dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) nicht möglich"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Während des Streamings ist kein Zugriff möglich. Versuch es stattdessen auf deinem Smartphone."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Funktion „Bild im Bild“ kann beim Streamen nicht verwendet werden"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Standardeinstellung des Systems"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 91d8aaf..8f55589 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Αυτ/τος τηλεφωνητής"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Πρόβλημα σύνδεσης ή μη έγκυρος κώδικας MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Η λειτουργία δεν υποστηρίζεται."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Η λειτουργία περιορίζεται μόνο σε προκαθορισμένους αριθμούς κλήσης."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Δεν είναι δυνατή η αλλαγή των ρυθμίσεων προώθησης κλήσεων από το τηλέφωνό σας κατά τη διάρκεια της περιαγωγής."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Η υπηρεσία ενεργοποιήθηκε."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Επιτρέπει στην εφαρμογή να δημιουργεί μόνιμα τμήματα του εαυτού της στη μνήμη. Αυτό μπορεί να περιορίζει τη μνήμη που διατίθεται σε άλλες εφαρμογές, καθυστερώντας τη λειτουργία του τηλεφώνου."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"εκτέλεση υπηρεσίας προσκηνίου"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί υπηρεσίες προσκηνίου."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"εκτέλεση υπηρεσίας στο προσκήνιο με τον τύπο \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Επιτρέπει στην εφαρμογή να χρησιμοποιεί τις υπηρεσίες στο προσκήνιο με τον τύπο \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"υπολογίζει τον αποθηκευτικό χώρο εφαρμογής"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Επιτρέπει στην εφαρμογή να ανακτήσει τα μεγέθη κώδικα, δεδομένων και προσωρινής μνήμης"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"τροποποίηση ρυθμίσεων συστήματος"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Δεν είναι δυνατή η πρόσβαση στην κάμερα τηλεφώνου από το <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Δεν είναι δυνατή η πρόσβαση στην κάμερα του tablet από τη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Δεν είναι δυνατή η πρόσβαση σε αυτό το στοιχείο κατά τη ροή. Δοκιμάστε στο τηλέφωνό σας."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Δεν είναι δυνατή η προβολή picture-in-picture κατά τη ροή"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Προεπιλογή συστήματος"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ΚΑΡΤΑ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8ef72d1..003b3f0 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Connection problem or invalid MMI code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Feature not supported."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operation is restricted to fixed dialling numbers only."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Cannot change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service was enabled."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Allows the app to make parts of itself persistent in memory. This can limit the memory available to other apps, slowing down the phone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"run foreground service"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Allows the app to make use of foreground services."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"run foreground service with the type \'camera\'"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Allows the app to make use of foreground services with the type \'camera\'"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"run foreground service with the type \'connectedDevice\'"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Allows the app to make use of foreground services with the type \'connectedDevice\'"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"run foreground service with the type \'dataSync\'"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Allows the app to make use of foreground services with the type \'dataSync\'"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"run foreground service with the type \'location\'"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Allows the app to make use of foreground services with the type \'location\'"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"run foreground service with the type \'mediaPlayback\'"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Allows the app to make use of foreground services with the type \'mediaPlayback\'"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"run foreground service with the type \'mediaProjection\'"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Allows the app to make use of foreground services with the type \'mediaProjection\'"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"run foreground service with the type \'microphone\'"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Allows the app to make use of foreground services with the type \'microphone\'"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"run foreground service with the type \'phoneCall\'"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Allows the app to make use of foreground services with the type \'phoneCall\'"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"run foreground service with the type \'health\'"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Allows the app to make use of foreground services with the type \'health\'"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"run foreground service with the type \'remoteMessaging\'"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Allows the app to make use of foreground services with the type \'remoteMessaging\'"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"run foreground service with the type \'systemExempted\'"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Allows the app to retrieve its code, data and cache sizes"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modify system settings"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index b16f3b6..e1cfd83 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Connection problem or invalid MMI code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Feature not supported."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operation is restricted to fixed dialing numbers only."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Can not change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service was enabled."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Allows the app to make parts of itself persistent in memory. This can limit memory available to other apps slowing down the phone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"run foreground service"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Allows the app to make use of foreground services."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"run foreground service with the type \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Allows the app to make use of foreground services with the type \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"run foreground service with the type \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Allows the app to make use of foreground services with the type \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"run foreground service with the type \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Allows the app to make use of foreground services with the type \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"run foreground service with the type \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Allows the app to make use of foreground services with the type \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"run foreground service with the type \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Allows the app to make use of foreground services with the type \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"run foreground service with the type \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Allows the app to make use of foreground services with the type \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"run foreground service with the type \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Allows the app to make use of foreground services with the type \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"run foreground service with the type \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Allows the app to make use of foreground services with the type \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"run foreground service with the type \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Allows the app to make use of foreground services with the type \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"run foreground service with the type \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Allows the app to make use of foreground services with the type \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"run foreground service with the type \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Allows the app to retrieve its code, data, and cache sizes"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modify system settings"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index fbc4aae..4c0a7aa 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Connection problem or invalid MMI code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Feature not supported."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operation is restricted to fixed dialling numbers only."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Cannot change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service was enabled."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Allows the app to make parts of itself persistent in memory. This can limit the memory available to other apps, slowing down the phone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"run foreground service"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Allows the app to make use of foreground services."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"run foreground service with the type \'camera\'"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Allows the app to make use of foreground services with the type \'camera\'"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"run foreground service with the type \'connectedDevice\'"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Allows the app to make use of foreground services with the type \'connectedDevice\'"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"run foreground service with the type \'dataSync\'"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Allows the app to make use of foreground services with the type \'dataSync\'"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"run foreground service with the type \'location\'"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Allows the app to make use of foreground services with the type \'location\'"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"run foreground service with the type \'mediaPlayback\'"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Allows the app to make use of foreground services with the type \'mediaPlayback\'"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"run foreground service with the type \'mediaProjection\'"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Allows the app to make use of foreground services with the type \'mediaProjection\'"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"run foreground service with the type \'microphone\'"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Allows the app to make use of foreground services with the type \'microphone\'"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"run foreground service with the type \'phoneCall\'"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Allows the app to make use of foreground services with the type \'phoneCall\'"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"run foreground service with the type \'health\'"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Allows the app to make use of foreground services with the type \'health\'"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"run foreground service with the type \'remoteMessaging\'"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Allows the app to make use of foreground services with the type \'remoteMessaging\'"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"run foreground service with the type \'systemExempted\'"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Allows the app to retrieve its code, data and cache sizes"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modify system settings"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 564a52d..7e3ce2d 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Connection problem or invalid MMI code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Feature not supported."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operation is restricted to fixed dialling numbers only."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Cannot change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service was enabled."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Allows the app to make parts of itself persistent in memory. This can limit the memory available to other apps, slowing down the phone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"run foreground service"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Allows the app to make use of foreground services."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"run foreground service with the type \'camera\'"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Allows the app to make use of foreground services with the type \'camera\'"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"run foreground service with the type \'connectedDevice\'"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Allows the app to make use of foreground services with the type \'connectedDevice\'"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"run foreground service with the type \'dataSync\'"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Allows the app to make use of foreground services with the type \'dataSync\'"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"run foreground service with the type \'location\'"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Allows the app to make use of foreground services with the type \'location\'"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"run foreground service with the type \'mediaPlayback\'"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Allows the app to make use of foreground services with the type \'mediaPlayback\'"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"run foreground service with the type \'mediaProjection\'"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Allows the app to make use of foreground services with the type \'mediaProjection\'"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"run foreground service with the type \'microphone\'"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Allows the app to make use of foreground services with the type \'microphone\'"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"run foreground service with the type \'phoneCall\'"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Allows the app to make use of foreground services with the type \'phoneCall\'"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"run foreground service with the type \'health\'"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Allows the app to make use of foreground services with the type \'health\'"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"run foreground service with the type \'remoteMessaging\'"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Allows the app to make use of foreground services with the type \'remoteMessaging\'"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"run foreground service with the type \'systemExempted\'"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Allows the app to make use of foreground services with the type \'systemExempted\'"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"run foreground service with the type \'specialUse\'"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Allows the app to make use of foreground services with the type \'specialUse\'"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"measure app storage space"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Allows the app to retrieve its code, data and cache sizes"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modify system settings"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index dc34624..9cc06d1 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‎‏‎‏‎‏‏‎‎‏‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎Voicemail‎‏‎‎‏‎"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‎‏‏‎‎‎‎‎MSISDN1‎‏‎‎‏‎"</string>
     <string name="mmiError" msgid="2862759606579822246">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‎‎‏‎‏‏‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎Connection problem or invalid MMI code.‎‏‎‎‏‎"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‎‎‏‎‏‎‏‎‎‏‏‎Feature not supported.‎‏‎‎‏‎"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‎Operation is restricted to fixed dialing numbers only.‎‏‎‎‏‎"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‎‎Can not change call forwarding settings from your phone while you are roaming.‎‏‎‎‏‎"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‏‏‎Service was enabled.‎‏‎‎‏‎"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‎‏‎‎‏‎‏‎‏‏‎‏‏‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎Allows the app to make parts of itself persistent in memory. This can limit memory available to other apps slowing down the phone.‎‏‎‎‏‎"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎run foreground service‎‏‎‎‏‎"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‎‏‎‎‎‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‏‏‎Allows the app to make use of foreground services.‎‏‎‎‏‎"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‎‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‏‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‏‎run foreground service with the type \"camera\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‏‏‎‎‏‎‎‎‎‏‏‏‏‎‏‎‏‎‏‎‎‏‏‎‏‏‎‏‎‎‏‎‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‏‏‎Allows the app to make use of foreground services with the type \"camera\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‎‎‏‎‎‎‏‏‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎run foreground service with the type \"connectedDevice\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‎‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‏‏‎Allows the app to make use of foreground services with the type \"connectedDevice\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‎‎‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‎‎‏‏‎‏‎‎‎run foreground service with the type \"dataSync\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‎‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‎‏‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‎‏‏‎‏‎‏‏‏‎‏‎‎Allows the app to make use of foreground services with the type \"dataSync\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‎‏‏‎‎‏‏‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‏‎‎‎‎‏‎‏‎‎run foreground service with the type \"location\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‎‎‏‏‎‎‏‎‏‎‏‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‏‏‏‏‎Allows the app to make use of foreground services with the type \"location\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‏‎‎‏‏‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‎‎run foreground service with the type \"mediaPlayback\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‎‎‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎Allows the app to make use of foreground services with the type \"mediaPlayback\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎run foreground service with the type \"mediaProjection\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‏‏‎‏‎‎Allows the app to make use of foreground services with the type \"mediaProjection\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‏‎‏‎‏‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‏‎run foreground service with the type \"microphone\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‏‎Allows the app to make use of foreground services with the type \"microphone\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‎‎‎‎‎‏‏‎‏‎‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‎‎run foreground service with the type \"phoneCall\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‏‏‎Allows the app to make use of foreground services with the type \"phoneCall\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‎‎‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‎‎‎‎run foreground service with the type \"health\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‏‏‎‎‏‏‏‎‎‎‎‏‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‎‏‎‏‏‎‏‎‏‏‎‎‎‏‎Allows the app to make use of foreground services with the type \"health\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‎‏‏‏‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‎‎‏‎‎‎‏‎‏‏‎‎run foreground service with the type \"remoteMessaging\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‏‏‎‎‏‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‎‏‎‏‎‎‏‏‎‎‏‏‏‎‎‏‎‏‎‏‎‏‎Allows the app to make use of foreground services with the type \"remoteMessaging\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‎‏‏‏‎‏‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‏‎‎‏‏‎‏‎run foreground service with the type \"systemExempted\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‏‎‎‏‎‎‏‎‏‏‏‎‎‎‏‏‎‏‎‏‏‎‎‎‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‎Allows the app to make use of foreground services with the type \"systemExempted\"‎‏‎‎‏‎"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‏‏‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‎‏‎‎‏‏‎‏‏‎‏‎‎run foreground service with the type \"specialUse\"‎‏‎‎‏‎"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‎Allows the app to make use of foreground services with the type \"specialUse\"‎‏‎‎‏‎"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‎‎‏‏‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎‏‎‏‏‏‎‎‎‏‎measure app storage space‎‏‎‎‏‎"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‏‎‎‏‏‏‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎Allows the app to retrieve its code, data, and cache sizes‎‏‎‎‏‎"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‎‏‎‎‏‏‎‏‎‏‎‎‏‎‎modify system settings‎‏‎‎‏‎"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f74ac2b..69ce57e 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Buzón de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de conexión o código incorrecto de MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Función no compatible."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"La operación está limitada a números de marcación fija."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"No se puede cambiar la configuración de desvío de llamadas de tu teléfono mientras usas el servicio de roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Se ha activado el servicio."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que la aplicación haga que algunas de sus partes se mantengan persistentes en la memoria. Esto puede limitar la memoria disponible para otras aplicaciones y ralentizar el dispositivo."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ejecutar servicio en primer plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que la app use servicios en primer plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"Ejecuta un servicio en primer plano con el tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que la app use servicios en primer plano con el tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"Ejecuta un servicio en primer plano con el tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que la app use servicios en primer plano con el tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"Ejecuta un servicio en primer plano con el tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que la app use servicios en primer plano con el tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"Ejecuta un servicio en primer plano con el tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que la app use servicios en primer plano con el tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"Ejecuta un servicio en primer plano con el tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que la app use servicios en primer plano con el tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"Ejecuta un servicio en primer plano con el tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que la app use servicios en primer plano con el tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"Ejecuta un servicio en primer plano con el tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que la app use servicios en primer plano con el tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"Ejecuta un servicio en primer plano con el tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que la app use servicios en primer plano con el tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"Ejecuta un servicio en primer plano con el tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que la app use servicios en primer plano con el tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"Ejecuta un servicio en primer plano con el tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que la app use servicios en primer plano con el tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"Ejecuta un servicio en primer plano con el tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que la app use servicios en primer plano con el tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Ejecuta un servicio en primer plano con el tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que la app use servicios en primer plano con el tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir el espacio de almacenamiento de la aplicación"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite que la aplicación recupere su código, sus datos y los tamaños de la memoria caché."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar la configuración del sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Esta app puede grabar audio con el micrófono mientras está en uso."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"grabar audio en segundo plano"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta app puede grabar audio con el micrófono en cualquier momento."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"Detección de capturas de pantalla de las ventanas de la app"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Esta app recibirá una notificación cuando se tome una captura de pantalla mientras esté en uso."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Usar este permiso es peligroso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del dispositivo desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara de la tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una transmisión. Inténtalo en tu teléfono."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"No puedes ver pantalla en pantalla mientras transmites"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 42fb37d..91c12c9 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Buzón de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Se ha producido un problema de conexión o el código MMI no es válido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Función no disponible."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"La operación solo es válida para números de marcación fija."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"No se puede cambiar la configuración de desvío de llamadas desde tu teléfono mientras estás en roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"El servicio se ha habilitado."</string>
@@ -88,7 +89,7 @@
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"Alertas"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"Desvío de llamadas"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Modo de devolución de llamada de emergencia"</string>
-    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Estado de los datos móviles"</string>
+    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Estado de datos móviles"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"Mensajes SMS"</string>
     <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Mensajes de voz"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"Llamada por Wi-Fi"</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que la aplicación haga que algunas de sus partes se mantengan en la memoria. Esto puede limitar la cantidad de memoria disponible para otras aplicaciones y ralentizar el teléfono."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ejecutar servicio en primer plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que la aplicación use servicios en primer plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"ejecutar un servicio en primer plano con el tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que la aplicación use servicios en primer plano con el tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"ejecutar un servicio en primer plano con el tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que la aplicación use servicios en primer plano con el tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"ejecutar un servicio en primer plano con el tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que la aplicación use servicios en primer plano con el tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"ejecutar un servicio en primer plano con el tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que la aplicación use servicios en primer plano con el tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"ejecutar un servicio en primer plano con el tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que la aplicación use servicios en primer plano con el tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"ejecutar un servicio en primer plano con el tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que la aplicación use servicios en primer plano con el tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"ejecutar un servicio en primer plano con el tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que la aplicación use servicios en primer plano con el tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"ejecutar un servicio en primer plano con el tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que la aplicación use servicios en primer plano con el tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"ejecutar un servicio en primer plano con el tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que la aplicación use servicios en primer plano con el tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"ejecutar un servicio en primer plano con el tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que la aplicación use servicios en primer plano con el tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"ejecutar un servicio en primer plano con el tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que la aplicación use servicios en primer plano con el tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ejecutar un servicio en primer plano con el tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que la aplicación use servicios en primer plano con el tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir el espacio de almacenamiento de la aplicación"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite que la aplicación recupere su código, sus datos y los tamaños de caché."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar los ajustes del sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Esta aplicación puede grabar audio con el micrófono mientras la estés usando."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Grabar audio en segundo plano"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta aplicación puede grabar audio con el micrófono en cualquier momento."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detectar capturas de pantalla de ventanas de la aplicación"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Esta aplicación recibirá un aviso cuando se haga una captura de pantalla mientras está en uso."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos a la tarjeta SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que la aplicación envíe comandos a la tarjeta SIM. Este permiso es muy peligroso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconocer actividad física"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"No se puede acceder a la cámara del teléfono desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"No se puede acceder a la cámara del tablet desde tu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"No se puede acceder a este contenido durante una emisión. Prueba en tu teléfono."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"No se puede usar imagen en imagen mientras se emite contenido"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predeterminado del sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARJETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index dd199d8..42a383c 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Kõnepost"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Ühendusprobleem või kehtetu MMI-kood."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funktsiooni ei toetata."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Toiming on ainult fikseeritud valimisnumbritele."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Kõne suunamise seadeid ei saa rändluse ajal teie telefonis muuta."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Teenus on lubatud."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Võimaldab rakendusel muuta oma osi mälus püsivaks. See võib piirata teistele (telefoni aeglasemaks muutvatele) rakendustele saadaolevat mälu."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"käita esiplaanil olevat teenust"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „camera“."</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „connectedDevice“."</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „dataSync“."</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „location“."</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „mediaPlayback“."</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „mediaProjection“."</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „microphone“."</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „phoneCall“."</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „health“."</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „remoteMessaging“."</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „systemExempted“."</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"sellise esiplaanil oleva teenuse käitamine, mille tüüp on „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lubab rakendusel kasutada esiplaanil olevaid teenuseid, mille tüüp on „specialUse“."</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"Rakenduse mäluruumi mõõtmine"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Võimaldab rakendusel tuua oma koodi, andmed ja vahemälu suurused"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"muutke süsteemi seadeid"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"See rakendus saab mikrofoniga heli salvestada siis, kui rakendus on kasutusel."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Taustal heli salvestamine."</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"See rakendus saab mikrofoniga heli salvestada mis tahes ajal."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"rakenduste akende puhul ekraanikuva jäädvustamise tuvastamine"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Rakendust teavitatakse, kui selle kasutamise ajal jäädvustatakse ekraanipilt."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM-kaardile käskluste saatmine"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Lubab rakendusel saata käske SIM-kaardile. See on väga ohtlik."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"füüsiliste tegevuste tuvastamine"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse telefoni kaamerale juurde."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Teie seadmest <xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tahvelarvuti kaamerale juurde"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Sellele ei pääse voogesituse ajal juurde. Proovige juurde pääseda oma telefonis."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Voogesitamise ajal ei saa pilt pildis funktsiooni kasutada"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Süsteemi vaikeseade"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 548ad23..878b57e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Erantzungailua"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Konexio-arazoren bat gertatu da edo MMI kodea baliogabea da."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Ez da onartzen eginbidea."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Eragiketa markatze finkoko zenbakietara murriztua dago."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Ezin dira aldatu deiak desbideratzeko ezarpenak telefonoa ibiltaritzan dagoenean."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Zerbitzua gaitu da."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Beren zati batzuk memoria modu iraunkorrean ezartzeko baimena ematen die aplikazioei. Horrela, beste aplikazioek erabilgarri duten memoria murritz daiteke eta telefonoa motel daiteke."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"abiarazi zerbitzuak aurreko planoan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Aurreko planoko zerbitzuak erabiltzea baimentzen dio aplikazioari."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"exekutatu aurreko planoko zerbitzu bat (camera motakoa)"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Aurreko planoko zerbitzuak (camera motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"exekutatu aurreko planoko zerbitzu bat (connectedDevice motakoa)"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Aurreko planoko zerbitzuak (connectedDevice motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"exekutatu aurreko planoko zerbitzu bat (dataSync motakoa)"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Aurreko planoko zerbitzuak (dataSync motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"exekutatu aurreko planoko zerbitzu bat (location motakoa)"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Aurreko planoko zerbitzuak (location motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"exekutatu aurreko planoko zerbitzu bat (mediaPlayback motakoa)"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Aurreko planoko zerbitzuak (mediaPlayback motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"exekutatu aurreko planoko zerbitzu bat (mediaProjection motakoa)"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Aurreko planoko zerbitzuak (mediaProjection motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"exekutatu aurreko planoko zerbitzu bat (microphone motakoa)"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Aurreko planoko zerbitzuak (microphone motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"exekutatu aurreko planoko zerbitzu bat (phoneCall motakoa)"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Aurreko planoko zerbitzuak (phoneCall motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"exekutatu aurreko planoko zerbitzu bat (health motakoa)"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Aurreko planoko zerbitzuak (health motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"exekutatu aurreko planoko zerbitzu bat (remoteMessaging motakoa)"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Aurreko planoko zerbitzuak (remoteMessaging motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"exekutatu aurreko planoko zerbitzu bat (systemExempted motakoa)"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Aurreko planoko zerbitzuak (systemExempted motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exekutatu aurreko planoko zerbitzu bat (specialUse motakoa)"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Aurreko planoko zerbitzuak (specialUse motakoak) erabiltzeko baimena ematen dio aplikazioari"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"neurtu aplikazioen biltegiratzeko tokia"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Bere kodea, datuak eta cache-tamainak eskuratzeko baimena ematen die aplikazioei."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"aldatu sistemaren ezarpenak"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikazioak abian den bitartean erabil dezake mikrofonoa audioa grabatzeko."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Audioa grabatu atzeko planoan."</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikazioak edonoiz erabil dezake mikrofonoa audioa grabatzeko."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"hauteman pantaila-argazkiak aplikazioen leihoetan"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Aplikazioa erabili bitartean pantaila-argazki bat ateratzen denean, jakinarazpen bat jasoko duzu aplikazioan."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"bidali aginduak SIM txartelera"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM txartelera aginduak bidaltzeko baimena ematen die aplikazioei. Oso arriskutsua da."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"hauteman jarduera fisikoa"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ezin da atzitu telefonoaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ezin da atzitu tabletaren kamera <xliff:g id="DEVICE">%1$s</xliff:g> gailutik"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Ezin da atzitu edukia hura igorri bitartean. Oraingo gailuaren ordez, erabili telefonoa."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Edukia zuzenean erreproduzitu bitartean ezin da pantaila txiki gainjarrian ikusi"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistemaren balio lehenetsia"</string>
     <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> TXARTELA"</string>
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 07fa710..a65910b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"پست صوتی"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"‏مشکل در اتصال یا کد MMI نامعتبر."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"از این ویژگی پشتیبانی نمی‌شود."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"عملکرد فقط به شماره‌های شماره‌گیری ثابت محدود است."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"وقتی درحال فراگردی هستید، نمی‌توانید تنظیمات هدایت تماس را از تلفنتان تغییر دهید."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"سرویس فعال شد."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"به برنامه امکان می‌دهد قسمت‌هایی از خود را در حافظه دائمی کند. این کار حافظه موجود را برای سایر برنامه‌ها محدود کرده و باعث کندی تلفن می‌شود."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"اجرای سرویس پیش‌زمینه"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌زمینه استفاده کند."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"اجرای سرویس پیش‌نما از نوع «دوربین»"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «دوربین» استفاده کند"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"اجرای سرویس پیش‌نما از نوع «دستگاه متصل»"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «دستگاه متصل» استفاده کند"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"اجرای سرویس پیش‌نما از نوع «همگام‌سازی داده»"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «همگام‌سازی داده» استفاده کند"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"اجرای سرویس پیش‌نما از نوع «مکان»"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «مکان» استفاده کند"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"اجرای سرویس پیش‌نما از نوع «بازپخش رسانه»"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «بازپخش رسانه» استفاده کند"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"اجرای سرویس پیش‌نما از نوع «ارسال محتوا»"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «ارسال محتوا» استفاده کند"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"اجرای سرویس پیش‌نما از نوع «میکروفون»"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «میکروفون» استفاده کند"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"اجرای سرویس پیش‌نما از نوع «تماس تلفنی»"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «تماس تلفنی» استفاده کند"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"اجرای سرویس پیش‌نما از نوع «سلامتی»"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «سلامتی» استفاده کند"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"اجرای سرویس پیش‌نما از نوع «پیام‌رسانی ازراه‌دور»"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «پیام‌رسانی ازراه‌دور» استفاده کند"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"اجرای سرویس پیش‌نما از نوع «معافیت سیستم»"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «معافیت سیستم» استفاده کند"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"اجرای سرویس پیش‌نما از نوع «استفاده ویژه»"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"به برنامه اجازه می‌دهد از سرویس‌های پیش‌نما از نوع «استفاده ویژه» استفاده کند"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"اندازه‌گیری اندازه فضای ذخیره‌سازی برنامه"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"‏به برنامه اجازه می‎دهد تا کدها، داده‎ها و اندازه‎های حافظهٔ پنهان خود را بازیابی کند"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"تغییر تنظیمات سیستم"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"این برنامه وقتی درحال استفاده است، می‌تواند بااستفاده از میکروفون صدا ضبط کند."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ضبط صدا در پس‌زمینه"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"این برنامه می‌تواند در هرزمانی با استفاده از میکروفون صدا ضبط کند."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"تشخیص ضبط صفحه‌نمایش از پنجره برنامه‌ها"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"وقتی نماگرفتی درحین استفاده از برنامه گرفته می‌شود، به این برنامه اطلاع داده می‌شود."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ارسال فرمان به سیم کارت"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"به برنامه اجازه ارسال دستورات به سیم کارت را می‌دهد. این بسیار خطرناک است."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"تشخیص فعالیت فیزیکی"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"از <xliff:g id="DEVICE">%1$s</xliff:g> به دوربین تلفن دسترسی ندارید"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"نمی‌توان از <xliff:g id="DEVICE">%1$s</xliff:g> شما به دوربین رایانه لوحی دسترسی داشت"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"درحین جاری‌سازی، نمی‌توانید به آن دسترسی داشته باشید. دسترسی به آن را در تلفنتان امتحان کنید."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"هنگام جاری‌سازی نمی‌توان تصویر در تصویر را مشاهده کرد"</string>
     <string name="system_locale_title" msgid="711882686834677268">"پیش‌فرض سیستم"</string>
     <string name="default_card_name" msgid="9198284935962911468">"کارت <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ce6e579..02ae893 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Vastaaja"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Yhteysongelma tai virheellinen MMI-koodi."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Ominaisuutta ei tueta."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Voit suorittaa toiminnon vain sallitut puhelut -numeroihin."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Soitonsiirtoasetuksia ei voi muuttaa puhelimella roaming-tilassa."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Palvelu otettiin käyttöön."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Antaa sovelluksen lisätä omia osiaan muistiin pysyvästi. Tämä voi rajoittaa muiden sovellusten käytettävissä olevaa muistia ja hidastaa puhelimen toimintaa."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"suorita etualan palvelu"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Sallii sovelluksen käyttää etualan palveluja"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"käyttää etualan palveluja, joiden tyyppi on \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"käyttää etualan palveluja, joiden tyyppi on \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"käyttää etualan palveluja, joiden tyyppi on \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"käyttää etualan palveluja, joiden tyyppi on \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"käyttää etualan palveluja, joiden tyyppi on \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"käyttää etualan palveluja, joiden tyyppi on \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"käyttää etualan palveluja, joiden tyyppi on \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"käyttää etualan palveluja, joiden tyyppi on \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"käyttää etualan palveluja, joiden tyyppi on \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"käyttää etualan palveluja, joiden tyyppi on \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"käyttää etualan palveluja, joiden tyyppi on \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"käyttää etualan palveluja, joiden tyyppi on \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Sallii sovelluksen käyttää etualan palveluja, joiden tyyppi on \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"sovellusten tallennustilan mittaaminen"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Antaa sovelluksen noutaa sen koodin, tietojen ja välimuistin koot."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"muokkaa järjestelmän asetuksia"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Tämä sovellus voi tallentaa mikrofonilla audiota, kun sovellusta käytetään."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"tallentaa audiota taustalla"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Tämä sovellus voi tallentaa mikrofonilla audiota koska tahansa."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"havaitse sovelluksen ikkunoista otetut kuvakaappaukset"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Sovellukseen tulee ilmoitus, kun kuvakaappaus otetaan käytettäessä sovellusta."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"lähettää komentoja SIM-kortille"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Antaa sovelluksen lähettää komentoja SIM-kortille. Tämä ei ole turvallista."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"tunnistaa liikkumisen"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse puhelimen kameraan"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> ei pääse tabletin kameraan"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Sisältöön ei saa pääsyä striimauksen aikana. Kokeile striimausta puhelimella."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Pikkuruutua ei voi nähdä striimauksen aikana"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Järjestelmän oletusarvo"</string>
     <string name="default_card_name" msgid="9198284935962911468">"Kortti: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 51f6db8..264cf67 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Messagerie vocale"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problème de connexion ou code IHM incorrect"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Fonctionnalité non prise en charge."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Opération réservée aux numéros autorisés"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Impossible de modifier les paramètres de transfert d\'appel sur votre téléphone lorsque vous êtes en itinérance."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Le service a été activé."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir le téléphone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"exécuter le service en premier plan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permet à l\'application d\'utiliser les services en premier plan."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"exécuter le service d\'avant-plan avec le type « appareil photo »"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appareil photo »"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"exécuter le service d\'avant-plan avec le type « appareil connecté »"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appareil connecté »"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"exécuter le service d\'avant-plan avec le type « synchronisation des données »"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « synchronisation des données »"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"exécuter le service d\'avant-plan avec le type « emplacement »"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « emplacement »"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"exécuter le service d\'avant-plan avec le type « lecture multimédia »"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « lecture multimédia »"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"exécuter le service d\'avant-plan avec le type « projection de contenus multimédias »"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « projection de contenus multimédias »"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"exécuter le service d\'avant-plan avec le type « microphone »"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « microphone »"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"exécuter le service d\'avant-plan avec le type « appel téléphonique »"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « appel téléphonique »"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"exécuter le service d\'avant-plan avec le type « santé »"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « santé »"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"exécuter le service d\'avant-plan avec le type « messagerie à distance »"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « messagerie à distance »"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"exécuter le service d\'avant-plan avec le type « système exempté »"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « système exempté »"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exécuter le service d\'avant-plan avec le type « usage spécial »"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autoriser l\'application à utiliser les services d\'avant-plan avec le type « usage spécial »"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'application"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permet à l\'application de récupérer la taille de son code, de ses données et de sa mémoire cache."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifier les paramètres du système"</string>
@@ -2169,7 +2146,7 @@
     <string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"Notifications"</string>
     <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"Paramètres rapides"</string>
     <string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"Boîte de dialogue sur l\'alimentation"</string>
-    <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
+    <string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
     <string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
     <string name="accessibility_system_action_headset_hook_label" msgid="8524691721287425468">"Crochet de casque d\'écoute"</string>
     <string name="accessibility_system_action_on_screen_a11y_shortcut_label" msgid="8488701469459210309">"Raccourci d\'accessibilité à l\'écran"</string>
@@ -2341,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette à partir de votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Vous ne pouvez pas y accéder lorsque vous utilisez la diffusion en continu. Essayez sur votre téléphone à la place."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher des incrustations d\'image pendant une diffusion en continu"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 8d84a39..0e4bb4c 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Messagerie vocale"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problème de connexion ou code IHM non valide."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Fonctionnalité non disponible."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Opération réservée aux numéros autorisés"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Impossible de modifier les paramètres de transfert d\'appel depuis votre téléphone lorsque vous êtes en itinérance."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Le service a été activé."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permet à l\'application de rendre certains de ces composants persistants dans la mémoire. Cette autorisation peut limiter la mémoire disponible pour d\'autres applications et ralentir le téléphone."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"exécuter un service de premier plan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Autorise l\'application à utiliser des services de premier plan."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"exécuter un service de premier plan avec le type \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Autorise l\'appli à utiliser les services de premier plan avec le type \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"exécuter un service de premier plan avec le type \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Autorise l\'appli à utiliser les services de premier plan avec le type \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"exécuter un service de premier plan avec le type \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Autorise l\'appli à utiliser les services de premier plan avec le type \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"exécuter un service de premier plan avec le type \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Autorise l\'appli à utiliser les services de premier plan avec le type \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"exécuter un service de premier plan avec le type \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Autorise l\'appli à utiliser les services de premier plan avec le type \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"exécuter un service de premier plan avec le type \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Autorise l\'appli à utiliser les services de premier plan avec le type \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"exécuter un service de premier plan avec le type \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Autorise l\'appli à utiliser les services de premier plan avec le type \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"exécuter un service de premier plan avec le type \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Autorise l\'appli à utiliser les services de premier plan avec le type \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"exécuter un service de premier plan avec le type \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Autorise l\'appli à utiliser les services de premier plan avec le type \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"exécuter un service de premier plan avec le type \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Autorise l\'appli à utiliser les services de premier plan avec le type \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"exécuter un service de premier plan avec le type \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Autorise l\'appli à utiliser les services de premier plan avec le type \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"exécuter un service de premier plan avec le type \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Autorise l\'appli à utiliser les services de premier plan avec le type \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"évaluer l\'espace de stockage de l\'application"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permet à l\'application de récupérer son code, ses données et la taille de sa mémoire cache."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifier les paramètres du système"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Cette application peut utiliser le micro pour réaliser des enregistrements audio quand elle est en cours d\'utilisation."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"réaliser des enregistrements audio en arrière-plan"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Cette application peut utiliser le micro pour réaliser des enregistrements audio à tout moment."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"détecter les captures d\'écran de fenêtres d\'appli"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Cette app sera notifiée lors de la prise d\'une capture d\'écran pendant son utilisation."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"envoyer des commandes à la carte SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Autoriser l\'envoi de commandes à la carte SIM via l\'application. Cette fonctionnalité est très risquée."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconnaître l\'activité physique"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossible d\'accéder à l\'appareil photo du téléphone depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossible d\'accéder à l\'appareil photo de la tablette depuis votre <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Impossible d\'accéder à cela pendant le streaming. Essayez plutôt sur votre téléphone."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossible d\'afficher Picture-in-picture pendant le streaming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Paramètre système par défaut"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 57fba7f..31da9fa 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Correo de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de conexión ou código MMI non válido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Función non compatible."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"A operación está restrinxida a números de marcación fixa."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Non se pode cambiar a configuración do desvío de chamadas desde o teléfono mentres estás en itinerancia."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Activouse o servizo."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite á aplicación converter partes súas como persistentes na memoria. Esta acción pode limitar a cantidade memoria dispoñible para outras aplicacións e reducir a velocidade de funcionamento do teléfono."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"executar un servizo en primeiro plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que a aplicación utilice os servizos en primeiro plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"executar servizo en primeiro plano co tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"executar servizo en primeiro plano co tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"executar servizo en primeiro plano co tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"executar servizo en primeiro plano co tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"executar servizo en primeiro plano co tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"executar servizo en primeiro plano co tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"executar servizo en primeiro plano co tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"executar servizo en primeiro plano co tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"executar servizo en primeiro plano co tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"executar servizo en primeiro plano co tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"executar servizo en primeiro plano co tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar servizo en primeiro plano co tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que a aplicación faga uso de servizos en primeiro plano co tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espazo de almacenamento da aplicación"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite á aplicación recuperar o código, os datos e os tamaños da caché"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar a configuración do sistema"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Mentres a empregas, esta aplicación pode utilizar o micrófono para gravar audio."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar audio en segundo plano"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Esta aplicación pode utilizar o micrófono en calquera momento para gravar audio."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detectar capturas de pantalla de ventás da aplicación"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Esta aplicación recibirá unha notificación cando se faga unha captura de pantalla mentres se estea utilizando."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos á SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite á aplicación enviar comandos á SIM. Isto é moi perigoso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"recoñecer actividade física"</string>
@@ -2004,13 +1979,13 @@
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tv" msgid="196994247017450357">"A configuración de Android TV non está dispoñible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="tablet" msgid="8222710146267948647">"A configuración da tableta non está dispoñible"</string>
     <string name="app_streaming_blocked_title_for_settings_dialog" product="default" msgid="6895719984375299791">"A configuración do teléfono non está dispoñible"</string>
-    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo con Android TV."</string>
+    <string name="app_streaming_blocked_message" product="tv" msgid="4003011766528814377">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message" product="tablet" msgid="4242053045964946062">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde a tableta."</string>
     <string name="app_streaming_blocked_message" product="default" msgid="6159168735030739398">"Nestes momentos, non podes acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
-    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta aplicación solicita seguranza adicional. Proba a facelo desde o dispositivo con Android TV."</string>
+    <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tv" msgid="3470977315395784567">"Esta aplicación solicita seguranza adicional. Proba a facelo desde o dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="tablet" msgid="698460091901465092">"Esta aplicación solicita seguranza adicional. Proba a facelo desde a tableta."</string>
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Esta aplicación solicita seguranza adicional. Proba a facelo desde o teléfono."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Non se puido acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo con Android TV."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Non se puido acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Non se puido acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde a tableta."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Non se puido acceder a este contido desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>). Proba a facelo desde o teléfono."</string>
     <string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Esta aplicación deseñouse para unha versión anterior de Android. Quizais non funcione correctamente e non inclúa as últimas medidas de protección de privacidade e seguranza. Comproba se hai actualizacións ou ponte en contacto co programador da aplicación."</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Non se puido acceder á cámara do teléfono desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Non se puido acceder á cámara da tableta desde o teu dispositivo (<xliff:g id="DEVICE">%1$s</xliff:g>)"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Non se puido acceder a este contido durante a reprodución en tempo real. Téntao desde o teléfono."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Non se pode ver un vídeo en pantalla superposta mentres se reproduce en tempo real"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Opción predeterminada do sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"TARXETA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index c89b02b..8351fbc 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"વૉઇસમેઇલ"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"કનેક્શન સમસ્યા અથવા અમાન્ય MMI કોડ."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"સુવિધાને સપોર્ટ આપવામાં આવતો નથી."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ઑપરેશન ફક્ત સ્થિર ડાયલિંગ નંબર્સ પર પ્રતિબંધિત છે."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"તમે રોમિંગમાં હો તે વખતે તમારા ફોન પરથી કૉલ ફૉરવર્ડિગ સેટિંગ બદલી શકતાં નથી."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"સેવા સક્ષમ હતી."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"એપ્લિકેશનને મેમરીમાં પોતાના ભાગ સતત બનાવવાની મંજૂરી આપે છે. આ ફોનને ધીમો કરીને અન્ય ઍપ્લિકેશનો પર ઉપલબ્ધ મેમરીને સીમિત કરી શકે છે."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ઍપને ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"ઍપને \"camera\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"ઍપને \"connectedDevice\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"ઍપને \"dataSync\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"ઍપને \"location\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"ઍપને \"mediaPlayback\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"ઍપને \"mediaProjection\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"ઍપને \"microphone\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"ઍપને \"phoneCall\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"ઍપને \"health\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"ઍપને \"remoteMessaging\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ઍપને \"systemExempted\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવા ચલાવો"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ઍપને \"specialUse\" પ્રકારની પરવાનગી વડે ફૉરગ્રાઉન્ડ સેવાઓનો ઉપયોગ કરવાની મંજૂરી આપે છે"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ઍપ્લિકેશન સંગ્રહ સ્થાન માપો"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"એપ્લિકેશનને તેનો કોડ, ડેટા અને કેશ કદ પુનઃપ્રાપ્ત કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"સિસ્ટમ સેટિંગમાં ફેરફાર કરો"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"આ ઍપ ઉપયોગમાં હોય ત્યારે તે માઇક્રોફોનનો ઉપયોગ કરીને ઑડિયો રેકોર્ડ કરી શકે છે."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"બૅકગ્રાઉન્ડમાં ઑડિયો રેકોર્ડ કરો"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"આ ઍપ, માઇક્રોફોનનો ઉપયોગ કરીને કોઈપણ સમયે ઑડિયો રેકોર્ડ કરી શકે છે."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ઍપ વિન્ડોના સ્ક્રીન કૅપ્ચરની ભાળ મેળવો"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ઍપનો ઉપયોગ થઈ રહ્યો હોય ત્યારે સ્ક્રીનશૉટ લેવામાં આવે, તો આ ઍપને નોટિફિકેશન મળશે."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"સિમ ને આદેશો મોકલો"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"એપ્લિકેશનને સિમ પરા આદેશો મોકલવાની મંજૂરી આપે છે. આ ખૂબ જ ખતરનાક છે."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"શારીરિક પ્રવૃત્તિને ઓળખો"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ફોનના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"તમારા <xliff:g id="DEVICE">%1$s</xliff:g> પરથી ટૅબ્લેટના કૅમેરાનો ઍક્સેસ કરી શકતાં નથી"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"સ્ટ્રીમ કરતી વખતે આ ઍક્સેસ કરી શકાતું નથી. તેના બદલે તમારા ફોન પર પ્રયાસ કરો."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"સ્ટ્રીમ કરતી વખતે ચિત્ર-માં-ચિત્ર જોઈ શકતા નથી"</string>
     <string name="system_locale_title" msgid="711882686834677268">"સિસ્ટમ ડિફૉલ્ટ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"કાર્ડ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index c544df4..5bc7273 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"वॉइसमेल"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"कनेक्‍शन समस्‍या या अमान्‍य MMI कोड."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"यह सुविधा, इस नेटवर्क पर काम नहीं करती है."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"कार्रवाई केवल फ़िक्‍स्‍ड डायलिंग नंबर के लिए प्रतिबंधित है."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"आपके रोमिंग में होने पर, आपके फ़ोन से कॉल को दूसरे नंबर पर भेजने की सेटिंग नहीं बदली जा सकती."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"सेवा अक्षम थी."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ऐप्स को मेमोरी में स्‍वयं के कुछ हिस्सों को लगातार बनाने देता है. यह अन्‍य ऐप्स  के लिए उपलब्‍ध स्‍मृति को सीमित कर फ़ोन को धीमा कर सकता है."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"स्क्रीन पर दिखने वाली सेवा चालू करें"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ऐप्लिकेशन को स्क्रीन पर दिखने वाली सेवाएं इस्तेमाल करने दें."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"इससे ऐप्लिकेशन, \"camera\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"इससे ऐप्लिकेशन, \"connectedDevice\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"इससे ऐप्लिकेशन, \"dataSync\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"इससे ऐप्लिकेशन, \"location\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"इससे ऐप्लिकेशन, \"mediaPlayback\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"इससे ऐप्लिकेशन, \"mediaProjection\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"इससे ऐप्लिकेशन, \"microphone\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"इससे ऐप्लिकेशन, \"phoneCall\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"इससे ऐप्लिकेशन, \"health\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"इससे ऐप्लिकेशन, \"remoteMessaging\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"इससे ऐप्लिकेशन, \"systemExempted\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" टाइप वाली फ़ोरग्राउंड सेवा को चलाने की अनुमति दें"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"इससे ऐप्लिकेशन, \"specialUse\" टाइप वाली फ़ोरग्राउंड सेवाओं का इस्तेमाल कर पाता है"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"पता करें कि ऐप मेमोरी में कितनी जगह है"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ऐप को उसका कोड, डेटा, और कैश मेमोरी के आकारों को फिर से पाने देता है"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"सिस्‍टम सेटिंग बदलें"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"जब इस ऐप्लिकेशन का इस्तेमाल किया जा रहा हो, तब यह माइक्रोफ़ोन का इस्तेमाल करके ऑडियो रिकॉर्ड कर सकता है."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ऐप्लिकेशन बैकग्राउंड में ऑडियो रिकॉर्ड कर सकता है"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"यह ऐप्लिकेशन जब चाहे, माइक्रोफ़ोन का इस्तेमाल करके ऑडियो रिकॉर्ड कर सकता है."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ऐप्लिकेशन विंडो के स्क्रीन कैप्चर का पता लगाने की अनुमति दें"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"अगर ऐप्लिकेशन का इस्तेमाल करते समय कोई स्क्रीनशॉट लिया जाता है, तो इसकी सूचना इस ऐप्लिकेशन पर दिखेगी."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"सिम पर निर्देश भेजें"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ऐप को सिम पर निर्देश भेजने देती है. यह बहुत ही खतरनाक है."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"शरीर की गतिविधि को पहचानना"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से फ़ोन के कैमरे को ऐक्सेस नहीं किया जा सकता"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"आपके <xliff:g id="DEVICE">%1$s</xliff:g> से टैबलेट के कैमरे को ऐक्सेस नहीं किया जा सकता"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीमिंग के दौरान, इसे ऐक्सेस नहीं किया जा सकता. इसके बजाय, अपने फ़ोन पर ऐक्सेस करके देखें."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीमिंग करते समय, \'पिक्चर में पिक्चर\' सुविधा इस्तेमाल नहीं की जा सकती"</string>
     <string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफ़ॉल्ट"</string>
     <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e4679fe..6d6d5fe 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Govorna pošta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problem s vezom ili nevažeći MMI kôd."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Značajka nije podržana."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacija je ograničena samo na brojeve s fiksnim biranjem."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nije moguće promijeniti postavke preusmjeravanja poziva na telefonu dok ste u roamingu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Usluga je omogućena."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Aplikaciji omogućuje trajnu prisutnost nekih njenih dijelova u memoriji. To može ograničiti dostupnost memorije drugim aplikacijama i usporiti telefon."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"pokrenuti uslugu u prednjem planu"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Omogućuje aplikaciji da upotrebljava usluge koje su u prednjem planu."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"pokretanje usluge u prednjem planu s vrstom \"kamera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"fotoaparat\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"pokretanje usluge u prednjem planu s vrstom \"povezani uređaj\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"povezani uređaj\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"pokretanje usluge u prednjem planu s vrstom \"sinkroniziranje podataka\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"sinkroniziranje podataka\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"pokretanje usluge u prednjem planu s vrstom \"lokacija\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"lokacija\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"pokretanje usluge u prednjem planu s vrstom \"reprodukcija medijskih sadržaja\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"reprodukcija medijskih sadržaja\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"pokretanje usluge u prednjem planu s vrstom \"projekcija multimedija\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"projekcija multimedija\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"pokretanje usluge u prednjem planu s vrstom \"mikrofon\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"mikrofon\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"pokretanje usluge u prednjem planu s vrstom \"telefonski poziv\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"telefonski poziv\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"pokretanje usluge u prednjem planu s vrstom \"zdravlje\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"zdravlje\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"pokretanje usluge u prednjem planu s vrstom \"udaljena razmjena poruka\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"udaljena razmjena poruka\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"pokretanje usluge u prednjem planu s vrstom \"sustav je izuzeo\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"izuzeo sustav\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"pokretanje usluge u prednjem planu s vrstom \"posebna upotreba\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Omogućuje aplikaciji da iskoristi usluge u prednjem planu s vrstom \"posebna upotreba\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mjerenje prostora za pohranu aplikacije"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Aplikaciji omogućuje dohvaćanje koda, podataka i veličine predmemorije"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"izmjena postavki sustava"</string>
@@ -2341,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu telefona"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"S vašeg uređaja <xliff:g id="DEVICE">%1$s</xliff:g> nije moguće pristupiti fotoaparatu tableta"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Sadržaju nije moguće pristupiti tijekom streaminga. Pokušajte mu pristupiti na telefonu."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slika u slici ne može se prikazivati tijekom streaminga"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Zadane postavke sustava"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 68bed06..05953f0 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Hangposta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Kapcsolódási probléma vagy érvénytelen MMI-kód."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"A funkció nem támogatott."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"A művelet fix hívószámokra van korlátozva."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"A hívásátirányítási beállításokat roaming közben telefonról nem lehet módosítani."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"A szolgáltatás engedélyezésre került."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Lehetővé teszi az alkalmazás számára, hogy egyes részeit állandó jelleggel eltárolja a memóriában. Ez korlátozhatja a többi alkalmazás számára rendelkezésre álló memóriát, és lelassíthatja a telefont."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"előtérben lévő szolgáltatás futtatása"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"előtérben lévő szolgáltatás futtatása a következő típussal: „camera”"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „camera”"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"előtérben lévő szolgáltatás futtatása a következő típussal: „connectedDevice”"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „connectedDevice”"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"előtérben lévő szolgáltatás futtatása a következő típussal: „dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „dataSync”"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"előtérben lévő szolgáltatás futtatása a következő típussal: „location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „location”"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"előtérben lévő szolgáltatás futtatása a következő típussal: „mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „mediaPlayback”"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"előtérben lévő szolgáltatás futtatása a következő típussal: „mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „mediaProjection”"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"előtérben lévő szolgáltatás futtatása a következő típussal: „microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „microphone”"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"előtérben lévő szolgáltatás futtatása a következő típussal: „phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „phoneCall”"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"előtérben lévő szolgáltatás futtatása a következő típussal: „health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „health”"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"előtérben lévő szolgáltatás futtatása a következő típussal: „remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „remoteMessaging”"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"előtérben lévő szolgáltatás futtatása a következő típussal: „systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „systemExempted”"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"előtérben lévő szolgáltatás futtatása a következő típussal: „specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Engedélyezi az alkalmazásnak az előtérben lévő szolgáltatások használatát a következő típussal: „specialUse”"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"alkalmazás-tárhely felmérése"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Lehetővé teszi az alkalmazás számára a kód, az adatok és a gyorsítótár-méret lekérését"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"rendszerbeállítások módosítása"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Az alkalmazás a mikrofon használatával akkor készíthet hangfelvételt, amikor az alkalmazás használatban van."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"hangfelvétel készítése a háttérben"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Az alkalmazás a mikrofon használatával bármikor készíthet hangfelvételt."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"alkalmazásablakokról készült képernyőfelvétel észlelése"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ez az alkalmazás értesítést kap majd, amikor képernyőkép készül az alkalmazás használata közben."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"parancsok küldése a SIM-kártyára"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Engedélyezi, hogy az alkalmazás parancsokat küldjön a SIM kártyára. Ez rendkívül veszélyes lehet."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"testmozgás felismerése"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nem lehet hozzáférni a telefon kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nem lehet hozzáférni a táblagép kamerájához a következő eszközön: <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Ehhez a tartalomhoz nem lehet hozzáférni streamelés közben. Próbálja újra a telefonján."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Streamelés közben nem lehetséges a kép a képben módban való lejátszás"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Rendszerbeállítás"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KÁRTYA: <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 4f053f3..7f8898e 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Ձայնային փոստ"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Միացման խնդիր կամ անվավեր MMI ծածակագիր:"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Գործառույթը չի աջակցվում։"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Գործողությունը սահմանափակված է միայն ամրակայված հեռախոսահամարների համար:"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Ռոումինգում չեք կարող փոխել զանգի վերահասցեավորման կարգավորումները ձեր հեռախոսից։"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Ծառայությունը միացված է:"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Թույլ է տալիս հավելվածին մնայուն դարձնել իր մասերը հիշողության մեջ: Սա կարող է սահմանափակել այլ հավելվածներին հասանելի հիշողությունը` դանդաղեցնելով հեռախոսի աշխատանքը:"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"աշխատեցնել ակտիվ ծառայությունները"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Թույլ է տալիս հավելվածին օգտագործել ակտիվ ծառայությունները:"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"գործարկել camera տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Հավելվածին թույլ է տալիս օգտագործել camera տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"գործարկել connectedDevice տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Հավելվածին թույլ է տալիս օգտագործել connectedDevice տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"գործարկել dataSync տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Հավելվածին թույլ է տալիս օգտագործել dataSync տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"գործարկել location տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Հավելվածին թույլ է տալիս օգտագործել location տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"գործարկել mediaPlayback տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Հավելվածին թույլ է տալիս օգտագործել mediaPlayback տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"գործարկել mediaProjection տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Հավելվածին թույլ է տալիս օգտագործել mediaProjection տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"գործարկել microphone տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Հավելվածին թույլ է տալիս օգտագործել microphone տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"գործարկել phoneCall տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Հավելվածին թույլ է տալիս օգտագործել phoneCall տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"գործարկել health տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Հավելվածին թույլ է տալիս օգտագործել health տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"գործարկել remoteMessaging տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Հավելվածին թույլ է տալիս օգտագործել remoteMessaging տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"գործարկել systemExempted տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Հավելվածին թույլ է տալիս օգտագործել systemExempted տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"գործարկել specialUse տեսակով ակտիվ ծառայությունները"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Հավելվածին թույլ է տալիս օգտագործել specialUse տեսակով ակտիվ ծառայությունները"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"չափել հավելվածի պահոցի տարածքը"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Թույլ է տալիս հավելվածին առբերել իր կոդը, տվյալները և քեշի չափերը"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"փոփոխել համակարգի կարգավորումները"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Այս հավելվածը կարող է օգտագործել խոսափողը՝ ձայնագրություններ անելու համար, միայն երբ հավելվածն ակտիվ է։"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ձայնագրել ֆոնային ռեժիմում"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Այս հավելվածը կարող է ցանկացած ժամանակ օգտագործել խոսափողը՝ ձայնագրություններ անելու համար։"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"հայտնաբերել հավելվածի պատուհանների էկրանի տեսագրումները"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Եթե հավելվածի օգտագործման ժամանակ սքրինշոթ արվի, հավելվածը ծանուցում կստանա։"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ուղարկել հրամաններ SIM քարտին"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Թույլ է տալիս հավելվածին հրամաններ ուղարկել SIM-ին: Սա շատ վտանգավոր է:"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ֆիզիկական ակտիվության ճանաչում"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Հնարավոր չէ օգտագործել հեռախոսի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Հնարավոր չէ օգտագործել պլանշետի տեսախցիկը ձեր <xliff:g id="DEVICE">%1$s</xliff:g> սարքից"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Այս բովանդակությունը հասանելի չէ հեռարձակման ընթացքում։ Օգտագործեք ձեր հեռախոսը։"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Հեռարձակման ժամանակ հնարավոր չէ դիտել նկարը նկարի մեջ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Կանխադրված"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ՔԱՐՏ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 882fb41..79ee0e8 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Pesan suara"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Masalah sambungan atau kode MMI tidak valid."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Fitur tidak didukung."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operasi dibatasi untuk nomor panggilan tetap saja."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Tidak dapat mengubah setelan penerusan panggilan dari ponsel saat roaming"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Layanan telah diaktifkan."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Memungkinkan aplikasi membuat bagian dari dirinya sendiri terus-menerus berada dalam memori. Izin ini dapat membatasi memori yang tersedia untuk aplikasi lain sehingga menjadikan ponsel lambat."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"jalankan layanan di latar depan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Mengizinkan aplikasi menggunakan layanan di latar depan."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"menjalankan layanan latar depan dengan jenis \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"menjalankan layanan latar depan dengan jenis \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"menjalankan layanan latar depan dengan jenis \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"menjalankan layanan latar depan dengan jenis \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"menjalankan layanan latar depan dengan jenis \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"menjalankan layanan latar depan dengan jenis \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"menjalankan layanan latar depan dengan jenis \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"menjalankan layanan latar depan dengan jenis \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"menjalankan layanan latar depan dengan jenis \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"menjalankan layanan latar depan dengan jenis \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"menjalankan layanan latar depan dengan jenis \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"menjalankan layanan latar depan dengan jenis \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Mengizinkan aplikasi menggunakan layanan latar depan dengan jenis \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mengukur ruang penyimpanan aplikasi"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Mengizinkan apl mengambil kode, data, dan ukuran temboloknya"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ubah setelan sistem"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Aplikasi ini dapat merekam audio menggunakan mikrofon saat aplikasi sedang digunakan."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"merekam audio di latar belakang"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Aplikasi ini dapat merekam audio menggunakan mikrofon kapan saja."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"mendeteksi screenshot jendela aplikasi"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Aplikasi ini akan diberi tahu saat screenshot diambil dan aplikasi sedang digunakan."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"kirimkan perintah ke SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Mengizinkan aplikasi mengirim perintah ke SIM. Ini sangat berbahaya."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"kenali aktivitas fisik"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera ponsel dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet dari <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Konten ini tidak dapat diakses saat melakukan streaming. Coba di ponsel."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat menampilkan picture-in-picture saat streaming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Default sistem"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTU <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 919276e..5343d23 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Talhólf"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Vandamál með tengingu eða ógild MMI-kóðaskipun."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Eiginleiki ekki studdur."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Aðgerð takmarkast við fast númeraval."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Ekki er hægt að breyta stillingum fyrir framsendingu símtala úr símanum á meðan þú ert í reiki."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Þjónustan var virkjuð."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Leyfir forriti að gera hluta sjálfs sín varanlega í minni. Þetta getur takmarkað það minni sem býðst öðrum forritum og þannig hægt á símanum."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"keyra þjónustu í forgrunni"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Leyfir forritinu að nota þjónustu sem er í forgrunni."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"keyra forgrunnsþjónustu af gerðinni „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"keyra forgrunnsþjónustu af gerðinni „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"keyra forgrunnsþjónustu af gerðinni „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"keyra forgrunnsþjónustu af gerðinni „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"keyra forgrunnsþjónustu af gerðinni „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"keyra forgrunnsþjónustu af gerðinni „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"keyra forgrunnsþjónustu af gerðinni „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"keyra forgrunnsþjónustu af gerðinni „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"keyra forgrunnsþjónustu af gerðinni „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"keyra forgrunnsþjónustu af gerðinni „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"keyra forgrunnsþjónustu af gerðinni „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"keyra forgrunnsþjónustu af gerðinni „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Leyfir forritinu að nota forgrunnsþjónustu af gerðinni „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mæla geymslurými forrits"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Leyfir forriti að sækja stærðir kóða, gagna og skyndiminnis síns."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"breyta kerfisstillingum"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Þetta forrit getur tekið upp hljóð með hljóðnemanum meðan forritið er í notkun."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"taka upp hljóð í bakgrunni"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Þetta forrit getur tekið upp hljóð með hljóðnemanum hvenær sem er."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"greina skjáupptöku í forritagluggum"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Tilkynning berst til forritsins þegar skjámynd er tekin á meðan forritið er í notkun."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"senda skipanir til SIM-kortsins"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Leyfir forriti að senda SIM-kortinu skipanir. Þetta er mjög hættulegt."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"greina hreyfingu"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ekki er hægt að opna myndavél símans úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ekki er hægt að opna myndavél spjaldtölvunnar úr <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Ekki er hægt að opna þetta á meðan streymi stendur yfir. Prófaðu það í símanum í staðinn."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ekki er hægt að horfa á mynd í mynd á meðan streymi er í gangi"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sjálfgildi kerfis"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index beb15d2..64c4fd5 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Segreteria"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema di connessione o codice MMI non valido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funzionalità non supportata."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operazione limitata solo ai numeri di selezione fissa."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Impossibile modificare le impostazioni di deviazione chiamate dal telefono durante il roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Il servizio è stato attivato."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Consente all\'applicazione di rendere persistenti in memoria alcune sue parti. Ciò può limitare la memoria disponibile per altre applicazioni, rallentando il telefono."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"esecuzione servizio in primo piano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Consente all\'app di utilizzare i servizi in primo piano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"Esecuzione di servizi in primo piano con il tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Consente all\'app di usare i servizi in primo piano con il tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"Esecuzione di servizi in primo piano con il tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Consente all\'app di usare i servizi in primo piano con il tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"Esecuzione di servizi in primo piano con il tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Consente all\'app di usare i servizi in primo piano con il tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"Esecuzione di servizi in primo piano con il tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Consente all\'app di usare i servizi in primo piano con il tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"Esecuzione di servizi in primo piano con il tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Consente all\'app di usare i servizi in primo piano con il tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"Esecuzione di servizi in primo piano con il tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Consente all\'app di usare i servizi in primo piano con il tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"Esecuzione di servizi in primo piano con il tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Consente all\'app di usare i servizi in primo piano con il tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"Esecuzione di servizi in primo piano con il tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Consente all\'app di usare i servizi in primo piano con il tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"Esecuzione di servizi in primo piano con il tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Consente all\'app di usare i servizi in primo piano con il tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"Esecuzione di servizi in primo piano con il tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Consente all\'app di usare i servizi in primo piano con il tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"Esecuzione di servizi in primo piano con il tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Consente all\'app di usare i servizi in primo piano con il tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"Esecuzione di servizi in primo piano con il tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Consente all\'app di usare i servizi in primo piano con il tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"calcolo spazio di archiviazione applicazioni"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Consente all\'applicazione di recuperare il suo codice, i suoi dati e le dimensioni della cache"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifica delle impostazioni di sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Questa app può registrare audio tramite il microfono mentre l\'app è in uso."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Registrazione di audio in background"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Questa app può registrare audio tramite il microfono in qualsiasi momento."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"rileva le acquisizioni schermo delle finestre dell\'app"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Questa app riceverà una notifica quando viene acquisito uno screenshot mentre è in uso."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"invio di comandi alla SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"riconoscimento dell\'attività fisica"</string>
@@ -2013,7 +1988,7 @@
     <string name="app_streaming_blocked_message_for_fingerprint_dialog" product="default" msgid="8552691971910603907">"Questa app richiede maggiore sicurezza. Prova a usare il telefono."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tv" msgid="820334666354451145">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il dispositivo Android TV."</string>
     <string name="app_streaming_blocked_message_for_settings_dialog" product="tablet" msgid="3286849551133045896">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il tablet."</string>
-    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Non è possibile accedere a questa impostazione su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il telefono."</string>
+    <string name="app_streaming_blocked_message_for_settings_dialog" product="default" msgid="6264287556598916295">"Non è possibile accedere su <xliff:g id="DEVICE">%1$s</xliff:g>. Prova a usare il telefono."</string>
     <string name="deprecated_target_sdk_message" msgid="5246906284426844596">"Questa app è stata progettata per una versione precedente di Android. Potrebbe non funzionare correttamente e non include le protezioni della sicurezza e della privacy più recenti. Verifica la presenza di un aggiornamento o contatta lo sviluppatore dell\'app."</string>
     <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca aggiornamenti"</string>
     <string name="new_sms_notification_title" msgid="6528758221319927107">"Hai nuovi messaggi"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Impossibile accedere alla fotocamera del telefono dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Impossibile accedere alla fotocamera del tablet dal tuo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Impossibile accedere a questi contenuti durante lo streaming. Prova a usare il telefono."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Impossibile visualizzare Picture in picture durante lo streaming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predefinita di sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SCHEDA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 34f4bee..a6c0383 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"דואר קולי"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"‏בעיה בחיבור או קוד MMI לא חוקי."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"התכונה לא נתמכת."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"הפעולה מוגבלת למספרי חיוג קבועים בלבד."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"לא ניתן לשנות את הגדרות העברת השיחות מהטלפון במצב נדידה."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"השירות הופעל."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"מאפשרת לאפליקציה להפוך חלקים ממנה לקבועים בזיכרון. הפעולה הזו עשויה להגביל את הזיכרון הזמין לאפליקציות אחרות ולהאט את פעולת הטלפון."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"הפעלת שירות בחזית"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"‏הפעלת שירות שפועל בחזית מסוג \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"‏הפעלת שירות שפועל בחזית מסוג \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"‏הפעלת שירות שפועל בחזית מסוג \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"‏הפעלת שירות שפועל בחזית מסוג \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"‏הפעלת שירות שפועל בחזית מסוג \'mediaPlayback\'"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"‏הפעלת שירות שפועל בחזית מסוג \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"‏הפעלת שירות שפועל בחזית מסוג \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"‏הפעלת שירות שפועל בחזית מסוג \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"‏הפעלת שירות שפועל בחזית מסוג \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"‏הפעלת שירות שפועל בחזית מסוג \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"‏הפעלת שירות שפועל בחזית מסוג \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"‏הפעלת שירות שפועל בחזית מסוג \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"‏ההרשאה הזו מאפשרת לאפליקציה להשתמש בשירותים שפועלים בחזית מסוג \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"מדידת נפח האחסון של אפליקציות"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"מאפשרת לאפליקציה לאחזר את הקוד, הנתונים, ואת גודל קובצי המטמון שלה"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"שינוי הגדרות מערכת"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"האפליקציה הזו יכולה להשתמש במיקרופון כדי להקליט אודיו כאשר היא בשימוש."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"הקלטת אודיו ברקע"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"האפליקציה הזו יכולה להשתמש במיקרופון כדי להקליט אודיו בכל זמן."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"זיהוי צילומי מסך של חלונות האפליקציה"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"לאפליקציה הזו תישלח התראה אם יצולם צילום מסך בזמן שהיא בשימוש."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"‏שליחת פקודות אל ה-SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"‏מאפשרת לאפליקציה לשלוח פקודות ל-SIM. זוהי הרשאה מסוכנת מאוד."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"זיהוי של פעילות גופנית"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index da7e387..9bcde38 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"留守番電話"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"接続に問題があるか、MMIコードが正しくありません。"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"サポートされていません。"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"発信番号制限で指定された番号に対してのみ操作できます。"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ローミング中はスマートフォンから着信転送設定の変更はできません。"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"サービスが有効になりました。"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"アプリにその一部をメモリに常駐させることを許可します。これにより他のアプリが使用できるメモリが制限されるため、モバイル デバイスの動作が遅くなることがあります。"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"フォアグラウンド サービスの実行"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"フォアグラウンド サービスの使用をアプリに許可します。"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"タイプが「camera」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"タイプが「camera」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"タイプが「connectedDevice」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"タイプが「connectedDevice」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"タイプが「dataSync」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"タイプが「dataSync」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"タイプが「location」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"タイプが「location」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"タイプが「mediaPlayback」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"タイプが「mediaPlayback」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"タイプが「mediaProjection」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"タイプが「mediaProjection」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"タイプが「microphone」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"タイプが「microphone」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"タイプが「phoneCall」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"タイプが「phoneCall」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"タイプが「health」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"タイプが「health」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"タイプが「remoteMessaging」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"タイプが「remoteMessaging」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"タイプが「systemExempted」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"タイプが「systemExempted」のフォアグラウンド サービスの使用をアプリに許可します"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"タイプが「specialUse」のフォアグラウンド サービスの実行"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"タイプが「specialUse」のフォアグラウンド サービスの使用をアプリに許可します"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"アプリのストレージ容量の計測"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"アプリのコード、データ、キャッシュサイズを取得することをアプリに許可します"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"システム設定の変更"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 664a25c..92a37ce 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ხმოვანი ფოსტა"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"კავშირის პრობლემა ან არასწორი MMI კოდი."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ფუნქცია მხარდაუჭერელია."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ოპერაცია შეზღუდულია მხოლოდ დაშვებულ ნომრებზე."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ზარის გადამისამართების პარამეტრების თქვენი ტელეფონიდან შეცვლა როუმინგისას ვერ მოხერხდება."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"სერვისი ჩართულია."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"აპს შეეძლება, საკუთარი ნაწილები მუდმივად ჩაწეროს მეხსიერებაში. ეს შეზღუდავს მეხსიერების ხელმისაწვდომობას სხვა აპებისთვის და შეანელებს ტელეფონს."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"წინა პლანის სერვისის გაშვება"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"აპს შეეძლება, გამოიყენოს წინა პლანის სერვისები."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"პრიორიტეტული სერვისის გაშვება ტიპის „კამერა“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „კამერა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"პრიორიტეტული სერვისის გაშვება ტიპის „დაკავშირებულიმოწყობილობა“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „დაკავშირებულიმოწყობილობა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"პრიორიტეტული სერვისის გაშვება ტიპის „მონაცემებისსინქრონიზაცია“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „მონაცემებისსინქრონიზაცია“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"პრიორიტეტული სერვისის გაშვება ტიპის „მდებარეობა“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „მდებარეობა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"პრიორიტეტული სერვისის გაშვება ტიპის „მედია-ფაილებისდაკვრა“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „მედია-ფაილებისდაკვრა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"პრიორიტეტული სერვისის გაშვება ტიპის „მედიაპროეცირება“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „მედიაპროეცირება“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"პრიორიტეტული სერვისის გაშვება ტიპის „მიკროფონი“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „მიკროფონი“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"პრიორიტეტული სერვისის გაშვება ტიპის „სატელეფონოზარი“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „სატელეფონოზარი“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"პრიორიტეტული სერვისის გაშვება ტიპის „ჯანმრთელობა“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „ჯანმრთელობა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"პრიორიტეტული სერვისის გაშვება ტიპის „დისტანციურიშეტყობინებები“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „დისტანციურიშეტყობინებები“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"პრიორიტეტული სერვისის გაშვება ტიპის \"გათავისუფლებულისისტემა\" შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „გათავისუფლებულისისტემა“ შემთხვევაში"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"პრიორიტეტული სერვისის გაშვება ტიპის „სპეციალურიგამოყენება“ შემთხვევაში"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ნებას რთავს აპს, გამოიყენოს პრიორიტეტული სერვისები ტიპის „სპეციალურიგამოყენება“ შემთხვევაში"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"აპის მეხსიერების სივრცის გაზომვა"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"აპს შეეძლება, მოიპოვოს თავისი კოდი, მონაცემები და ქეშის ზომები."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"სისტემის პარამეტრების შეცვლა"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ტელეფონის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ტაბლეტის კამერაზე წვდომა ვერ მოხერხდა თქვენი <xliff:g id="DEVICE">%1$s</xliff:g>-დან"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"მასზე წვდომის მიᲦება შეუძლებელია სტრიმინგის დროს. ცადეთ ტელეფონიდან."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"სტრიმინგის დროს ეკრანის ეკრანში ნახვა შეუძლებელია"</string>
     <string name="system_locale_title" msgid="711882686834677268">"სისტემის ნაგულისხმევი"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ბარათი <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 14da390..04f0445 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Дауыстық пошта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Байланыс мәселесі немесе MMИ коды жарамсыз."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функция қолданылмайды."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Әрекет анықталған сандарды теруге шектелген."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Роуминг кезінде телефоннан қоңырауды басқа нөмірге бағыттау параметрлері өзгертілмейді."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Қызмет қосылған."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Қолданбаға өзінің бөліктерін жадта бекіндіру мүмкіндігін береді. Бұл басқа қолданбалардың жадқа қол жетімділігін шектеп, телефонды баяулатуы мүмкін."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"басымдылығы жоғары қызметті іске қосу"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Қолданбаға басымдылығы жоғары қызметтерді пайдалануға рұқсат береді."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Қолданбаға \"camera\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"health\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Қолданбаға \"connectedDevice\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Қолданбаға \"dataSync\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Қолданбаға \"location\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Қолданбаға \"mediaPlayback\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Қолданбаға \"mediaProjection\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Қолданбаға \"microphone\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Қолданбаға \"phoneCall\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Қолданбаға \"health\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Қолданбаға \"remoteMessaging\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Қолданбаға \"systemExempted\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" түріне жататын экрандық режимдегі қызметті іске қосу"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Қолданбаға \"specialUse\" түріне жататын экрандық режимдегі қызметтерді пайдалануға рұқсат беріледі."</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"қолданба жадындағы бос орынды өлшеу"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Қолданбаға оның кодын, деректерін және кэш өлшемдерін шығарып алуға рұқсат береді"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"жүйе параметрлерін өзгерту"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Бұл қолданба жұмыс барысында микрофон арқылы аудиомазмұн жаза алады."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Фондық режимде аудиомазмұн жазу"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Бұл қолданба кез келген уақытта микрофон арқылы аудиомазмұн жаза алады."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"қолданба терезелерінің скриншоттарын анықтау"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Қолданбаны пайдаланып скриншот жасаған кезде, ескерту шығады."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM картасына пәрмендер жіберу"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Қолданбаға SIM картасына пәрмен жіберу мүмкіндігін береді. Бұл өте қауіпті."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"физикалық әрекетті тану"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан телефон камерасын пайдалану мүмкін емес."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> құрылғысынан планшет камерасын пайдалану мүмкін емес."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Трансляция кезінде мазмұнды көру мүмкін емес. Оның орнына телефоннан көріңіз."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Трансляция кезінде суреттегі суретті көру мүмкін емес."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Жүйенің әдепкі параметрі"</string>
     <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g>-КАРТА"</string>
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index fc1a49c..1477713 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"សារ​ជា​សំឡេង"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"បញ្ហា​ក្នុង​ការ​តភ្ជាប់​ ឬ​កូដ MMI មិន​ត្រឹមត្រូវ។"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"មិនអាចប្រើមុខងារនេះបានទេ។"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ប្រតិបត្តិការ​ត្រូវ​បាន​ដាក់​កម្រិត​​​ចំពោះ​លេខ​ហៅ​ថេរ​តែ​ប៉ុណ្ណោះ។"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"មិន​អាច​ប្តូរ​ការ​កំណត់​នៃ​ការ​បញ្ជូន​ការ​ហៅ​បន្ត​ពី​ទូរសព្ទ​របស់​អ្នក​បាន​ទេ​ ខណៈ​ពេល​ដែល​អ្នក​កំពុង​ប្រើ​សេវា​រ៉ូមីង។"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"បាន​បើក​សេវាកម្ម។"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ឲ្យ​កម្មវិធី ធ្វើជា​ផ្នែក​អចិន្ត្រៃយ៍​នៃ​ខ្លួន​ក្នុង​អង្គ​ចងចាំ។ វា​អាច​កម្រិត​អង្គ​ចងចាំ​អាច​ប្រើ​បាន​ ដើម្បី​ធ្វើ​ឲ្យ​កម្មវិធី​ផ្សេង​ធ្វើ​ឲ្យ​ទូរស័ព្ទ​របស់​អ្នក​យឺត។​"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ដំណើរ​ការ​សេវាកម្ម​ផ្ទៃ​ខាង​មុខ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"អនុញ្ញាត​ឱ្យ​កម្មវិធី​ប្រើ​ប្រាស់​សេវាកម្ម​ផ្ទៃខាង​មុខ។"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ដំណើរការសេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"អនុញ្ញាតឱ្យកម្មវិធីប្រើប្រាស់សេវាកម្មផ្ទៃខាងមុខជាមួយនឹងប្រភេទ \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"វាស់​ទំហំ​ការ​ផ្ទុក​​កម្មវិធី"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ឲ្យ​កម្មវិធី​ទៅ​យក​កូដ ទិន្នន័យ និង​ទំហំ​ឃ្លាំង​សម្ងាត់​របស់​វា"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"កែ​​ការ​កំណត់​ប្រព័ន្ធ"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"កម្មវិធី​នេះ​អាច​ថតសំឡេងដោយប្រើមីក្រូហ្វូន នៅពេលកំពុងប្រើប្រាស់កម្មវិធី។"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ថតសំឡេងនៅផ្ទៃខាងក្រោយ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"កម្មវិធី​នេះ​អាច​ថត​សំឡេង​ដោយ​ប្រើ​មីក្រូហ្វូន​បាន​គ្រប់​ពេល។"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"រកឃើញការថត​អេក្រង់វិនដូកម្មវិធី"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"កម្មវិធី​នេះ​នឹង​ទទួល​បាន​ការ​ជូន​ដំណឹង​នៅ​ពេល​រូបថត​អេក្រង់ត្រូវបានថត ​ខណៈ​ពេល​​​កំពុង​ប្រើកម្មវិធី​នេះ។"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ផ្ញើពាក្យបញ្ជាទៅស៊ីមកាត"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ឲ្យ​កម្មវិធី​ផ្ញើ​ពាក្យ​បញ្ជា​ទៅ​ស៊ីម​កាត។ វា​គ្រោះ​ថ្នាក់​ណាស់។"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ស្គាល់​សកម្មភាព​រាងកាយ"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"មិនអាច​ចូលប្រើ​កាមេរ៉ាទូរសព្ទ​ពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​បានទេ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"មិនអាច​ចូលប្រើ​កាមេរ៉ា​ថេប្លេតពី <xliff:g id="DEVICE">%1$s</xliff:g> របស់អ្នក​បានទេ"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"មិន​អាច​ចូល​ប្រើប្រាស់​ខ្លឹមសារ​នេះ​បាន​ទេ ពេល​ផ្សាយ។ សូមសាកល្បងប្រើ​នៅលើ​ទូរសព្ទរបស់អ្នក​ជំនួសវិញ។"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"មិនអាចមើលរូបក្នុងរូបខណៈពេលកំពុងផ្សាយបានទេ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"លំនាំ​ដើម​ប្រព័ន្ធ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"កាត <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 7ca2dff..b5535c9 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ಧ್ವನಿಮೇಲ್"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ಸಂಪರ್ಕ ಸಮಸ್ಯೆ ಇಲ್ಲವೇ ಅಮಾನ್ಯ MMI ಕೋಡ್."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ಫೀಚರ್ ಬಂಬಲಿಸುತ್ತಿಲ್ಲ."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ಕಾರ್ಯಾಚರಣೆಯನ್ನು ಸ್ಥಿರ ದೂರವಾಣಿ ಸಂಖ್ಯೆಗಳಿಗೆ ಮಾತ್ರ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ನೀವು ರೋಮಿಂಗ್‌ನಲ್ಲಿರುವಾಗ ನಿಮ್ಮ ಫೋನ್‌ನಿಂದ ಕರೆ ಫಾರ್ವರ್ಡ್ ಮಾಡುವಿಕೆಯ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"ಸೇವೆಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ಸ್ಮರಣೆಯಲ್ಲಿ ನಿರಂತರವಾಗಿ ತನ್ನದೇ ಭಾಗಗಳನ್ನು ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಇದು ಫೋನ್ ಕಾರ್ಯವನ್ನು ನಿಧಾನಗೊಳಿಸುವುದರ ಮೂಲಕ ಇತರ ಅಪ್ಲಿಕೇಶನ್‍‍ಗಳಿಗೆ ಲಭ್ಯವಿರುವ ಸ್ಮರಣೆಯನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್‌ ಮಾಡಿ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡಿ."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"ಕ್ಯಾಮರಾ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"ಕ್ಯಾಮರಾ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"ಸ್ಥಳ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"ಸ್ಥಳ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"ಮೈಕ್ರೊಫೋನ್‌\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"ಮೈಕ್ರೊಫೋನ್‌\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"ಅರೋಗ್ಯ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"ಅರೋಗ್ಯ\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಯನ್ನು ರನ್ ಮಾಡಿ"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" ಪ್ರಕಾರದೊಂದಿಗೆ ಮುನ್ನೆಲೆ ಸೇವೆಗಳನ್ನು ಬಳಸಲು ಆ್ಯಪ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ಅಪ್ಲಿಕೇಶನ್‌ ಸಂಗ್ರಹ ಸ್ಥಳವನ್ನು ಅಳೆಯಿರಿ"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ಅದರ ಕೋಡ್‌‌, ಡೇಟಾ, ಮತ್ತು ಕ್ಯಾಷ್‌ ಗಾತ್ರಗಳನ್ನು ಹಿಂಪಡೆಯಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ಸಿಸ್ಟಂ ಸೆಟ್ಟಿಂಗ್‍ಗಳನ್ನು ಮಾರ್ಪಡಿಸಿ"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಈ ಆ್ಯಪ್ ಮೈಕ್ರೊಫೋನ್ ಬಳಸಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಆಡಿಯೊವನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ಈ ಆ್ಯಪ್ ಮೈಕ್ರೋಫೋನ್ ಬಳಸುವ ಮೂಲಕ ಯಾವುದೇ ಸಮಯದಲ್ಲಾದರೂ ಆಡಿಯೋ ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದು."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ಆ್ಯಪ್ ವಿಂಡೋಗಳ ಸ್ಕ್ರೀನ್ ಕ್ಯಾಪ್ಚರ್‌ಗಳನ್ನು ಪತ್ತೆ ಮಾಡಿ"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ಆ್ಯಪ್ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಸ್ಕ್ರೀನ್‌ಶಾಟ್ ಒಂದನ್ನು ತೆಗೆದುಕೊಂಡಾಗ ಈ ಆ್ಯಪ್ ಸೂಚನೆಯನ್ನು ಪಡೆಯುತ್ತದೆ."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ಸಿಮ್‌ಗೆ ಆಜ್ಞೆಗಳನ್ನು ಕಳುಹಿಸಿ"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ಸಿಮ್‌ ಗೆ ಆದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ತುಂಬಾ ಅಪಾಯಕಾರಿ."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ದೈಹಿಕ ಚಟುವಟಿಕೆಯನ್ನು ಗುರುತಿಸಿ"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಫೋನ್‌ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ನಿಮ್ಮ <xliff:g id="DEVICE">%1$s</xliff:g> ಮೂಲಕ ಟ್ಯಾಬ್ಲೆಟ್‌ನ ಕ್ಯಾಮರಾವನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಇದನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. ಅದರ ಬದಲು ನಿಮ್ಮ ಫೋನ್‌ನಲ್ಲಿ ಪ್ರಯತ್ನಿಸಿ."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ಸ್ಟ್ರೀಮ್ ಮಾಡುವಾಗ ಚಿತ್ರದಲ್ಲಿ ಚಿತ್ರವನ್ನು ವೀಕ್ಷಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ಸಿಸ್ಟಂ ಡೀಫಾಲ್ಟ್"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ಕಾರ್ಡ್ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a3a2f22..aa6feae 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"음성사서함"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"연결에 문제가 있거나 MMI 코드가 잘못되었습니다."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"기능이 지원되지 않습니다."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"발신 허용 번호에서만 수행할 수 있는 작업입니다."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"로밍 중에는 착신 전환 설정을 변경할 수 없습니다."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"서비스를 사용하도록 설정했습니다."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"앱이 그 일부분을 영구적인 메모리로 만들 수 있도록 허용합니다. 이렇게 하면 다른 앱이 사용할 수 있는 메모리를 제한하여 휴대전화의 속도를 저하시킬 수 있습니다."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"포그라운드 서비스 실행"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"앱에서 포그라운드 서비스를 사용하도록 허용합니다."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\'camera\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"앱에서 \'camera\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\'connectedDevice\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"앱에서 \'connectedDevice\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\'dataSync\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"앱에서 \'dataSync\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\'location\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"앱에서 \'location\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\'mediaPlayback\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"앱에서 \'mediaPlayback\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\'mediaProjection\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"앱에서 \'mediaProjection\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\'microphone\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"앱에서 \'microphone\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\'phoneCall\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"앱에서 \'phoneCall\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\'health\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"앱에서 \'health\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\'remoteMessaging\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"앱에서 \'remoteMessaging\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\'systemExempted\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"앱에서 \'systemExempted\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\'specialUse\' 유형의 포그라운드 서비스 실행"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"앱에서 \'specialUse\' 유형의 포그라운드 서비스를 사용하도록 허용합니다."</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"앱 저장공간 계산"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"앱이 해당 코드, 데이터 및 캐시 크기를 검색할 수 있도록 허용합니다."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"시스템 설정 수정"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"앱을 사용하는 동안 앱에서 마이크를 사용하여 오디오를 녹음할 수 있습니다."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"백그라운드에서 오디오 녹음"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"언제든지 앱에서 마이크를 사용하여 오디오를 녹음할 수 있습니다."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"앱 창 화면 캡처 감지"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"앱이 사용 중일 때 스크린샷을 찍으면 알림이 전송됩니다."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM 카드로 명령 전송"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"앱이 SIM에 명령어를 전송할 수 있도록 허용합니다. 이 기능은 매우 신중히 허용해야 합니다."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"신체 활동 확인"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 휴대전화 카메라에 액세스할 수 없습니다."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"사용자의 <xliff:g id="DEVICE">%1$s</xliff:g>에서 태블릿 카메라에 액세스할 수 없습니다."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"스트리밍 중에는 액세스할 수 없습니다. 대신 휴대전화에서 시도해 보세요."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"스트리밍 중에는 PIP 모드를 볼 수 없습니다."</string>
     <string name="system_locale_title" msgid="711882686834677268">"시스템 기본값"</string>
     <string name="default_card_name" msgid="9198284935962911468">"<xliff:g id="CARDNUMBER">%d</xliff:g> 카드"</string>
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 92943d0..8201c50 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Үн почтасы"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Туташууда көйгөй чыкты же MMI коду жараксыз."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функция колдоого алынбайт."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Иш-аракет туруктуу терүү номерлери менен гана чектелет."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Роуминг учурунда чалууну башка номерге багыттоонун жөндөөлөрүн телефонуңуздан өзгөртүү мүмкүн эмес."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Кызмат иштетилди."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Колдонмого  өзүнүн бөлүктөрүн эстутумда туруктуу кармоого уруксат берет. Бул эстутумдун башка колдонмолорго жетиштүүлүгүн чектеши жана телефондун иштешин жайлатышы мүмкүн."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"активдүү кызматты иштетүү"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Колдонмолорго алдынкы пландагы кызматтарды колдонууга уруксат берет."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"алдынкы пландагы \"camera\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Колдонмолорго алдынкы пландагы \"camera\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"алдынкы пландагы \"connectedDevice\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Колдонмолорго алдынкы пландагы \"connectedDevice\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"алдынкы пландагы \"dataSync\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Колдонмолорго алдынкы пландагы \"dataSync\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"алдынкы пландагы \"location\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Колдонмолорго алдынкы пландагы \"location\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"алдынкы пландагы \"mediaPlayback\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Колдонмолорго алдынкы пландагы \"mediaPlayback\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"алдынкы пландагы \"mediaProjection\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Колдонмолорго алдынкы пландагы \"mediaProjection\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"алдынкы пландагы \"microphone\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Колдонмолорго алдынкы пландагы \"microphone\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"алдынкы пландагы \"phoneCall\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Колдонмолорго алдынкы пландагы \"phoneCall\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"алдынкы пландагы \"health\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Колдонмолорго алдынкы пландагы \"health\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"алдынкы пландагы \"remoteMessaging\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Колдонмолорго алдынкы пландагы \"remoteMessaging\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"алдынкы пландагы \"systemExempted\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Колдонмолорго алдынкы пландагы \"systemExempted\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"алдынкы пландагы \"specialUse\" түрүндөгү кызматты аткаруу"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Колдонмолорго алдынкы пландагы \"specialUse\" түрүндөгү кызматтарды колдонууга уруксат берет"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"колдонмо сактагычынын мейкиндигин өлчөө"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Колдонмого өз кодун, дайындарын жана кэш өлчөмдөрүн түшүрүп алуу мүмкүнчүлүгүн берет"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"система тууралоолорун өзгөртүү"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Бул колдонмо иштеп жатканда микрофон менен аудио файлдарды жаздыра алат."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Фондо аудио жаздыруу"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Бул колдонмо каалаган убакта микрофон менен аудио файлдарды жаздыра алат."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"колдонмонун терезелериндегилер сүрөткө тартылганын аныктоо"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Колдонмо иштеп жатканда скриншот тартылса, колдонмого кабарланат."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM-картага буйруктарды жөнөтүү"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Колдонмого SIM-картага буйруктарды жөнөтүү мүмкүнчүлүгүн берет. Бул абдан кооптуу."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"Кыймыл-аракетти аныктоо"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн телефондун камерасына мүмкүнчүлүк жок"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүңүздөн планшетиңиздин камерасына мүмкүнчүлүк жок"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Муну алып ойнотуу учурунда көрүүгө болбойт. Анын ордуна телефондон кирип көрүңүз."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Алып ойнотуп жатканда сүрөттөгү сүрөт көрүнбөйт"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Системанын демейки параметрлери"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 0f73d68..d7b77bfc 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ຂໍ້ຄວາມສຽງ"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ມີບັນຫາໃນການເຊື່ອມຕໍ່ ຫຼືລະຫັດ MMI ບໍ່ຖືກຕ້ອງ."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ບໍ່ຮອງຮັບຄຸນສົມບັດ."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ການດຳເນີນການຖືກຈຳກັດເປັນ ຈຳກັດໝາຍເລກໂທອອກເທົ່ານັ້ນ."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Can not change call forwarding settings from your phone while you are roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"ບໍລິການຖືກເປີດໄວ້ແລ້ວ."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ອະນຸຍາດໃຫ້ແອັບຯເຮັດໃຫ້ສ່ວນນຶ່ງຂອງຕົນເອງ ຄົງຢູ່ຖາວອນໃນໜ່ວຍຄວາມຈຳ ເຊິ່ງອາດສາມາດ ເຮັດໃຫ້ການນຳໃຊ້ໜ່ວຍຄວາມຈຳຂອງແອັບຯ ອື່ນຖືກຈຳກັດ ສົ່ງຜົນເຮັດໃຫ້ມືຖືຂອງທ່ານເຮັດວຽກຊ້າລົງໄດ້."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ໃຊ້ບໍລິການພື້ນໜ້າ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ບໍລິການພື້ນໜ້າ."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ກ້ອງຖ່າຍຮູບ\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ກ້ອງຖ່າຍຮູບ\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ອຸປະກອນທີ່ເຊື່ອມຕໍ່\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ອຸປະກອນທີ່ເຊື່ອມຕໍ່\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຊິ້ງຂໍ້ມູນ\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຊິ້ງຂໍ້ມູນ\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສະຖານທີ່\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສະຖານທີ່\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຫຼິ້ນມີເດຍ\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຫຼິ້ນມີເດຍ\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການສາຍພາບມີເດຍ\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການສາຍພາບມີເດຍ\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ໄມໂຄຣໂຟນ\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ໄມໂຄຣໂຟນ\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສາຍໂທ\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສາຍໂທ\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສຸຂະພາບ\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ສຸຂະພາບ\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຮັບສົ່ງຂໍ້ຄວາມຈາກໄລຍະໄກ\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການຮັບສົ່ງຂໍ້ຄວາມຈາກໄລຍະໄກ\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ໄດ້ຮັບການຍົກເວັ້ນຈາກລະບົບ\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ໄດ້ຮັບການຍົກເວັ້ນຈາກລະບົບ\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"ເອີ້ນໃຊ້ບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການນຳໃຊ້ພິເສດ\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ອະນຸຍາດໃຫ້ແອັບໃຊ້ປະໂຫຍດຈາກບໍລິການທີ່ເຮັດວຽກຢູ່ເບື້ອງໜ້າໂດຍມີປະເພດເປັນ \"ການນຳໃຊ້ພິເສດ\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ກວດສອບພື້ນທີ່ຈັດເກັບຂໍ້ມູນແອັບຯ"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ອະນຸຍາດໃຫ້ແອັບຯດຶງໂຄດ, ຂໍ້ມູນ ແລະຂະໜາດ cache ຂອງມັນໄດ້."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ແກ້ໄຂການຕັ້ງຄ່າລະບົບ"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ແອັບນີ້ສາມາດບັນທຶກສຽງດ້ວຍໄມໂຄຣໂຟນໃນຂະນະທີ່ກຳລັງໃຊ້ແອັບຢູ່ໄດ້."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ບັນທຶກສຽງໃນພື້ນຫຼັງ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ແອັບນີ້ສາມາດບັນທຶກສຽງດ້ວຍໄມໂຄຣໂຟນຕອນໃດກໍໄດ້."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ກວດຫາການຖ່າຍຮູບໜ້າຈໍຂອງໜ້າຈໍແອັບ"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ແອັບນີ້ຈະໄດ້ຮັບການແຈ້ງເຕືອນເມື່ອມີການຖ່າຍຮູບໜ້າຈໍໃນຂະນະທີ່ກຳລັງໃຊ້ແອັບຢູ່."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"ສົ່ງ​ຄຳ​ສັ່ງ​ຫາ SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ອະນຸຍາດໃຫ້ແອັບຯສົ່ງຄຳສັ່ງຫາ SIM. ສິ່ງນີ້ອັນຕະລາຍຫຼາຍ."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ຈຳແນກກິດຈະກຳທາງກາຍ"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງໂທລະສັບຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ບໍ່ສາມາດເຂົ້າເຖິງກ້ອງຖ່າຍຮູບຂອງແທັບເລັດຈາກ <xliff:g id="DEVICE">%1$s</xliff:g> ຂອງທ່ານໄດ້"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ບໍ່ສາມາດເຂົ້າເຖິງເນື້ອຫານີ້ໄດ້ໃນຂະນະທີ່ຍັງສະຕຣີມຢູ່. ກະລຸນາລອງຢູ່ໂທລະສັບຂອງທ່ານແທນ."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ບໍ່ສາມາດເບິ່ງການສະແດງຜົນຊ້ອນກັນໃນຂະນະທີ່ສະຕຣີມໄດ້"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ຄ່າເລີ່ມຕົ້ນຂອງລະບົບ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ບັດ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 404dbd8..eb74970 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Balso paštas"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Ryšio problema arba neteisingas MMI kodas."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcija nepalaikoma."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacija ribojama tik naudojant fiksuoto rinkimo numerius."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Negalima pakeisti telefono skambučio peradresavimo nustatymų, kai naudojate tarptinklinį ryšį."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Paslauga įgalinta."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Leidžiama programai savo dalis įrašyti į atmintį. Dėl to gali būti apribota kitomis programomis pasiekiama atmintis ir sulėtėti telefono veikimas."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"vykdyti priekiniame plane veikiančią paslaugą"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Programai leidžiama naudoti priekiniame plane veikiančias paslaugas."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"paleisti priekinio plano paslaugą, kurios tipas „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"paleisti priekinio plano paslaugą, kurios tipas „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"paleisti priekinio plano paslaugą, kurios tipas „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"paleisti priekinio plano paslaugą, kurios tipas „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"paleisti priekinio plano paslaugą, kurios tipas „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"paleisti priekinio plano paslaugą, kurios tipas „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"paleisti priekinio plano paslaugą, kurios tipas „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"paleisti priekinio plano paslaugą, kurios tipas „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"paleisti priekinio plano paslaugą, kurios tipas „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"paleisti priekinio plano paslaugą, kurios tipas „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"paleisti priekinio plano paslaugą, kurios tipas „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"paleisti priekinio plano paslaugą, kurios tipas „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Programai leidžiama naudoti priekinio plano paslaugas, kurių tipas „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"matuoti programos atmintinės vietą"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Leidžiama programai nuskaityti kodą, duomenis ir talpykloje saugoti dydžius"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"keisti sistemos nustatymus"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ši programa gali įrašyti garsą naudodama mikrofoną, kol programa naudojama."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"įrašyti garsą fone"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ši programa gali bet kada įrašyti garsą naudodama mikrofoną."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"Programos langų ekrano fiksavimo aptikimas"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Šiai programai bus pranešta, kai bus sukurta ekrano kopija, kol programa naudojama."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"siųsti komandas į SIM kortelę"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Programai leidžiama siųsti komandas į SIM kortelę. Tai labai pavojinga."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"atpažinti fizinę veiklą"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nepavyko pasiekti telefono fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nepavyko pasiekti planšetinio kompiuterio fotoaparato iš „<xliff:g id="DEVICE">%1$s</xliff:g>“"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Nepavyksta pasiekti perduodant srautu. Pabandykite naudoti telefoną."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Negalima peržiūrėti vaizdo vaizde perduodant srautu"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Numatytoji sistemos vertė"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORTELĖ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 721c17e..792ce6a 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Balss pasts"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Savienojuma problēma vai nederīgs MMI kods."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcija netiek atbalstīta."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Darbība ir atļauta tikai fiksēto numuru sastādīšanai."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nevar mainīt zvanu pāradresēšanas iestatījumus tālrunī, kamēr izmantojat viesabonēšanu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Pakalpojums tika iespējots."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Ļauj lietotnei nodrošināt atsevišķu tās daļu nepārtrauktu atrašanos atmiņā. Tas var ierobežot pieejamo atmiņas daudzumu citām lietotnēm, tādējādi palēninot tālruņa darbību."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"Aktivizēt priekšplāna pakalpojumu"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Ļauj lietotnei izmantot priekšplāna pakalpojumus."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"izpildīt šāda veida priekšplāna pakalpojumu: camera"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"izpildīt šāda veida priekšplāna pakalpojumu: connectedDevice"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"izpildīt šāda veida priekšplāna pakalpojumu: dataSync"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"izpildīt šāda veida priekšplāna pakalpojumu: location"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"izpildīt šāda veida priekšplāna pakalpojumu: mediaPlayback"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"izpildīt šāda veida priekšplāna pakalpojumu: mediaProjection"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"izpildīt šāda veida priekšplāna pakalpojumu: microphone"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"izpildīt šāda veida priekšplāna pakalpojumu: phoneCall"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"izpildīt šāda veida priekšplāna pakalpojumu: health"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"izpildīt šāda veida priekšplāna pakalpojumu: remoteMessaging"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"izpildīt šāda veida priekšplāna pakalpojumu: systemExempted"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"izpildīt šāda veida priekšplāna pakalpojumu: specialUse"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ļauj lietotnei izmantot šāda veida priekšplāna pakalpojumus: specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"noteikt vietas apjomu lietotnes atmiņā"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Ļauj lietotnei izgūt tās koda datus un kešatmiņas izmēru."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"mainīt sistēmas iestatījumus"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Šī lietotne var ierakstīt audio, izmantojot mikrofonu, kamēr lietotne tiek izmantota."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ierakstīt audio fonā"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Šī lietotne var jebkurā brīdī ierakstīt audio, izmantojot mikrofonu."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"noteikt lietotnes logu ekrānuzņēmumu izveidi"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ja lietotnes izmantošanas laikā tiks izveidots ekrānuzņēmums, lietotnei tiks nosūtīts paziņojums."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"Sūtīt komandas SIM kartei"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Ļauj lietotnei sūtīt komandas uz SIM karti. Tas ir ļoti bīstami!"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"noteikt fiziskās aktivitātes"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nevar piekļūt tālruņa kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nevar piekļūt planšetdatora kamerai no jūsu ierīces (<xliff:g id="DEVICE">%1$s</xliff:g>)."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Straumēšanas laikā nevar piekļūt šim saturam. Mēģiniet tam piekļūt savā tālrunī."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Straumēšanas laikā nevar skatīt attēlu attēlā"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistēmas noklusējums"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTE <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b3d46db..e5710cd 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Говорна пошта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Проблем со поврзување или неважечки MMI код."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функцијата не е поддржана."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Операцијата е ограничена на бирање само фиксни броеви."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Не може да се сменат поставките за проследување повик од телефонот додека сте во роаминг."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Услугата беше овозможена."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Овозможува апликацијата да прави трајни делови од себеси во меморијата. Ова може да ја ограничи расположливата меморија на други апликации што го забавува телефонот."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"извршување услуга во преден план"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Дозволува апликацијата да ги користи услугите во преден план."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"да извршува во преден план услуга со типот „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Дозволува апликацијата да ги користи во преден план услугите со типот „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"да извршува во преден план услуга со типот „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Дозволува апликацијата да ги користи во преден план услугите со типот „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"да извршува во преден план услуга со типот „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Дозволува апликацијата да ги користи во преден план услугите со типот „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"да извршува во преден план услуга со типот „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Дозволува апликацијата да ги користи во преден план услугите со типот „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"да извршува во преден план услуга со типот „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Дозволува апликацијата да ги користи во преден план услугите со типот „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"да извршува во преден план услуга со типот „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Дозволува апликацијата да ги користи во преден план услугите со типот „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"да извршува во преден план услуга со типот „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Дозволува апликацијата да ги користи во преден план услугите со типот „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"да извршува во преден план услуга со типот „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Дозволува апликацијата да ги користи во преден план услугите со типот „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"да извршува во преден план услуга со типот „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Дозволува апликацијата да ги користи во преден план услугите со типот „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"да извршува во преден план услуга со типот „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Дозволува апликацијата да ги користи во преден план услугите со типот „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"да извршува во преден план услуга со типот „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозволува апликацијата да ги користи во преден план услугите со типот „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"да извршува во преден план услуга со типот „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозволува апликацијата да ги користи во преден план услугите со типот „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"измери простор за складирање на апликацијата"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Дозволува апликацијата да ги обнови кодот, податоците и величините на кеш."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"менува системски поставки"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се пристапи до камерата на вашиот телефон од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се пристапи до камерата на вашиот таблет од <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"До ова не може да се пристапи при стриминг. Наместо тоа, пробајте на вашиот телефон."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не може да се прикажува слика во слика при стримување"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Стандардно за системот"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТИЧКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index efc475c..65b2c5d 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"വോയ്സ് മെയില്‍"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"കണക്ഷൻ പ്രശ്‌നം അല്ലെങ്കിൽ MMI കോഡ് അസാധുവാണ്."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ഫീച്ചർ പിന്തുണയ്‌ക്കുന്നില്ല."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"നിശ്ചയിച്ചുറപ്പിച്ച ഡയൽ ചെയ്യൽ നമ്പറുകൾക്ക് മാത്രമായി പ്രവർത്തനം പരിമിതപ്പെടുത്തിയിരിക്കുന്നു."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"റോമിംഗിൽ ആയിരിക്കുമ്പോൾ നിങ്ങളുടെ ഫോണിൽ നിന്ന് കോൾ കൈമാറ്റ ക്രമീകരണം സാധിക്കില്ല."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"സേവനം പ്രവർത്തനക്ഷമമാക്കി."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"മെമ്മറിയിൽ അപ്ലിക്കേഷനുകളുടെ ഭാഗങ്ങൾ നിലനിർത്താൻ സ്വയം അനുവദിക്കുന്നു. ഇത് ഫോണിനെ മന്ദഗതിയിലാക്കുന്ന വിധത്തിൽ മറ്റ് അപ്ലിക്കേഷനുകൾക്ക് ലഭ്യമായ മെമ്മറി പരിമിതപ്പെടുത്താനിടയുണ്ട്."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"മുൻവശത്തുള്ള സേവനം റൺ ചെയ്യുക"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"മുൻവശത്തുള്ള സേവനങ്ങൾ ഉപയോഗിക്കാൻ ആപ്പിനെ അനുവദിക്കുന്നു."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"camera\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"location\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"microphone\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"health\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനം റൺ ചെയ്യുക"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" എന്ന തരം ഉപയോഗിച്ച് ഫോർഗ്രൗണ്ട് സേവനങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആപ്പിനെ അനുവദിക്കുന്നു"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"അപ്ലിക്കേഷൻ സംഭരണയിടം അളക്കുക"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"അപ്ലിക്കേഷന്റെ കോഡ്, ഡാറ്റ, കാഷെ വലുപ്പങ്ങൾ എന്നിവ വീണ്ടെടുക്കുന്നതിന് അതിനെ അനുവദിക്കുക"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"സിസ്റ്റം ക്രമീകരണങ്ങൾ പരിഷ്‌ക്കരിക്കുക"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ആപ്പ് ഉപയോഗത്തിലായിരിക്കുമ്പോൾ മൈക്രോഫോൺ ഉപയോഗിച്ച് ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"പശ്ചാത്തലത്തിൽ ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ഈ ആപ്പിന് ഏത് സമയത്തും മൈക്രോഫോൺ ഉപയോഗിച്ച് ഓഡിയോ റെക്കോർഡ് ചെയ്യാൻ കഴിയും."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ആപ്പ് വിൻഡോകളുടെ സ്‌ക്രീൻ ക്യാപ്‌ചർ ചെയ്യലുകൾ കണ്ടെത്തുക"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ആപ്പ് ഉപയോഗിച്ചുകൊണ്ടിരിക്കുമ്പോൾ സ്ക്രീൻഷോട്ട് എടുത്താൽ ആപ്പിന് അറിയിപ്പ് ലഭിക്കും."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM-ലേക്ക് കമാൻഡുകൾ അയയ്ക്കുക"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"സിമ്മിലേക്ക് കമാൻഡുകൾ അയയ്‌ക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് വളരെ അപകടകരമാണ്."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ശാരീരിക പ്രവർത്തനം തിരിച്ചറിയുക"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ഫോണിന്റെ ക്യാമറ ആക്‌സസ് ചെയ്യാനാകില്ല"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"നിങ്ങളുടെ <xliff:g id="DEVICE">%1$s</xliff:g> എന്നതിൽ നിന്ന് ടാബ്‌ലെറ്റിന്റെ ക്യാമറ ആക്‌സസ് ചെയ്യാനാകില്ല"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"സ്ട്രീം ചെയ്യുമ്പോൾ ഇത് ആക്സസ് ചെയ്യാനാകില്ല. പകരം നിങ്ങളുടെ ഫോണിൽ ശ്രമിച്ച് നോക്കൂ."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"സ്ട്രീമിംഗിനിടെ ചിത്രത്തിനുള്ളിൽ ചിത്രം കാണാനാകില്ല"</string>
     <string name="system_locale_title" msgid="711882686834677268">"സിസ്‌റ്റം ഡിഫോൾട്ട്"</string>
     <string name="default_card_name" msgid="9198284935962911468">"കാർഡ് <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 114d562..6d48c97 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"дуут шуудан"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Холболтын асуудал эсвэл буруу MMI код."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Онцлогийг дэмжээгүй."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Ажиллагаа зөвөх тогтсон дугаараар хязгаарлагдсан."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Таныг роуминг үйлчилгээг идэвхжүүлсэн үед таны утаснаас дуудлага дамжуулах тохиргоог өөрчлөх боломжгүй."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Үйлчилгээ идэвхжсэн."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Апп нь өөрийн хэсгийг санах ойд байнга байлгах боломжтой. Энэ нь бусад апп-уудын ашиглах санах ойг хязгаарлан утсыг удаашруулах болно."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"интерактив (foreground) үйлчилгээг ажиллуулах"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Аппад интерактив (foreground) үйлчилгээг ашиглахыг зөвшөөрнө үү."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"Камер\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Аппад \"камер\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"ConnectedDevice\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Аппад \"connectedDevice\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"DataSync\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Аппад \"dataSync\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"Байршил\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Аппад \"байршил\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"MediaPlayback\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Аппад \"mediaPlayback\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"MediaProjection\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Аппад \"mediaProjection\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"Микрофон\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Аппад \"микрофон\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"PhoneCall\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Аппад \"phoneCall\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"Эрүүл мэнд\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Аппад \"эрүүл мэнд\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"RemoteMessaging\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Аппад \"remoteMessaging\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"SystemExempted\"-н төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Аппад \"systemExempted\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"SpecialUse\" төрөлтэй нүүрэн талын үйлчилгээг ажиллуулах"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Аппад \"specialUse\" төрөлтэй нүүрэн талын үйлчилгээнүүдийг ашиглахыг зөвшөөрнө"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"апп сангийн хэмжээг хэмжих"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Апп нь өөрийн код, дата болон кеш хэмжээг унших боломжтой"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"систем тохиргоог өөрчлөх"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с утасны камерт хандах боломжгүй"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Таны <xliff:g id="DEVICE">%1$s</xliff:g>-с таблетын камерт хандах боломжгүй"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Стримингийн үед үүнд хандах боломжгүй. Оронд нь утас дээрээ туршиж үзнэ үү."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Дамжуулах явцад дэлгэц доторх дэлгэцийг үзэх боломжгүй"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Системийн өгөгдмөл"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 216d960..b33fb3fb 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"व्हॉइसमेल"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"कनेक्शन समस्या किंवा अवैध MMI कोड."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"वैशिष्ट्याला सपोर्ट नाही."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"कार्य फक्त निश्चित डायलिंग नंबरसाठी प्रतिबंधित आहे."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"तुम्ही रोमिंगमध्ये असताना आपल्या फोनवरील कॉल फॉरवर्डिंग सेटिंंग्ज बदलू शकत नाही."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"सेवा सक्षम केली."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"अ‍ॅप ला मेमरीमध्ये कायम असलेले त्याचे स्वतःचे भाग बनविण्यास अनुमती देते. हे फोन धीमा करून अन्य अ‍ॅप्सवर उपलब्ध असलेल्या मेमरीवर मर्यादा घालू शकते."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"पृष्‍ठभाग सेवा रन करा"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"अ‍ॅपला पृष्‍ठभाग सेवा वापरण्याची अनुमती देते."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"कॅमेरा\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"कॅमेरा\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"स्थान\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"स्थान\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"मायक्रोफोन\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"मायक्रोफोन\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"आरोग्य\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"आरोग्य\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" प्रकारासोबत फोरग्राउंड सेवा रन करा"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" प्रकारासोबत अ‍ॅपला फोरग्राउंड सेवांचा वापर करण्याची अनुमती देते"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"अ‍ॅप संचयन स्थान मोजा"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"अ‍ॅप ला त्याचा कोड, डेटा आणि कॅशे    आकार पुनर्प्राप्त करण्यासाठी अनुमती देते"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"सिस्टीम सेटिंग्ज सुधारित करा"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ॲप वापरात असताना, हे ॲप मायक्रोफोन वापरून ऑडिओ रेकॉर्ड करू शकते."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"बॅकग्राउंडमध्ये ऑडिओ रेकॉर्ड करा"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"हे ॲप मायक्रोफोन वापरून ऑडिओ कधीही रेकॉर्ड करू शकते."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"अ‍ॅप विंडोचे स्‍क्रीन कॅप्‍चर डिटेक्ट करा"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ॲप वापरात असताना स्क्रीनशॉट घेतल्यावर या ॲपला सूचित केले जाईल."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"सिम वर कमांड पाठवा"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"अ‍ॅप ला सिम वर कमांड पाठविण्‍याची अनुमती देते. हे खूप धोकादायक असते."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक ॲक्टिव्हिटी ओळखा"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून फोनचा कॅमेरा अ‍ॅक्सेस करू शकत नाही"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तुमच्या <xliff:g id="DEVICE">%1$s</xliff:g> वरून टॅबलेटचा कॅमेरा अ‍ॅक्सेस करू शकत नाही"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रीम करताना हे अ‍ॅक्सेस केले जाऊ शकत नाही. त्याऐवजी तुमच्या फोनवर अ‍ॅक्सेस करून पहा."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रीम होत असताना चित्रात-चित्र पाहू शकत नाही"</string>
     <string name="system_locale_title" msgid="711882686834677268">"सिस्टीम डीफॉल्ट"</string>
     <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 112190b..c6065c6 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Mel suara"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Masalah sambungan atau kod MMI tidak sah"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Ciri tidak disokong."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Pengendalian dihadkan kepada nombor dailan tetap sahaja."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Tidak dapat mengubah tetapan pemajuan panggilan daripad telefon anda semasa dalam perayauan."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Perkhidmatan telah didayakan."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Membenarkan apl untuk membuat sebahagian dari dirinya berterusan dalam memori. Ini boleh mengehadkan memori yang tersedia kepada apl lain dan menjadikan telefon perlahan."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"jalankan perkhidmatan latar depan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Membenarkan apl menggunakan perkhidmatan latar depan."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"jalankan perkhidmatan latar depan dengan jenis \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"jalankan perkhidmatan latar depan dengan jenis \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"jalankan perkhidmatan latar depan dengan jenis \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"jalankan perkhidmatan latar depan dengan jenis \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"jalankan perkhidmatan latar depan dengan jenis \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"jalankan perkhidmatan latar depan dengan jenis \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"jalankan perkhidmatan latar depan dengan jenis \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"jalankan perkhidmatan latar depan dengan jenis \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"jalankan perkhidmatan latar depan dengan jenis \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"jalankan perkhidmatan latar depan dengan jenis \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"jalankan perkhidmatan latar depan dengan jenis \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"jalankan perkhidmatan latar depan dengan jenis \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Membenarkan apl menggunakan perkhidmatan latar depan dengan jenis \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ukur ruang storan apl"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Membenarkan apl mendapatkan semula kodnya, datanya dan saiz cachenya"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ubah suai tetapan sistem"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Tidak dapat mengakses kamera telefon daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Tidak dapat mengakses kamera tablet daripada <xliff:g id="DEVICE">%1$s</xliff:g> anda"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Kandungan ini tidak boleh diakses semasa penstriman. Cuba pada telefon anda."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Tidak dapat melihat gambar dalam gambar semasa penstriman"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Lalai sistem"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 8e9b9ad..0e92d8a 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"အသံမေးလ်"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ဆက်သွယ်မှုဆိုင်ရာပြသနာ သို့မဟုတ် မမှန်ကန်သောMMIကုတ်"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ဝန်ဆောင်မှုကို မပံ့ပိုးပါ။"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"သတ်မှတ်ခေါ်ဆိုနိုင်သောနံပါတ်များထံသာ ကန့်သတ်ထားသည်"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ကွန်ရက်ပြင်ပဒေတာအသုံးပြုခြင်းကို ဖွင့်ထားသည့်အခါ သင့်ဖုန်းမှနေ၍ ခေါ်ဆိုမှုထပ်ဆင့်ပို့ခြင်းဆက်တင်အား ပြောင်း၍မရပါ။"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"ဝန်ဆောင်မှု လုပ်ဆောင်နိုင်မည်"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"အပလီကေးရှင်းအား မှတ်ဉာဏ်ထဲတွင် ရေရှည်သိမ်းဆည်ထားရန် ခွင့်ပြုပါ။ ဒီခွင့်ပြုချက်ကြောင့် တခြားအပလီကေးရှင်းအများအတွက် မှတ်ဉာဏ်ရရှိမှု နည်းသွားနိုင်ပြီး ဖုန်းလည်း နှေးသွားနိုင်ပါသည်။"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"မျက်နှာစာ ဝန်ဆောင်မှုကို ဖွင့်ခြင်း"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"မျက်နှာစာဝန်ဆောင်မှုများကို အက်ပ်အား အသုံးပြုခွင့်ပေးသည်။"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"camera\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"location\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"microphone\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"health\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှု လုပ်ဆောင်ခြင်း"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" အမျိုးအစား မျက်နှာစာဝန်ဆောင်မှုများအား အကျိုးရှိရှိ အသုံးပြုနိုင်ရန် အက်ပ်ကို ခွင့်ပြုသည်"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"အက်ပ်သိုလ​ှောင်မှု နေရာကို တိုင်းထွာခြင်း"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"အက်ပ်အား ၎င်း၏ ကုဒ်၊ ဒေတာ၊ နှင့် ကက်ရှ ဆိုက်များကို ရယူခွင့် ပြုသည်။"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"စနစ်အပြင်အဆင်အား မွမ်းမံခြင်း"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ဤအက်ပ်ကို အသုံးပြုနေစဉ် ၎င်းက မိုက်ခရိုဖုန်းကို အသုံးပြု၍ အသံဖမ်းနိုင်သည်။"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"နောက်ခံတွင် အသံဖမ်းပါ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ဤအက်ပ်သည် မိုက်ခရိုဖုန်းကို အသုံးပြု၍ အချိန်မရွေး အသံဖမ်းနိုင်သည်။"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"အက်ပ်ဝင်းဒိုး၏ ဖန်သားပြင်ပုံဖမ်းမှုကို သိရှိခြင်း"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"အက်ပ်သုံးနေစဉ် ဖန်သားပြင်ဓာတ်ပုံရိုက်သည့်အခါ ဤအက်ပ်က အကြောင်းကြားချက်ရရှိမည်။"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM ထံသို့ ညွှန်ကြားချက်များကို ပို့ပါ"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"အက်ပ်အား ဆင်းမ်ကဒ်ဆီသို့ အမိန့်များ ပေးပို့ခွင့် ပြုခြင်း။ ဤခွင့်ပြုမှုမှာ အန္တရာယ်အလွန် ရှိပါသည်။"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ကိုယ်ခန္ဓာလှုပ်ရှားမှုကို မှတ်သားပါ"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ ဖုန်းကင်မရာကို သုံး၍မရပါ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"သင်၏ <xliff:g id="DEVICE">%1$s</xliff:g> မှ တက်ဘလက်ကင်မရာကို သုံး၍မရပါ"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"တိုက်ရိုက်လွှင့်နေစဉ် ၎င်းကို မသုံးနိုင်ပါ။ ၎င်းအစား ဖုန်းတွင် စမ်းကြည့်ပါ။"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"တိုက်ရိုက်လွှင့်စဉ် နှစ်ခုထပ်၍ မကြည့်နိုင်ပါ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"စနစ်မူရင်း"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ကတ် <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index dc8be27..8b796dd 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Telefonsvarer"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Tilkoblingsproblem eller ugyldig MMI-kode."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funksjonen støttes ikke."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Handlingen kan kun utføres på numre med anropsbegrensning."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Får ikke endret innstillinger for viderekobling fra telefonen din når du bruker roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Tjenesten ble aktivert."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Lar appen gjøre deler av seg selv vedvarende i minnet. Dette kan begrense minnet for andre apper og gjøre telefonen treg."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"kjøre tjenesten i forgrunnen"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Lar appen bruke tjenester i forgrunnen."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"kjøre forgrunnstjeneste med typen «camera»"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Lar appen bruke forgrunnstjenester med typen «camera»"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"kjøre forgrunnstjeneste med typen «connectedDevice»"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Lar appen bruke forgrunnstjenester med typen «connectedDevice»"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"kjøre forgrunnstjeneste med typen «dataSync»"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Lar appen bruke forgrunnstjenester med typen «dataSync»"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"kjøre forgrunnstjeneste med typen «location»"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Lar appen bruke forgrunnstjenester med typen «location»"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"kjøre forgrunnstjeneste med typen «mediaPlayback»"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Lar appen bruke forgrunnstjenester med typen «mediaPlayback»"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"kjøre forgrunnstjeneste med typen «mediaProjection»"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Lar appen bruke forgrunnstjenester med typen «mediaProjection»"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"kjøre forgrunnstjeneste med typen «microphone»"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Lar appen bruke forgrunnstjenester med typen «microphone»"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"kjøre forgrunnstjeneste med typen «phoneCall»"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Lar appen bruke forgrunnstjenester med typen «phoneCall»"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"kjøre forgrunnstjeneste med typen «health»"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Lar appen bruke forgrunnstjenester med typen «health»"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"kjøre forgrunnstjeneste med typen «remoteMessaging»"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Lar appen bruke forgrunnstjenester med typen «remoteMessaging»"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"kjøre forgrunnstjeneste med typen «systemExempted»"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lar appen bruke forgrunnstjenester med typen «systemExempted»"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kjøre forgrunnstjeneste med typen «specialUse»"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lar appen bruke forgrunnstjenester med typen «specialUse»"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"måle lagringsplass for apper"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Lar appen hente ut koden, dataene og bufferstørrelsene til appen"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"endre systeminnstillingene"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Denne appen kan ta opp lyd med mikrofonen mens den er i bruk."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ta opp lyd i bakgrunnen"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Denne appen kan når som helst ta opp lyd med mikrofonen."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"registrere skjermdumper av appvinduer"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Denne appen varsles hvis det tas skjermdumper mens appen er i bruk."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"sende kommandoer til SIM-kortet"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Lar appen sende kommandoer til SIM-kortet. Dette er veldig farlig."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"gjenkjenn fysisk aktivitet"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Det er ikke mulig å få tilgang til telefonkameraet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Det er ikke mulig å få tilgang til kameraet på nettbrettet fra <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Dette er ikke tilgjengelig under strømming. Prøv på telefonen i stedet."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan ikke se bilde-i-bilde under strømming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systemstandard"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b031aa8..54875ac 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"भ्वाइस मेल"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN१"</string>
     <string name="mmiError" msgid="2862759606579822246">"जडान समस्या वा अमान्य MMI कोड।"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"यो सुविधा प्रयोग गर्न मिल्दैन।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"अपरेशन निश्चित डायल नम्बरहरूको लागि मात्र प्रतिबन्धित छ।"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"तपाईं रोमिङमा हुनुहुँदा तपाईंको फोनबाट कल फर्वार्ड गर्ने सम्बन्धी सेटिङहरू परिवर्तन गर्न सकिँदैन।"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"सेवा सक्षम पारियो।"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"एपलाई मेमोरीमा आफैंको निरन्तरको अंश बनाउन अनुमति दिन्छ। यसले फोनलाई ढिला बनाएर अन्य एपहरूमा मेमोरी SIMित गर्न सक्दछन्।"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"अग्रभूमिको सेवा सञ्चालन गर्नुहोस्"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"एपलाई अग्रभूमिका सेवाहरू प्रयोग गर्ने अनुमति दिन्छ।"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"यसले एपलाई \"camera\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"यसले एपलाई \"connectedDevice\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"यसले एपलाई \"dataSync\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"यसले एपलाई \"location\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"यसले एपलाई \"mediaPlayback\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"यसले एपलाई \"mediaProjection\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"यसले एपलाई \"microphone\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"यसले एपलाई \"phoneCall\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"यसले एपलाई \"health\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"यसले एपलाई \"remoteMessaging\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"यसले एपलाई \"systemExempted\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिनुहोस्"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"यसले एपलाई \"specialUse\" सँग सम्बन्धित फोरग्राउन्ड सेवाहरू प्रयोग गर्ने अनुमति दिन्छ"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"एप भण्डारण ठाउँको मापन गर्नुहोस्"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"एपलाई यसको कोड, डेटा, र क्यास आकारहरू पुनःप्राप्त गर्न अनुमति दिन्छ।"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"प्रणाली सेटिङहरू परिमार्जन गर्नुहोस्"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"यो एप प्रयोग भइरहेका बेला यसले माइक्रोफोन प्रयोग गरेर अडियो रेकर्ड गर्न सक्छ।"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ब्याकग्राउन्डमा अडियो रेकर्ड गर्नुहोस्"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"यो एपले जुनसुकै बेला माइक्रोफोन प्रयोग गरी अडियो रेकर्ड गर्न सक्छ।"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"एपको विन्डोको स्क्रिन क्याप्चर गरेको कुरा पत्ता लगाउनुहोस्"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"एप प्रयोग भइरहेको बेला स्क्रिनसट लिइयो भने यो एपलाई सूचना दिइने छ।"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM मा आदेशहरू पठाउन दिनुहोस्"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM लाई आदेश पठाउन एपलाई अनुमति दिन्छ। यो निकै खतरनाक हुन्छ।"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"शारीरिक गतिविधि पहिचान गर्नुहोस्‌"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत फोनको क्यामेरा प्रयोग गर्न मिल्दैन"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"तपाईंको <xliff:g id="DEVICE">%1$s</xliff:g> मार्फत ट्याब्लेटको क्यामेरा प्रयोग गर्न मिल्दैन"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"स्ट्रिम गरिरहेका बेला यो सामग्री हेर्न तथा प्रयोग गर्न मिल्दैन। बरु आफ्नो फोनमार्फत सो सामग्री हेर्ने तथा प्रयोग गर्ने प्रयास गर्नुहोस्।"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"स्ट्रिम गरिरहेका बेला picture-in-picture मोड प्रयोग गर्न मिल्दैन"</string>
     <string name="system_locale_title" msgid="711882686834677268">"सिस्टम डिफल्ट"</string>
     <string name="default_card_name" msgid="9198284935962911468">"कार्ड <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 566bbb3..e40a087 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Verbindingsprobleem of ongeldige MMI-code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Functie niet ondersteund."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Bewerking is beperkt tot vaste nummers."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Kan instellingen voor doorschakelen van gesprekken niet wijzigen vanaf je telefoon tijdens roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Service staat aan."</string>
@@ -257,7 +258,7 @@
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Stille modus"</string>
     <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Geluid is UIT"</string>
     <string name="global_action_silent_mode_off_status" msgid="6608006545950920042">"Geluid is AAN"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Vliegtuigmodus"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="6911684460146916206">"Vliegtuig­modus"</string>
     <string name="global_actions_airplane_mode_on_status" msgid="5508025516695361936">"Vliegtuigmodus is AAN"</string>
     <string name="global_actions_airplane_mode_off_status" msgid="8522219771500505475">"Vliegtuigmodus is UIT"</string>
     <string name="global_action_settings" msgid="4671878836947494217">"Instellingen"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Hiermee kan de app gedeelten van zichzelf persistent maken in het geheugen. Dit kan de hoeveelheid geheugen beperken die beschikbaar is voor andere apps, waardoor de telefoon trager kan worden."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"service op de voorgrond uitvoeren"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Hiermee kan de app gebruikmaken van services op de voorgrond."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"service op de voorgrond van het type \'camera\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'camera\'"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"service op de voorgrond van het type \'connectedDevice\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'connectedDevice\'"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"service op de voorgrond van het type \'dataSync\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'dataSync\'"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"service op de voorgrond van het type \'location\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'location\'"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"service op de voorgrond van het type \'mediaPlayback\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'mediaPlayback\'"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"service op de voorgrond van het type \'mediaProjection\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'mediaProjection\'"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"service op de voorgrond van het type \'microphone\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'microphone\'"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"service op de voorgrond van het type \'phoneCall\' uitvoeren"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'phoneCall\'"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"service op de voorgrond van het type \'health\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'health\'"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"service op de voorgrond van het type \'remoteMessaging\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'remoteMessaging\'"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"service op de voorgrond van het type \'systemExempted\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'systemExempted\'"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"service op de voorgrond van het type \'specialUse\' uitvoeren"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Hiermee kan de app gebruikmaken van services op de voorgrond van het type \'specialUse\'"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"opslagruimte van app meten"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Hiermee kan de app de bijbehorende code, gegevens en cachegrootten ophalen."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"systeeminstellingen aanpassen"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Deze app kan audio opnemen met de microfoon als de app wordt gebruikt."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"audio opnemen op de achtergrond"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Deze app kan altijd audio opnemen met de microfoon."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"schermopnamen van de app vastleggen"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Deze app krijgt een melding als een screenshot wordt gemaakt terwijl de app in gebruik is."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"opdrachten verzenden naar de simkaart"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Hiermee kan de app opdrachten verzenden naar de simkaart. Dit is erg gevaarlijk."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"fysieke activiteit herkennen"</string>
@@ -1042,7 +1017,7 @@
     <string name="keyguard_accessibility_user_selector" msgid="1466067610235696600">"Gebruikersselectie"</string>
     <string name="keyguard_accessibility_status" msgid="6792745049712397237">"Status"</string>
     <string name="keyguard_accessibility_camera" msgid="7862557559464986528">"Camera"</string>
-    <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Mediabediening"</string>
+    <string name="keygaurd_accessibility_media_controls" msgid="2267379779900620614">"Media­bediening"</string>
     <string name="keyguard_accessibility_widget_reorder_start" msgid="7066213328912939191">"Opnieuw indelen van widget gestart."</string>
     <string name="keyguard_accessibility_widget_reorder_end" msgid="1083806817600593490">"Opnieuw indelen van widget beëindigd."</string>
     <string name="keyguard_accessibility_widget_deleted" msgid="1509738950119878705">"Widget <xliff:g id="WIDGET_INDEX">%1$s</xliff:g> verwijderd."</string>
@@ -1535,7 +1510,7 @@
     <string name="forward_intent_to_work" msgid="3620262405636021151">"U gebruikt deze app in je werkprofiel"</string>
     <string name="input_method_binding_label" msgid="1166731601721983656">"Invoermethode"</string>
     <string name="sync_binding_label" msgid="469249309424662147">"Synchroniseren"</string>
-    <string name="accessibility_binding_label" msgid="1974602776545801715">"Toegankelijkheid"</string>
+    <string name="accessibility_binding_label" msgid="1974602776545801715">"Toe­gankelijk­heid"</string>
     <string name="wallpaper_binding_label" msgid="1197440498000786738">"Achtergrond"</string>
     <string name="chooser_wallpaper" msgid="3082405680079923708">"Achtergrond wijzigen"</string>
     <string name="notification_listener_binding_label" msgid="2702165274471499713">"Listener voor meldingen"</string>
@@ -2041,7 +2016,7 @@
     <string name="app_category_news" msgid="1172762719574964544">"Nieuws en tijdschriften"</string>
     <string name="app_category_maps" msgid="6395725487922533156">"Maps en navigatie"</string>
     <string name="app_category_productivity" msgid="1844422703029557883">"Productiviteit"</string>
-    <string name="app_category_accessibility" msgid="6643521607848547683">"Toegankelijkheid"</string>
+    <string name="app_category_accessibility" msgid="6643521607848547683">"Toe­gankelijk­heid"</string>
     <string name="device_storage_monitor_notification_channel" msgid="5164244565844470758">"Apparaatopslag"</string>
     <string name="adb_debugging_notification_channel_tv" msgid="4764046459631031496">"USB-foutopsporing"</string>
     <string name="time_picker_hour_label" msgid="4208590187662336864">"uur"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Kan geen toegang tot de camera van de telefoon krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Kan geen toegang tot de camera van de tablet krijgen vanaf je <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Je hebt hier geen toegang toe tijdens streaming. Probeer het in plaats daarvan op je telefoon."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Kan scherm-in-scherm niet bekijken tijdens het streamen"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systeemstandaard"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KAART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 26880c5..412409a 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ଭଏସ୍‌ ମେଲ୍"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ସଂଯୋଗରେ ସମସ୍ୟା ଅଛି କିମ୍ବା ଅମାନ୍ୟ MMI କୋଡ୍।"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ଫିଚର ସମର୍ଥିତ ନୁହେଁ।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"କେବଳ ସ୍ଥାୟୀ ଡାୟଲିଙ୍ଗ ନମ୍ବର୍‌ ପାଇଁ କାର୍ଯ୍ୟ ସୀମିତ ଅଟେ।"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ଆପଣ ରୋମିଙ୍ଗରେ ଥିବାବେଳେ କଲ୍‍ ଫର୍‌ୱର୍ଡିଙ୍ଗ ସେଟିଙ୍ଗ ବଦଳାଇପାରିବେ ନାହିଁ।"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"ସେବା ସକ୍ଷମ କରାଯାଇଥିଲା।"</string>
@@ -87,7 +88,7 @@
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"ଆଲର୍ଟ"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"କଲ୍‌ ଫରୱାର୍ଡିଂ"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"ଜରୁରୀକାଳୀନ କଲବ୍ୟାକ୍‍ ମୋଡ୍‍"</string>
-    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ମୋବାଇଲ୍‍ ଡାଟା ଷ୍ଟାଟସ୍‌"</string>
+    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"ମୋବାଇଲ ଡାଟା ଷ୍ଟାଟସ"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"SMS ମେସେଜ୍‌"</string>
     <string name="notification_channel_voice_mail" msgid="8457433203106654172">"ଭଏସମେଲ୍‍ ମେସେଜ୍‍"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"ୱାଇ-ଫାଇ କଲିଙ୍ଗ"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ଆପ୍‍ଟି ନିଜକୁ ମେମୋରୀରେ ଭାଗ କରିବାକୁ ଦେଇଥାଏ। ଏହାଦ୍ୱାରା ଅନ୍ୟ ଆପ୍‍ଗୁଡ଼ିକ ପାଇଁ ମେମୋରୀ ଉପଲବ୍ଧକୁ କମ୍‌ କରିବା ସହ ଫୋନ୍‍ଟିକୁ ମନ୍ଥର କରିବ।"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ଫୋର୍‌ଗ୍ରାଉଣ୍ଡ ସେବାକୁ ଚଲାନ୍ତୁ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ଫୋର୍‌ଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପ୍‌କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"camera\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"location\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"microphone\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"health\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ଚଲାଏ"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" ପ୍ରକାର ସହ ଫୋରଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ଆପ୍‍ ଷ୍ଟୋରେଜ୍‍ ସ୍ଥାନର ମାପ କରନ୍ତୁ"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ଆପ୍‍ର କୋଡ୍‍, ଡାଟା ଓ କ୍ୟାଶ୍‌ ଆକାର ହାସଲ କରିବା ପାଇଁ ଏହାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ସିଷ୍ଟମ୍‍ ସେଟିଂସ ବଦଳାନ୍ତୁ"</string>
@@ -849,30 +826,30 @@
     <item msgid="8150904584178569699">"ୱାର୍କ ଫ୍ୟାକ୍ସ"</item>
     <item msgid="4537253139152229577">"ହୋମ ଫାକ୍ସ"</item>
     <item msgid="6751245029698664340">"ପେଜର୍"</item>
-    <item msgid="1692790665884224905">"ଅନ୍ୟାନ୍ୟ"</item>
+    <item msgid="1692790665884224905">"ଅନ୍ୟ"</item>
     <item msgid="6216981255272016212">"କଷ୍ଟମ୍‌"</item>
   </string-array>
   <string-array name="emailAddressTypes">
     <item msgid="7786349763648997741">"ହୋମ"</item>
     <item msgid="435564470865989199">"ୱାର୍କ"</item>
-    <item msgid="4199433197875490373">"ଅନ୍ୟାନ୍ୟ"</item>
+    <item msgid="4199433197875490373">"ଅନ୍ୟ"</item>
     <item msgid="3233938986670468328">"କଷ୍ଟମ୍‌"</item>
   </string-array>
   <string-array name="postalAddressTypes">
     <item msgid="3861463339764243038">"ହୋମ"</item>
     <item msgid="5472578890164979109">"ୱାର୍କ"</item>
-    <item msgid="5718921296646594739">"ଅନ୍ୟାନ୍ୟ"</item>
+    <item msgid="5718921296646594739">"ଅନ୍ୟ"</item>
     <item msgid="5523122236731783179">"କଷ୍ଟମ୍‌"</item>
   </string-array>
   <string-array name="imAddressTypes">
     <item msgid="588088543406993772">"ହୋମ"</item>
     <item msgid="5503060422020476757">"ୱାର୍କ"</item>
-    <item msgid="2530391194653760297">"ଅନ୍ୟାନ୍ୟ"</item>
+    <item msgid="2530391194653760297">"ଅନ୍ୟ"</item>
     <item msgid="7640927178025203330">"କଷ୍ଟମ୍‌"</item>
   </string-array>
   <string-array name="organizationTypes">
     <item msgid="6144047813304847762">"ୱାର୍କ"</item>
-    <item msgid="7402720230065674193">"ଅନ୍ୟାନ୍ୟ"</item>
+    <item msgid="7402720230065674193">"ଅନ୍ୟ"</item>
     <item msgid="808230403067569648">"କଷ୍ଟମ୍‌"</item>
   </string-array>
   <string-array name="imProtocols">
@@ -892,7 +869,7 @@
     <string name="phoneTypeFaxWork" msgid="6757519896109439123">"ୱାର୍କ ଫାକ୍ସ"</string>
     <string name="phoneTypeFaxHome" msgid="6678559953115904345">"ହୋମ ଫାକ୍ସ"</string>
     <string name="phoneTypePager" msgid="576402072263522767">"ପେଜର୍"</string>
-    <string name="phoneTypeOther" msgid="6918196243648754715">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="phoneTypeOther" msgid="6918196243648754715">"ଅନ୍ୟ"</string>
     <string name="phoneTypeCallback" msgid="3455781500844157767">"କଲବ୍ୟାକ୍"</string>
     <string name="phoneTypeCar" msgid="4604775148963129195">"କାର୍"</string>
     <string name="phoneTypeCompanyMain" msgid="4482773154536455441">"କମ୍ପାନୀର ମୁଖ୍ୟ"</string>
@@ -913,16 +890,16 @@
     <string name="emailTypeCustom" msgid="1809435350482181786">"କଷ୍ଟମ୍‌"</string>
     <string name="emailTypeHome" msgid="1597116303154775999">"ହୋମ"</string>
     <string name="emailTypeWork" msgid="2020095414401882111">"ୱାର୍କ"</string>
-    <string name="emailTypeOther" msgid="5131130857030897465">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="emailTypeOther" msgid="5131130857030897465">"ଅନ୍ୟ"</string>
     <string name="emailTypeMobile" msgid="787155077375364230">"ମୋବାଇଲ୍‍"</string>
     <string name="postalTypeCustom" msgid="5645590470242939129">"କଷ୍ଟମ୍‌"</string>
     <string name="postalTypeHome" msgid="7562272480949727912">"ହୋମ"</string>
     <string name="postalTypeWork" msgid="8553425424652012826">"ୱାର୍କ"</string>
-    <string name="postalTypeOther" msgid="7094245413678857420">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="postalTypeOther" msgid="7094245413678857420">"ଅନ୍ୟ"</string>
     <string name="imTypeCustom" msgid="5653384545085765570">"କଷ୍ଟମ୍‌"</string>
     <string name="imTypeHome" msgid="6996507981044278216">"ହୋମ"</string>
     <string name="imTypeWork" msgid="2099668940169903123">"ୱାର୍କ"</string>
-    <string name="imTypeOther" msgid="8068447383276219810">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="imTypeOther" msgid="8068447383276219810">"ଅନ୍ୟ"</string>
     <string name="imProtocolCustom" msgid="4437878287653764692">"କଷ୍ଟମ୍‌"</string>
     <string name="imProtocolAim" msgid="4050198236506604378">"AIM"</string>
     <string name="imProtocolMsn" msgid="2257148557766499232">"Windows Live"</string>
@@ -934,7 +911,7 @@
     <string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string>
     <string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string>
     <string name="orgTypeWork" msgid="8684458700669564172">"ୱାର୍କ"</string>
-    <string name="orgTypeOther" msgid="5450675258408005553">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="orgTypeOther" msgid="5450675258408005553">"ଅନ୍ୟ"</string>
     <string name="orgTypeCustom" msgid="1126322047677329218">"କଷ୍ଟମ୍‌"</string>
     <string name="relationTypeCustom" msgid="282938315217441351">"କଷ୍ଟମ୍‌"</string>
     <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
@@ -954,7 +931,7 @@
     <string name="sipAddressTypeCustom" msgid="6283889809842649336">"କଷ୍ଟମ୍‌"</string>
     <string name="sipAddressTypeHome" msgid="5918441930656878367">"ହୋମ"</string>
     <string name="sipAddressTypeWork" msgid="7873967986701216770">"ୱାର୍କ"</string>
-    <string name="sipAddressTypeOther" msgid="6317012577345187275">"ଅନ୍ୟାନ୍ୟ"</string>
+    <string name="sipAddressTypeOther" msgid="6317012577345187275">"ଅନ୍ୟ"</string>
     <string name="quick_contacts_not_available" msgid="1262709196045052223">"ଏହି କଣ୍ଟାକ୍ଟ ଦେଖିବାକୁ କୌଣସି ଆପ୍ଲିକେସନ ମିଳିଲା ନାହିଁ।"</string>
     <string name="keyguard_password_enter_pin_code" msgid="6401406801060956153">"PIN କୋଡ୍‍ ଟାଇପ୍‍ କରନ୍ତୁ"</string>
     <string name="keyguard_password_enter_puk_code" msgid="3112256684547584093">"PUK ଓ ନୂଆ PIN କୋଡ୍‍ ଟାଇପ୍‍ କରନ୍ତୁ"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଫୋନର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ଆପଣଙ୍କ <xliff:g id="DEVICE">%1$s</xliff:g>ରୁ ଟାବଲେଟର କ୍ୟାମେରାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ଏହାକୁ ଆକ୍ସେସ କରାଯାଇପାରିବ ନାହିଁ। ଏହା ପରିବର୍ତ୍ତେ ଆପଣଙ୍କ ଫୋନରେ ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ଷ୍ଟ୍ରିମ କରିବା ସମୟରେ ପିକଚର-ଇନ-ପିକଚର ଦେଖାଯାଇପାରିବ ନାହିଁ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ସିଷ୍ଟମ ଡିଫଲ୍ଟ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"କାର୍ଡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 6727f74..cb2886e 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ਵੌਇਸਮੇਲ"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ਕਨੈਕਸ਼ਨ ਸਮੱਸਿਆ ਜਾਂ ਅਵੈਧ MMI ਕੋਡ।"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ਵਿਸ਼ੇਸ਼ਤਾ ਸਮਰਥਿਤ ਨਹੀਂ ਹੈ।"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ਓਪਰੇਸ਼ਨ ਕੇਵਲ ਫਿਕਸਡ ਡਾਇਲਿੰਗ ਨੰਬਰਾਂ ਤੱਕ ਸੀਮਿਤ ਹੈ।"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ਤੁਹਾਡੇ ਰੋਮਿੰਗ ਵਿੱਚ ਹੋਣ ਦੌਰਾਨ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਕਾਲ ਫਾਰਵਰਡਿੰਗ ਸੈਟਿੰਗਾਂ ਨੂੰ ਬਦਲਿਆ ਨਹੀਂ ਜਾ ਸਕਦਾ।"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"ਸੇਵਾ ਅਸਮਰੱਥ ਬਣਾਈ ਗਈ ਸੀ।"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ਐਪ ਨੂੰ ਮੈਮਰੀ ਵਿੱਚ ਖੁਦ ਦੇ ਭਾਗਾਂ ਨੂੰ ਸਥਾਈ ਬਣਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਫ਼ੋਨ ਨੂੰ ਹੌਲੀ ਕਰਦੇ ਹੋਏ ਹੋਰਾਂ ਐਪਾਂ ਤੇ ਉਪਲਬਧ ਮੈਮਰੀ ਨੂੰ ਸੀਮਿਤ ਕਰ ਸਕਦਾ ਹੈ।"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ਫੋਰਗ੍ਰਾਉਂਡ ਸੇਵਾਵਾਂ ਚਲਾਓ"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ਐਪ ਨੂੰ ਫੋਰਗ੍ਰਾਉਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦਿਓ।"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"ਐਪ ਨੂੰ \"camera\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"ਐਪ ਨੂੰ \"connectedDevice\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"ਐਪ ਨੂੰ \"dataSync\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"ਐਪ ਨੂੰ \"location\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"ਐਪ ਨੂੰ \"mediaPlayback\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"ਐਪ ਨੂੰ \"mediaProjection\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"ਐਪ ਨੂੰ \"microphone\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"ਐਪ ਨੂੰ \"phoneCall\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"ਐਪ ਨੂੰ \"health\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"ਐਪ ਨੂੰ \"remoteMessaging\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"ਐਪ ਨੂੰ \"systemExempted\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਨੂੰ ਚਲਾਉਂਦੀ ਹੈ"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"ਐਪ ਨੂੰ \"specialUse\" ਕਿਸਮ ਨਾਲ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾਵਾਂ ਦੀ ਵਰਤੋਂ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ਐਪ ਸਟੋਰੇਜ ਜਗ੍ਹਾ ਮਾਪੋ"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ਐਪ ਨੂੰ ਇਸਦਾ ਕੋਡ, ਡਾਟਾ ਅਤੇ ਕੈਸ਼ੇ ਆਕਾਰ ਮੁੜ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ਸਿਸਟਮ ਸੈਟਿੰਗਾਂ  ਸੰਸ਼ੋਧਿਤ ਕਰੋ"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ਇਹ ਐਪ ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ ਵੇਲੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਵਰਤ ਕੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"ਇਹ ਐਪ ਕਿਸੇ ਵੇਲੇ ਵੀ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਨੂੰ ਵਰਤ ਕੇ ਆਡੀਓ ਰਿਕਾਰਡ ਕਰ ਸਕਦੀ ਹੈ।"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ਐਪ ਵਿੰਡੋਆਂ ਦੇ ਸਕ੍ਰੀਨ ਕੈਪਚਰਾਂ ਦਾ ਪਤਾ ਲਗਾਓ"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"ਐਪ ਦੇ ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ ਦੌਰਾਨ ਸਕ੍ਰੀਨਸ਼ਾਟ ਲੈਣ \'ਤੇ ਇਸ ਐਪ ਨੂੰ ਸੂਚਨਾ ਪ੍ਰਾਪਤ ਹੋਵੇਗੀ।"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"ਐਪ ਨੂੰ SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਬਹੁਤ ਘਾਤਕ ਹੈ।"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ਸਰੀਰਕ ਸਰਗਰਮੀ ਨੂੰ ਪਛਾਣਨਾ"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਫ਼ੋਨ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ਤੁਹਾਡੇ <xliff:g id="DEVICE">%1$s</xliff:g> ਤੋਂ ਟੈਬਲੈੱਟ ਦੇ ਕੈਮਰੇ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਇਸ ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ। ਇਸਦੀ ਬਜਾਏ ਆਪਣੇ ਫ਼ੋਨ \'ਤੇ ਵਰਤ ਕੇ ਦੇਖੋ।"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ਸਟ੍ਰੀਮਿੰਗ ਦੌਰਾਨ ਤਸਵੀਰ-ਵਿੱਚ-ਤਸਵੀਰ ਨਹੀਂ ਦੇਖੀ ਜਾ ਸਕਦੀ"</string>
     <string name="system_locale_title" msgid="711882686834677268">"ਸਿਸਟਮ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"ਕਾਰਡ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 0441a5f..70c9e32 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Poczta głosowa"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problem z połączeniem lub błędny kod MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcja nie jest obsługiwana."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacja jest ograniczona wyłącznie do numerów ustalonych."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Podczas roamingu nie można zmienić ustawień przekazywania połączeń z telefonu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Usługa została włączona."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Pozwala aplikacji na trwałe zapisywanie swoich fragmentów w pamięci. Może to zmniejszyć ilość pamięci dostępnej dla innych aplikacji i spowolnić działanie telefonu."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"uruchom usługę na pierwszym planie"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Zezwala na korzystanie przez aplikację z usług na pierwszym planie."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"uruchamianie usług działających na pierwszym planie typu „camera”"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „camera”"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"uruchamianie usług działających na pierwszym planie typu „connectedDevice”"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „connectedDevice”"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"uruchamianie usług działających na pierwszym planie typu „dataSync”"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „dataSync”"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"uruchamianie usług działających na pierwszym planie typu „location”"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „location”"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"uruchamianie usług działających na pierwszym planie typu „mediaPlayback”"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „mediaPlayback”"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"uruchamianie usług działających na pierwszym planie typu „mediaProjection”"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „mediaProjection”"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"uruchamianie usług działających na pierwszym planie typu „microphone”"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „microphone”"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"uruchamianie usług działających na pierwszym planie typu „phoneCall”"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „phoneCall”"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"uruchamianie usług działających na pierwszym planie typu „health”"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „health”"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"uruchamianie usług działających na pierwszym planie typu „remoteMessaging”"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „remoteMessaging”"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"uruchamianie usług działających na pierwszym planie typu „systemExempted”"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „systemExempted”"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"uruchamianie usług działających na pierwszym planie typu „specialUse”"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Zezwala na wykorzystywanie przez aplikację usług działających na pierwszym planie typu „specialUse”"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mierzenie rozmiaru pamięci aplikacji"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Pozwala aplikacji na pobieranie własnego kodu, danych oraz rozmiarów pamięci podręcznej."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modyfikowanie ustawień systemu"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ta aplikacja może nagrywać dźwięk przy użyciu mikrofonu, gdy jest używana."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"nagrywanie dźwięku w tle"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ta aplikacja może w dowolnym momencie nagrywać dźwięk przy użyciu mikrofonu."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"wykrywanie zrzutów ekranu z oknami aplikacji"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ta aplikacja będzie powiadamiana o zrzutach ekranu robionych po jej uruchomieniu."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"wysyłanie poleceń do karty SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Pozwala aplikacji na wysyłanie poleceń do karty SIM. To bardzo niebezpieczne."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznawanie aktywności fizycznej"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nie można korzystać z aparatu telefonu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nie można korzystać z aparatu tabletu na urządzeniu <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Nie można z tego skorzystać podczas strumieniowania. Użyj telefonu."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Podczas strumieniowania nie można wyświetlać obrazu w obrazie"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Ustawienie domyślne systemu"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f4a654b..255ed46 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Correio de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de conexão ou código MMI inválido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Recurso indisponível."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"A operação é limitada somente a números de discagem fixa."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Não é possível alterar as configurações de encaminhamento de chamada do seu smartphone em roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"O serviço foi ativado."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que o app torne partes de si mesmo persistentes na memória. Pode limitar a memória disponível para outros apps, deixando o telefone mais lento."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"executar serviço em primeiro plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que o app use serviços em primeiro plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"executar serviços em primeiro plano com o tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que o app use serviços em primeiro plano com o tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"executar serviços em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que o app use serviços em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"executar serviços em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que o app use serviços em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"executar serviços em primeiro plano com o tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que o app use serviços em primeiro plano com o tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"executar serviços em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que o app use serviços em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"executar serviços em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que o app use serviços em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"executar serviços em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que o app use serviços em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"executar serviços em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que o app use serviços em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"executar serviços em primeiro plano com o tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que o app use serviços em primeiro plano com o tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"executar serviços em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que o app use serviços em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"executar serviços em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que o app use serviços em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar serviços em primeiro plano com o tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que o app use serviços em primeiro plano com o tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espaço de armazenamento do app"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite que o app recupere o código, os dados e os tamanhos de cache"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar configurações do sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detectar capturas de tela de janelas do app"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"O app vai ser notificado quando uma captura de tela for tirada enquanto ele estiver em uso."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index a72cf67..480de87 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Correio de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de ligação ou código MMI inválido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funcionalidade não suportada."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"A operação está restringida a números fixos autorizados."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Não é possível alterar as definições do encaminhamento de chamadas no telemóvel quando está em roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"O serviço foi ativado."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que a app torne partes de si mesma persistentes na memória. Isto pode limitar a disponibilidade da memória para outras aplicações, tornando o telemóvel mais lento."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"executar serviço em primeiro plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que a app utilize serviços em primeiro plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"executar o serviço em primeiro plano com o tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que a app use serviços em primeiro plano com o tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"executar o serviço em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que a app use serviços em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"executar o serviço em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que a app use serviços em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"executar o serviço em primeiro plano com o tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que a app use serviços em primeiro plano com o tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"executar o serviço em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que a app use serviços em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"executar o serviço em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que a app use serviços em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"executar o serviço em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que a app use serviços em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"executar o serviço em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que a app use serviços em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"executar o serviço em primeiro plano com o tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que a app use serviços em primeiro plano com o tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"executar o serviço em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que a app use serviços em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"executar o serviço em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que a app use serviços em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar o serviço em primeiro plano com o tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que a app use serviços em primeiro plano com o tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir espaço de armazenamento da app"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite à app obter o código, os dados e o tamanhos de cache da mesma"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar as definições do sistema"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f4a654b..255ed46 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Correio de voz"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema de conexão ou código MMI inválido."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Recurso indisponível."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"A operação é limitada somente a números de discagem fixa."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Não é possível alterar as configurações de encaminhamento de chamada do seu smartphone em roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"O serviço foi ativado."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite que o app torne partes de si mesmo persistentes na memória. Pode limitar a memória disponível para outros apps, deixando o telefone mais lento."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"executar serviço em primeiro plano"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite que o app use serviços em primeiro plano."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"executar serviços em primeiro plano com o tipo \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite que o app use serviços em primeiro plano com o tipo \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"executar serviços em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite que o app use serviços em primeiro plano com o tipo \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"executar serviços em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite que o app use serviços em primeiro plano com o tipo \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"executar serviços em primeiro plano com o tipo \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite que o app use serviços em primeiro plano com o tipo \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"executar serviços em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite que o app use serviços em primeiro plano com o tipo \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"executar serviços em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite que o app use serviços em primeiro plano com o tipo \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"executar serviços em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite que o app use serviços em primeiro plano com o tipo \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"executar serviços em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite que o app use serviços em primeiro plano com o tipo \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"executar serviços em primeiro plano com o tipo \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite que o app use serviços em primeiro plano com o tipo \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"executar serviços em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite que o app use serviços em primeiro plano com o tipo \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"executar serviços em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite que o app use serviços em primeiro plano com o tipo \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"executar serviços em primeiro plano com o tipo \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite que o app use serviços em primeiro plano com o tipo \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"medir o espaço de armazenamento do app"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite que o app recupere o código, os dados e os tamanhos de cache"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modificar configurações do sistema"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Enquanto está sendo usado, este app pode gravar áudio usando o microfone."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"gravar áudio em segundo plano"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Este app pode gravar áudio usando o microfone a qualquer momento."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"detectar capturas de tela de janelas do app"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"O app vai ser notificado quando uma captura de tela for tirada enquanto ele estiver em uso."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"enviar comandos para o chip"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Permite que o app envie comandos ao chip. Muito perigoso."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"reconhecer atividade física"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Não é possível acessar a câmera do smartphone pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Não é possível acessar a câmera do tablet pelo <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Não é possível acessar esse conteúdo durante o streaming. Tente pelo smartphone."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Não é possível usar o modo picture-in-picture durante o streaming"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Padrão do sistema"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CHIP <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 3f9c0b5..4d8d96b4 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Mesagerie vocală"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problemă de conexiune sau cod MMI nevalid."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funcția nu este acceptată."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operația este limitată la numerele cu apelări restricționate."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nu poți schimba setările de redirecționare a apelurilor de pe telefon când ești în roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Serviciul a fost activat."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea telefonului."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"să ruleze serviciul în prim plan"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Permite aplicației să utilizeze serviciile din prim-plan."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"să folosească serviciile în prim-plan cu tipul „camera”"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Permite aplicației să folosească serviciile în prim-plan cu tipul „camera”"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"să folosească serviciile în prim-plan cu tipul „connectedDevice”"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Permite aplicației să folosească serviciile în prim-plan cu tipul „connectedDevice”"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"să folosească serviciile în prim-plan cu tipul „dataSync”"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Permite aplicației să folosească serviciile în prim-plan cu tipul „dataSync”"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"să folosească serviciile în prim-plan cu tipul „location”"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Permite aplicației să folosească serviciile în prim-plan cu tipul „location”"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"să folosească serviciile în prim-plan cu tipul „mediaPlayback”"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Permite aplicației să folosească serviciile în prim-plan cu tipul „mediaPlayback”"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"să folosească serviciile în prim-plan cu tipul „mediaProjection”"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Permite aplicației să folosească serviciile în prim-plan cu tipul „mediaProjection”"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"să folosească serviciile în prim-plan cu tipul „microphone”"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Permite aplicației să folosească serviciile în prim-plan cu tipul „microphone”"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"să folosească serviciile în prim-plan cu tipul „phoneCall”"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Permite aplicației să folosească serviciile în prim-plan cu tipul „phoneCall”"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"să folosească serviciile în prim-plan cu tipul „health”"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Permite aplicației să folosească serviciile în prim-plan cu tipul „health”"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"să folosească serviciile în prim-plan cu tipul „remoteMessaging”"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Permite aplicației să folosească serviciile în prim-plan cu tipul „remoteMessaging”"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"să folosească serviciile în prim-plan cu tipul „systemExempted”"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Permite aplicației să folosească serviciile în prim-plan cu tipul „systemExempted”"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"să folosească serviciile în prim-plan cu tipul „specialUse”"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Permite aplicației să folosească serviciile în prim-plan cu tipul „specialUse”"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"măsurare spațiu de stocare al aplicației"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifică setări de sistem"</string>
@@ -2341,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nu se poate accesa camera foto a telefonului de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nu se poate accesa camera foto a tabletei de pe <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Nu se poate accesa în timpul streamingului. Încearcă pe telefon."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Nu se poate viziona picture-in-picture în timpul streamingului"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Prestabilit de sistem"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 33612de..353131e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Голосовая почта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Неполадки подключения или неверный код MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функция не поддерживается."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Операция возможна только для разрешенных номеров."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Вы не можете изменить настройки переадресации вызовов, поскольку находитесь в роуминге."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Служба включена."</string>
@@ -89,7 +90,7 @@
     <string name="notification_channel_network_alert" msgid="4788053066033851841">"Оповещения"</string>
     <string name="notification_channel_call_forward" msgid="8230490317314272406">"Переадресация вызовов"</string>
     <string name="notification_channel_emergency_callback" msgid="54074839059123159">"Режим экстренных обратных вызовов"</string>
-    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Состояние мобильного Интернета"</string>
+    <string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Состояние мобильного интернета"</string>
     <string name="notification_channel_sms" msgid="1243384981025535724">"SMS"</string>
     <string name="notification_channel_voice_mail" msgid="8457433203106654172">"Голосовые сообщения"</string>
     <string name="notification_channel_wfc" msgid="9048240466765169038">"Звонки по Wi-Fi"</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Приложение сможет постоянно хранить свои компоненты в памяти. Это может уменьшить объем памяти, доступный другим приложениям, и замедлить работу устройства."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"Запуск активных сервисов"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Разрешить приложению использовать активные сервисы."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"запускать активные службы с типом camera"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Разрешить приложению использовать активные службы с типом camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"запускать активные службы с типом connectedDevice"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Разрешить приложению использовать активные службы с типом connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"запускать активные службы с типом dataSync"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Разрешить приложению использовать активные службы с типом dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"запускать активные службы с типом location"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Разрешить приложению использовать активные службы с типом location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"запускать активные службы с типом mediaPlayback"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Разрешить приложению использовать активные службы с типом mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"запускать активные службы с типом mediaProjection"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Разрешить приложению использовать активные службы с типом mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"запускать активные службы с типом microphone"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Разрешить приложению использовать активные службы с типом microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"запускать активные службы с типом phoneCall"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Разрешить приложению использовать активные службы с типом phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"запускать активные службы с типом health"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Разрешить приложению использовать активные службы с типом health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"запускать активные службы с типом remoteMessaging"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Разрешить приложению использовать активные службы с типом remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"запускать активные службы с типом systemExempted"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Разрешить приложению использовать активные службы с типом systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запускать активные службы с типом specialUse"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Разрешить приложению использовать активные службы с типом specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"Вычисление объема памяти приложений"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Приложение сможет получать сведения о размере кода, данных и кеша."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"Изменение настроек системы"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Когда приложение используется, оно может записывать аудио с помощью микрофона."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"Записывать аудио в фоновом режиме"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Приложение может в любое время записывать аудио с помощью микрофона."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"Обнаруживать запись экрана, когда открыто окно приложения"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Если во время использования приложения будет сделан скриншот, оно получит уведомление."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"Отправка команд SIM-карте"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Приложение сможет отправлять команды SIM-карте (данное разрешение представляет большую угрозу)."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"Распознавать физическую активность"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"У устройства <xliff:g id="DEVICE">%1$s</xliff:g> нет доступа к камере телефона."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"У устройства \"<xliff:g id="DEVICE">%1$s</xliff:g>\" нет доступа к камере планшета."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Этот контент недоступен во время трансляции. Используйте телефон."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Нельзя запустить режим \"Картинка в картинке\" во время потоковой передачи"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Системные настройки по умолчанию"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 3eab51b..7bee4de 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"කටහඬ තැපෑල"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"සම්බන්ධතා ගැටළුවක් හෝ අවලංගු MMI කේතයකි."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"විශේෂාංගය සහාය නොදක්වයි."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"ස්ථාවර ඇමතීම් අංක වලට පමණක් මෙහෙයුම සීමාකර ඇත."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ඔබ රෝමිං තුළ සිටින අතරතුර ඔබේ දුරකථනයෙන් ඇමතුම් ප්‍රතියොමු සැකසීම් වෙනස් කළ නොහැකිය."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"සේවාව සබල කරන ලදි."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"යෙදුමට තම කොටස් මතකය තුල නොබිඳීව රඳා පවත්වාගෙන යාමට අවසර දෙන්න. මෙය දුරකථනය මන්දගාමී කරමින් අනෙකුත් උපාංගයන් සඳහා ඉතිරි මතකය සීමා කිරීමට හැක."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"පෙරබිම් සේවාව ධාවනය කරන්න"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"පෙරබිම් සේවා භාවිත කිරීමට යෙදුමට ඉඩ දෙයි."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"කැමරාව\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"කැමරාව\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"ස්ථානය\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"ස්ථානය\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"මයික්‍රොෆෝනය\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"මයික්‍රොෆෝනය\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"සෞඛ්‍යය\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"සෞඛ්‍යය\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" වර්ගය සමග පෙරබිම් සේවාව ධාවනය කරන්න"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" වර්ගය සමග පෙරබිම් සේවා භාවිතා කිරීමට යෙදුමට ඉඩ දෙයි"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"යෙදුම් ආචයනයේ ඉඩ ප්‍රමාණය මැනීම"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"යෙදුමකට එහි කේතය, දත්ත සහ හැඹිලි ප්‍රමාණ ලබාගැනීමට අවසර දෙන්න."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"පද්ධති සැකසීම් වෙනස් කිරීම"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"මෙම යෙදුමට එය භාවිතයෙහි ඇති අතරතුර මයික්‍රෆෝනය භාවිත කර ඕඩියෝ පටිගත කිරීමට හැකිය."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"පසුබිමෙහි ඕඩියෝ පටිගත කරන්න"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"මෙම යෙදුමට ඕනෑම වේලාවක මයික්‍රෆෝනය භාවිත කර ඕඩියෝ පටිගත කිරීමට හැකිය."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"යෙදුම් කවුළුවල තිර ග්‍රහණ අනාවරණය කර ගන්න"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"යෙදුම භාවිතා කරන අතරේ තිර රුවක් ගත් විට මෙම යෙදුමට දැනුම් දෙනු ලැබේ."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM වෙත විධාන යැවීම"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"SIM වෙත විධාන ගෙන යාමට යෙදුමට අවසර දෙයි. මෙය ඉතා භයානක වේ."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"ශාරීරික ක්‍රියාකාරකම හඳුනා ගන්න"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් දුරකථනයේ කැමරාවට ප්‍රවේශ විය නොහැකිය"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"ඔබගේ <xliff:g id="DEVICE">%1$s</xliff:g> වෙතින් ටැබ්ලටයේ කැමරාවට ප්‍රවේශ විය නොහැකිය"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ප්‍රවාහය කරන අතරේ මෙයට ප්‍රවේශ විය නොහැක. ඒ වෙනුවට ඔබේ දුරකථනයෙහි උත්සාහ කරන්න."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ප්‍රවාහය අතරේ පින්තූරයේ-පින්තූරය බැලිය නොහැක"</string>
     <string name="system_locale_title" msgid="711882686834677268">"පද්ධති පෙරනිමිය"</string>
     <string name="default_card_name" msgid="9198284935962911468">"කාඩ්පත <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index de86dfe..7fa87e4 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Hlasová schránka"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problém s pripojením alebo neplatný kód MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcia nie je podporovaná."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operácia je obmedzená len na povolené čísla."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nastavenia presmerovania hovorov nie je možné zmeniť z telefónu počas roamingu."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Služba bola povolená."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Umožňuje aplikácii uložiť niektoré svoje časti natrvalo do pamäte. Môže to obmedziť pamäť dostupnú pre ostatné aplikácie a spomaliť tak telefón."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"spustiť službu v popredí"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Umožňuje aplikácii používať služby v popredí"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"spustiť službu na popredí s typom camera"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Umožňuje aplikácii využívať služby na popredí s typom camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"spustiť službu na popredí s typom connectedDevice"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Umožňuje aplikácii využívať služby na popredí s typom connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"spustiť službu na popredí s typom dataSync"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Umožňuje aplikácii využívať služby na popredí s typom dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"spustiť službu na popredí s typom location"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Umožňuje aplikácii využívať služby na popredí s typom location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"spustiť službu na popredí s typom mediaPlayback"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Umožňuje aplikácii využívať služby na popredí s typom mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"spustiť službu na popredí s typom mediaProjection"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Umožňuje aplikácii využívať služby na popredí s typom mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"spustiť službu na popredí s typom microphone"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Umožňuje aplikácii využívať služby na popredí s typom microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"spustiť službu na popredí s typom phoneCall"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Umožňuje aplikácii využívať služby na popredí s typom phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"spustiť službu na popredí s typom health"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Umožňuje aplikácii využívať služby na popredí s typom health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"spustiť službu na popredí s typom remoteMessaging"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Umožňuje aplikácii využívať služby na popredí s typom remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"spustiť službu na popredí s typom systemExempted"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Umožňuje aplikácii využívať služby na popredí s typom dataSync systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"spustiť službu na popredí s typom specialUse"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Umožňuje aplikácii využívať služby na popredí s typom specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"zistiť veľkosť ukladacieho priestoru aplikácie"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Umožňuje aplikácii načítať svoj kód, údaje a veľkosti vyrovnávacej pamäte"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"upraviť nastavenia systému"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Táto aplikácia môže nahrávať zvuk pomocou mikrofónu, keď ju používate."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"nahrávanie zvuku na pozadí"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Táto aplikácia môže kedykoľvek nahrávať zvuk pomocou mikrofónu."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"rozpoznávanie snímaní obrazovky zahŕňajúcich okná aplikácie"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Táto aplikácia dostane upozornenie, keď bude počas jej používania vytvorená snímka obrazovky."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"posielanie príkazov do SIM karty"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Umožňuje aplikácii odosielať príkazy na SIM kartu. Toto je veľmi nebezpečné povolenie."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"rozpoznávanie fyzickej aktivity"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere telefónu"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"V zariadení <xliff:g id="DEVICE">%1$s</xliff:g> nemáte prístup ku kamere tabletu"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"K tomuto obsahu nie je počas streamovania prístup. Skúste použiť telefón."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Počas streamingu sa obraz v obraze nedá zobraziť"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Predvolené systémom"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 52c5441..d98a130 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Glasovna pošta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Težava s povezavo ali neveljavna koda MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funkcija ni podprta."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Operacija je omejena na dovoljene telefonske številke, za katere ne velja zapora odhodnega klica."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Nastavitev preusmerjanja klicev ni mogoče spremeniti v telefonu med gostovanjem v tujem omrežju."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Storitev je omogočena."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Aplikaciji omogoča, da nekatere svoje dele naredi trajne v pomnilniku. S tem je lahko pomnilnik omejen za druge aplikacije, zaradi česar je delovanje telefona upočasnjeno."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"Izvajanje storitve v ospredju"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Aplikaciji dovoljuje uporabo storitev v ospredju."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"izvajanje storitve v ospredju vrste »camera«"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »camera«."</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"izvajanje storitve v ospredju vrste »connectedDevice«"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »connectedDevice«."</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"izvajanje storitve v ospredju vrste »dataSync«"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »dataSync«."</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"izvajanje storitve v ospredju vrste »location«"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »location«."</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"izvajanje storitve v ospredju vrste »mediaPlayback«"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »mediaPlayback«."</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"izvajanje storitve v ospredju vrste »mediaProjection«"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »mediaProjection«."</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"izvajanje storitve v ospredju vrste »microphone«"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »microphone«."</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"izvajanje storitve v ospredju vrste »phoneCall«"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »phoneCall«."</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"izvajanje storitve v ospredju vrste »health«"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »health«."</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"izvajanje storitve v ospredju vrste »remoteMessaging«"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »remoteMessaging«."</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"izvajanje storitve v ospredju vrste »systemExempted«"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »systemExempted«."</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"izvajanje storitve v ospredju vrste »specialUse«"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Aplikaciji dovoljuje, da uporablja storitve v ospredju vrste »specialUse«."</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"izračunavanje prostora za shranjevanje aplikacije"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Aplikaciji omogoča, da pridobi njeno kodo, podatke in velikosti predpomnilnika."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"spreminjanje sistemskih nastavitev"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ta aplikacija lahko uporablja mikrofon za snemanje zvoka med uporabo aplikacije."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"snemanje zvoka v ozadju"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ta aplikacija lahko poljubno uporablja mikrofon za snemanje zvoka."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"zaznavanje zajemov zaslonskih slik v oknih aplikacij"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ta aplikacija bo obveščena o vsakem posnetku zaslona, ustvarjenem med njeno uporabo."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"pošiljanje ukazov na kartico SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Aplikaciji dovoli pošiljanje ukazov kartici SIM. To je lahko zelo nevarno."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"prepoznavanje telesne dejavnosti"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ni mogoče dostopati do fotoaparata telefona prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ni mogoče dostopati do fotoaparata tabličnega računalnika prek naprave <xliff:g id="DEVICE">%1$s</xliff:g>."</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Do te vsebine ni mogoče dostopati med pretočnim predvajanjem. Poskusite s telefonom."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Slike v sliki ni mogoče prikazati med pretočnim predvajanjem."</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistemsko privzeto"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTICA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index d5c8c87..17c1f63a 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Posta zanore"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problem në lidhje ose kod i pavlefshëm MMI-je."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Veçoria nuk mbështetet."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Veprimi është i kufizuar vetëm kundrejt numrave me telefonim të përzgjedhur"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Cilësimet e transferimit të telefonatave nuk mund të ndryshohen nga telefoni yt kur je në roaming."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Shërbimi u aktivizua."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Lejon aplikacionin të zaptojë një pjesë të qëndrueshme në kujtesë. Kjo mund të kufizojë kujtesën e disponueshme për aplikacionet e tjera duke e ngadalësuar telefonin."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ekzekuto shërbimin në plan të parë"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Lejon aplikacionin të përdorë shërbimet në plan të parë."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"të ekzekutojë shërbimin në plan të parë me llojin \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"të ekzekutojë shërbimin në plan të parë me llojin \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"të ekzekutojë shërbimin në plan të parë me llojin \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"të ekzekutojë shërbimin në plan të parë me llojin \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"të ekzekutojë shërbimin në plan të parë me llojin \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"të ekzekutojë shërbimin në plan të parë me llojin \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"të ekzekutojë shërbimin në plan të parë me llojin \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"të ekzekutojë shërbimin në plan të parë me llojin \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"të ekzekutojë shërbimin në plan të parë me llojin \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"të ekzekutojë shërbimin në plan të parë me llojin \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"të ekzekutojë shërbimin në plan të parë me llojin \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"të ekzekutojë shërbimin në plan të parë me llojin \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Lejon që aplikacioni të përdorë shërbimet në plan të parë me llojin \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mat hapësirën ruajtëse të aplikacionit"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Lejon aplikacionin të gjejë kodin e tij, të dhënat dhe madhësitë e memorieve të përkohshme."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"modifiko cilësimet e sistemit"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ky aplikacion mund të regjistrojë audion duke përdorur mikrofonin kur aplikacioni është në përdorim."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"të regjistrojë audion në sfond"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ky aplikacion mund të regjistrojë audion me mikrofonin në çdo kohë."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"të zbulojë regjistrimet e ekranit të dritareve të aplikacionit"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ky aplikacion do të njoftohet kur nxirret një pamje ekrani ndërkohë që aplikacioni është në përdorim."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"dërgo komanda te karta SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Lejon aplikacionin t\'i dërgojë komanda kartës SIM. Kjo është shumë e rrezikshme."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"njih aktivitetin fizik"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Nuk mund të qasesh në kamerën e telefonit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Nuk mund të qasesh në kamerën e tabletit tënd nga <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Nuk mund të kesh qasje në të gjatë transmetimit. Provoje në telefon më mirë."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Figura brenda figurës nuk mund të shikohet gjatë transmetimit"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Parazgjedhja e sistemit"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 142d2dd..e7b1b12 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Гласовна пошта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Проблеми са везом или неважећи MMI кôд."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функција није подржана."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Рад је ограничен само на бројеве фиксног бирања."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Не можете да промените подешавања преусмеравања позива са телефона док сте у ромингу."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Услуга је омогућена."</string>
@@ -396,54 +397,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори телефон."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"покрени услугу у првом плану"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Дозвољава апликацији да користи услуге у првом плану."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"покретање услуге у првом плану која припада типу „camera“"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „camera“"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"покретање услуге у првом плану која припада типу „connectedDevice“"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „connectedDevice“"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"покретање услуге у првом плану која припада типу „dataSync“"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „dataSync“"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"покретање услуге у првом плану која припада типу „location“"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „location“"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"покретање услуге у првом плану која припада типу „mediaPlayback“"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „mediaPlayback“"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"покретање услуге у првом плану која припада типу „mediaProjection“"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „mediaProjection“"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"покретање услуге у првом плану која припада типу „microphone“"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „microphone“"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"покретање услуге у првом плану која припада типу „phoneCall“"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „phoneCall“"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"покретање услуге у првом плану која припада типу „health“"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „health“"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"покретање услуге у првом плану која припада типу „remoteMessaging“"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „remoteMessaging“"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"покретање услуге у првом плану која припада типу „systemExempted“"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „systemExempted“"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"покретање услуге у првом плану која припада типу „specialUse“"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозвољава апликацији да користи услуге у првом плану које припадају типу „specialUse“"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"мерење меморијског простора у апликацији"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Дозвољава апликацији да преузме величине кôда, података и кеша."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"измена подешавања система"</string>
@@ -496,10 +473,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ова апликација може да снима звук помоћу микрофона док се апликација користи."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"да снима звук у позадини"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ова апликација може да снима звук помоћу микрофона у било ком тренутку."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"откривање снимања екрана у прозорима апликација"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ако се током коришћења ове апликације направи снимак екрана, апликација ће добити обавештење."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"слање команди на SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Омогућава апликацији да шаље команде SIM картици. То је веома опасно."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"препознавање физичких активности"</string>
@@ -2343,8 +2318,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не може да се приступи камери телефона са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не може да се приступи камери таблета са <xliff:g id="DEVICE">%1$s</xliff:g> уређаја"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Овом не можете да приступате током стримовања. Пробајте на телефону."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Не можете да гледате слику у слици при стримовању"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Подразумевани системски"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТИЦА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index baeffd2..7d4ba74 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Röstbrevlåda"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Anslutningsproblem eller ogiltig MMI-kod."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Funktionen stöds inte."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Endast fasta nummer kan användas."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Det går inte att ändra inställningarna för vidarebefordran av samtal medan mobilen är i roaming-läge."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Tjänsten har aktiverats."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Tillåter att delar av appen läggs beständigt i minnet. Detta kan innebära att det tillgängliga minnet för andra appar begränsas, vilket gör mobilen långsam."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"kör tjänst i förgrunden"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Tillåter att appen använder tjänster i förgrunden."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"kör förgrundstjänst av typen camera"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Tillåter att appen använder förgrundstjänster av typen camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"kör förgrundstjänst av typen connectedDevice"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Tillåter att appen använder förgrundstjänster av typen connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"kör förgrundstjänst av typen dataSync"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Tillåter att appen använder förgrundstjänster av typen dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"kör förgrundstjänst av typen location"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Tillåter att appen använder förgrundstjänster av typen location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"kör förgrundstjänst av typen mediaPlayback"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Tillåter att appen använder förgrundstjänster av typen mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"kör förgrundstjänst av typen mediaProjection"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Tillåter att appen använder förgrundstjänster av typen mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"kör förgrundstjänst av typen microphone"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Tillåter att appen använder förgrundstjänster av typen microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"kör förgrundstjänst av typen phoneCall"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Tillåter att appen använder förgrundstjänster av typen phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"kör förgrundstjänst av typen health"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Tillåter att appen använder förgrundstjänster av typen health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"kör förgrundstjänst av typen remoteMessaging"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Tillåter att appen använder förgrundstjänster av typen remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"kör förgrundstjänst av typen systemExempted"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Tillåter att appen använder förgrundstjänster av typen systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kör förgrundstjänst av typen specialUse"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Tillåter att appen använder förgrundstjänster av typen specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"mäta appens lagringsplats"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Tillåter att appen hämtar kod, data och cachestorlekar"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"ändra systeminställningar"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Appen kan ta spela in ljud med mikrofonen när appen används."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"spela in ljud i bakgrunden"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Appen kan spela in ljud med mikrofonen när som helst."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"upptäck skärmbilder/skärminspelningar av appfönster"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Den här appen informeras om en skärmbild tas när appen används."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"skicka kommandon till SIM-kortet"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Tillåter att appen skickar kommandon till SIM-kortet. Detta är mycket farligt."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"känn igen fysisk aktivitet"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Telefonens kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Surfplattans kamera kan inte användas från <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Det går inte att komma åt innehållet när du streamar. Testa med telefonen i stället."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Det går inte att visa bild-i-bild när du streamar"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Systemets standardinställning"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KORT <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index ea63885..702e97f 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Ujumbe wa sauti"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Tatizo la muunganisho au msimbo batili MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Kipengele hakitumiki."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Ni matumizi yanayohusisha nambari za simu zilizobainishwa pekee yatakayowezekana."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Haiwezi kubadilisha mipangilio ya kusambaza simu kutoka kwenye simu yako ukiwa unatumia mitandao mingine."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Huduma iliwezeshwa"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Inaruhusu programu kuendelesha vijisehemu vyake kwenye kumbukumbu. Hii inaweza kupunguza kumbukumbu inayopatikana katika programu nyingine ikipunguza kasi ya simu."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"tumia huduma zinazoonekana kwenye skrini"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Huruhusu programu kutumia huduma zinazoonekana kwenye skrini."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"health\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"kutekeleza huduma inayoonekana kwenye skrini inayohusiana na \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Huruhusu programu itumie huduma zinazoonekana kwenye skrini zinazohusiana na \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"Pima nafasi ya hifadhi ya programu"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Huruhusu Programu kupata tena msimbo, data na ukubwa wa akiba yake"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"rekebisha mipangilio ya mfumo"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Programu hii inaweza kurekodi sauti kwa kutumia maikrofoni wakati programu inatumika."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"rekodi sauti chinichini"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Programu hii inaweza kurekodi sauti kwa kutumia maikrofoni wakati wowote."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"tambua picha za skrini za madirisha ya programu"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Programu hii itaarifiwa picha ya skrini itakapopigwa wakati programu inatumika."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"tuma amri kwenye SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Huruhusu programu kutuma amri kwa SIM. Hii ni hatari sana."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"itambue shughuli unazofanya"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Huwezi kufikia kamera ya simu kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Haiwezi kufikia kamera ya kompyuta kibao kutoka kwenye <xliff:g id="DEVICE">%1$s</xliff:g> yako"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Huwezi kufikia maudhui haya unapotiririsha. Badala yake jaribu kwenye simu yako."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Huwezi kuona picha iliyopachikwa ndani ya picha nyingine unapotiririsha"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Chaguomsingi la mfumo"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM KADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 461ddbd..7e1ad9e 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"குரலஞ்சல்"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"இணைப்பு சிக்கல் அல்லது தவறான MMI குறியீடு."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"அம்சம் ஆதரிக்கப்படவில்லை."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"நிலையான அழைப்பு எண்களுக்கு மட்டுமே எனச் செயல்பாடு வரையறுக்கப்பட்டுள்ளது."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ரோமிங்கில் இருக்கும் போது, உங்கள் மொபைலிலிருந்து அழைப்புப் பகிர்வு அமைப்புகளை மாற்ற முடியாது."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"சேவை இயக்கப்பட்டுள்ளது."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"நினைவகத்தில் நிலையாக இருக்கும் தன்னுடைய பகுதிகளை உருவாக்கப் ஆப்ஸை அனுமதிக்கிறது. இதனால பிற பயன்பாடுகளுக்குக் கிடைக்கும் நினைவகம் வரையறுக்கப்பட்டு, மொபைலின் வேகத்தைக் குறைக்கலாம்"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"முன்புலத்தில் இயங்கும் சேவையை இயக்குதல்"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"முன்புலத்தில் இயங்கும் சேவைகளை உபயோகிக்க, ஆப்ஸை அனுமதிக்கிறது."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"camera\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"location\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"microphone\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"health\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" எனும் வகையைக் கொண்ட முன்புலச் சேவையை இயக்குதல்"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" எனும் வகையைக் கொண்ட முன்புலச் சேவைகளைப் பயன்படுத்த ஆப்ஸை அனுமதிக்கும்"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ஆப்ஸ் சேமிப்பு இடத்தை அளவிடல்"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ஆப்ஸ், அதன் குறியீடு, தரவு, மற்றும் தற்காலிகச் சேமிப்பு அளவுகளை மீட்டெடுக்க அனுமதிக்கிறது"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"சாதன அமைப்புகளை மாற்றுதல்"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"இந்த ஆப்ஸ் உபயோகத்தில் இருக்கும்போதே இதனால் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்ய முடியும்."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"பின்புலத்தில் ஆடியோ ரெக்கார்டு செய்தல்"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"இந்த ஆப்ஸால் எப்போது வேண்டுமானாலும் மைக்ரோஃபோனைப் பயன்படுத்தி ஆடியோவை ரெக்கார்டு செய்ய முடியும்."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ஆப்ஸ் சாளரங்களில் திரையைப் படமெடுத்தலைக் கண்டறிதல்"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"இந்த ஆப்ஸ் பயன்பாட்டில் இருக்கும்போது ஸ்கிரீன்ஷாட் எடுக்கப்பட்டால் ஆப்ஸுக்கு அறிவிக்கப்படும்."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"கட்டளைகளை சிம்மிற்கு அனுப்புதல்"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"சிம் க்குக் கட்டளைகளை அனுப்ப ஆப்ஸை அனுமதிக்கிறது. இது மிகவும் ஆபத்தானதாகும்."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"உடல் செயல்பாட்டைக் கண்டறிதல்"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து மொபைலின் கேமராவை அணுக முடியாது"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"உங்கள் <xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்திலிருந்து டேப்லெட்டின் கேமராவை அணுக முடியாது"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"ஸ்ட்ரீமின்போது இதை அணுக முடியாது. அதற்குப் பதிலாக உங்கள் மொபைலில் பயன்படுத்திப் பார்க்கவும்."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"ஸ்ட்ரீம் செய்யும்போது பிக்ச்சர்-இன்-பிக்ச்சர் அம்சத்தைப் பயன்படுத்த முடியாது"</string>
     <string name="system_locale_title" msgid="711882686834677268">"சிஸ்டத்தின் இயல்பு"</string>
     <string name="default_card_name" msgid="9198284935962911468">"கார்டு <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 37d4328..5355f6f 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"వాయిస్ మెయిల్"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"కనెక్షన్ సమస్య లేదా చెల్లని MMI కోడ్."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ప్రస్తుత మొబైల్ నెట్‌వర్క్‌లో ఫీచర్ సపోర్ట్ చేయడం లేదు."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"చర్య స్థిరమైన డయలింగ్ నంబర్‌లకు మాత్రమే పరిమితం చేయబడింది."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"మీరు రోమింగ్‌లో ఉన్నప్పుడు మీ ఫోన్‌ నుండి కాల్ ఫార్వార్డింగ్ సెట్టింగ్‌లను మార్చలేరు."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"సేవ ప్రారంభించబడింది."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"యాప్‌, దాని భాగాలు మెమరీలో ఉండేలా చేయడానికి దానిని అనుమతిస్తుంది. ఇది ఇతర యాప్‌లకు అందుబాటులో ఉన్న మెమరీని ఆక్రమిస్తుంది, ఫోన్ నెమ్మదిగా పని చేస్తుంది."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"సేవని ముందు భాగంలో అమలు చేయడం"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ముందు భాగంలో సేవలను ఉపయోగించడానికి యాప్‌ని అనుమతిస్తుంది."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"\"camera\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"\"connectedDevice\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"\"dataSync\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"\"location\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"\"mediaPlayback\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"\"mediaProjection\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"\"microphone\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"\"phoneCall\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"\"health\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించుకోవడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"\"remoteMessaging\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"\"systemExempted\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌ను రన్ చేయండి"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"\"specialUse\" అనే రకంతో ఫోర్‌గ్రౌండ్ సర్వీస్‌లను ఉపయోగించడానికి యాప్‌ను అనుమతిస్తుంది"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"యాప్ నిల్వ స్థలాన్ని అంచనా వేయడం"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"యాప్‌ కోడ్, డేటా మరియు కాష్ పరిమాణాలను తిరిగి పొందడానికి దాన్ని అనుమతిస్తుంది"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"సిస్టమ్ సెట్టింగ్‌లను మార్చడం"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"యాప్ ఉపయోగంలో ఉన్నపుడు మైక్రోఫోన్‌ను ఉపయోగించి ఈ యాప్, ఆడియోను రికార్డ్ చేయగలదు."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"బ్యాక్‌గ్రౌండ్‌లో ఆడియోను రికార్డ్ చేయగలదు"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"మైక్రోఫోన్‌ను ఉపయోగించి ఈ యాప్ ఎప్పుడైనా ఆడియోను రికార్డ్ చేయగలదు."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"యాప్ విండోలకు సంబంధించిన స్క్రీన్ క్యాప్చర్‌లను గుర్తించండి"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"యాప్ ఉపయోగంలో ఉన్నప్పుడు స్క్రీన్‌షాట్ తీయబడినప్పుడు ఈ యాప్‌కు తెలియజేయబడుతుంది."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIMకి ఆదేశాలను పంపడం"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"సిమ్‌కు ఆదేశాలను పంపడానికి యాప్‌ను అనుమతిస్తుంది. ఇది చాలా ప్రమాదకరం."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"భౌతిక కార్యాకలాపాన్ని గుర్తించండి"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి ఫోన్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"మీ <xliff:g id="DEVICE">%1$s</xliff:g> నుండి టాబ్లెట్ కెమెరాను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"స్ట్రీమింగ్ చేస్తున్నప్పుడు దీన్ని యాక్సెస్ చేయడం సాధ్యపడదు. బదులుగా మీ ఫోన్‌లో ట్రై చేయండి."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"స్ట్రీమింగ్ చేస్తున్నప్పుడు పిక్చర్-ఇన్-పిక్చర్ చూడలేరు"</string>
     <string name="system_locale_title" msgid="711882686834677268">"సిస్టమ్ ఆటోమేటిక్ సెట్టింగ్"</string>
     <string name="default_card_name" msgid="9198284935962911468">"కార్డ్ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 81c1d39..1bdaa50 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"ข้อความเสียง"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"ปัญหาการเชื่อมต่อหรือรหัส MMI ไม่ถูกต้อง"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"ไม่รองรับฟีเจอร์"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"การดำเนินการถูกจำกัดไว้ที่การจำกัดหมายเลขโทรออกเท่านั้น"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"ไม่สามารถเปลี่ยนการตั้งค่าการโอนสายจากโทรศัพท์ในขณะที่โรมมิ่ง"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"เปิดใช้งานบริการแล้ว"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"อนุญาตให้แอปพลิเคชันทำให้ส่วนหนึ่งของตัวเองคงอยู่ถาวรในหน่วยความจำ ซึ่งจะจำกัดพื้นที่หน่วยความจำที่ใช้งานได้ของแอปพลิเคชันอื่นๆ และทำให้โทรศัพท์ทำงานช้าลง"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"เรียกใช้บริการที่ใช้งานอยู่"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ใช้งานอยู่"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"กล้อง\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"กล้อง\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"อุปกรณ์ที่เชื่อมต่อ\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"อุปกรณ์ที่เชื่อมต่อ\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การซิงค์ข้อมูล\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การซิงค์ข้อมูล\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ตำแหน่ง\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ตำแหน่ง\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การเล่นสื่อ\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การเล่นสื่อ\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การฉายภาพสื่อ\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การฉายภาพสื่อ\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ไมโครโฟน\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ไมโครโฟน\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การโทร\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การโทร\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"สุขภาพ\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"สุขภาพ\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การรับส่งข้อความระยะไกล\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การรับส่งข้อความระยะไกล\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ได้รับการยกเว้นจากระบบ\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"ได้รับการยกเว้นจากระบบ\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"เรียกใช้บริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การใช้งานพิเศษ\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"อนุญาตให้แอปใช้ประโยชน์จากบริการที่ทำงานอยู่เบื้องหน้าโดยมีประเภทเป็น \"การใช้งานพิเศษ\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"วัดพื้นที่เก็บข้อมูลของแอปพลิเคชัน"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"อนุญาตให้แอปพลิเคชันเรียกดูรหัส ข้อมูล และขนาดแคชของตน"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"แก้ไขการตั้งค่าระบบ"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 46783ea..bb17eb9 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Voicemail"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Problema sa koneksyon o di-wastong MMI code."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Hindi sinusuportahan ang feature."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Pinaghihigpitan ang pagpapatakbo sa mga fixed dialing number lang."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Hindi maaaring baguhin ang mga setting ng pagpapasa ng tawag mula sa iyong telepono habang naka-roaming ka."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Pinagana ang serbisyo."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Pinapayagan ang app na panatilihin ang ilang bahagi nito sa memory. Maaari nitong limitahan ang memory na available sa iba pang apps na nagpapabagal sa telepono."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"paganahin ang foreground na serbisyo"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Payagan ang app na gamitin ang mga foreground na serbisyo."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"magpagana ng serbisyo sa foreground na may uring \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"magpagana ng serbisyo sa foreground na may uring \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"magpagana ng serbisyo sa foreground na may uring \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"magpagana ng serbisyo sa foreground na may uring \"lokasyon\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"lokasyon\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"magpagana ng serbisyo sa foreground na may uring \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"magpagana ng serbisyo sa foreground na may uring \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Nagbibigay-daan sa na gamitin ang mga serbisyo sa foreground na may uring \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"magpagana ng serbisyo sa foreground na may uring \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"magpagana ng serbisyo sa foreground gamit na may uring \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"magpagana ng serbisyo sa foreground na may uring \"kalusugan\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"kalusugan\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"magpagana ng serbisyo sa foreground na may uring \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"magpagana ng serbisyo sa foreground na may uring \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"magpagana ng serbisyo sa foreground na may uring \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Nagbibigay-daan sa app na gamitin ang mga serbisyo sa foreground na may uring \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"sukatin ang espasyo ng storage ng app"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Pinapayagan ang app na bawiin ang code, data, at mga laki ng cache nito"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"baguhin ang mga setting ng system"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Hindi ma-access ang camera ng telepono mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Hindi ma-access ang camera ng tablet mula sa iyong <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Hindi ito puwedeng i-access habang nagsi-stream. Subukan na lang sa iyong telepono."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Hindi matingnan nang picture-in-picture habang nagsi-stream"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Default ng system"</string>
     <string name="default_card_name" msgid="9198284935962911468">"CARD <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 87d7ba7..3e974e3 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Sesli Mesaj"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Bağlantı sorunu veya geçersiz MMI kodu."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Özellik desteklenmiyor."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"İşlem sadece sabit arama numaralarıyla sınırlandırılmıştır."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Dolaşımdayken telefonunuzdan çağrı yönlendirme ayarları değiştirilemiyor."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Hizmet etkindi."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Uygulamaya kendisinin bir bölümünü bellekte kalıcı yapma izni verir. Bu izin, diğer uygulamaların kullanabileceği belleği sınırlandırarak telefonun yavaş çalışmasına neden olabilir."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"ön plan hizmetini çalıştırma"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Uygulamanın ön plan hizmetlerinden faydalanmasına izin verir."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"camera\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Uygulamanın \"camera\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"\"connectedDevice\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Uygulamanın \"connectedDevice\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"\"dataSync\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Uygulamanın \"dataSync\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"location\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Uygulamanın \"location\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"\"mediaPlayback\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Uygulamanın \"mediaPlayback\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"\"mediaProjection\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Uygulamanın \"mediaProjection\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"microphone\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Uygulamanın \"microphone\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"\"phoneCall\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Uygulamanın \"phoneCall\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"health\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Uygulamanın \"health\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"\"remoteMessaging\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Uygulamanın \"remoteMessaging\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"\"systemExempted\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Uygulamanın \"systemExempted\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"\"specialUse\" türüyle ön plan hizmetini çalıştırma"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Uygulamanın \"specialUse\" türüyle ön plan hizmetlerini kullanmasına izin verir"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"uygulama depolama alanını ölç"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Uygulamaya kodunu, verilerini ve önbellek boyutlarını alma izni verir"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"sistem ayarlarını değiştirme"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Bu uygulama, kullanıldığı sırada mikrofonu kullanarak ses kaydedebilir."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"arka planda ses kaydeder"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Bu uygulama, herhangi bir zaman mikrofonu kullanarak ses kaydedebilir."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"uygulama pencerelerindeki ekran görüntülerini algılama"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Uygulama kullanılırken ekran görüntüsü alındığında bu uygulama bilgilendirilir."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"SIM karta komut gönderme"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Uygulamanın SIM karta komut göndermesine izin verir. Bu izin çok tehlikelidir."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"fiziksel aktiviteyi algıla"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan telefonun kamerasına erişilemiyor"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazınızdan tabletin kamerasına erişilemiyor"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Canlı oynatılırken bu içeriğe erişilemez. Bunun yerine telefonunuzu kullanmayı deneyin."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Yayın sırasında pencere içinde pencere görüntülenemez"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Sistem varsayılanı"</string>
     <string name="default_card_name" msgid="9198284935962911468">"KART <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 7a81546..528575b 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Голосова пошта"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Пробл. підключення чи недійсний код MMI."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Функція не підтримується."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Операція лише для номерів фіксованого набору."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"У роумінгу на телефоні не можна змінити налаштування переадресації викликів."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Послугу ввімкнено."</string>
@@ -397,54 +398,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Дозволяє програмі робити свої частини сталими в пам’яті. Це може зменшувати обсяг пам’яті, доступної для інших програм, і сповільнювати роботу телефону."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"запускати пріоритетну службу"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Додаток може використовувати пріоритетні служби."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"запускати сервіс типу camera в активному режимі"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Дозволяє додатку використовувати активні сервіси типу camera"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"запускати сервіс типу connectedDevice в активному режимі"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Дозволяє додатку використовувати активні сервіси типу connectedDevice"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"запускати сервіс типу dataSync в активному режимі"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Дозволяє додатку використовувати активні сервіси типу dataSync"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"запускати сервіс типу location в активному режимі"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Дозволяє додатку використовувати активні сервіси типу location"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"запускати сервіс типу mediaPlayback в активному режимі"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Дозволяє додатку використовувати активні сервіси типу mediaPlayback"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"запускати сервіс типу mediaProjection в активному режимі"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Дозволяє додатку використовувати активні сервіси типу mediaProjection"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"запускати сервіс типу microphone в активному режимі"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Дозволяє додатку використовувати активні сервіси типу microphone"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"запускати сервіс типу phoneCall в активному режимі"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Дозволяє додатку використовувати активні сервіси типу phoneCall"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"запускати сервіс типу health в активному режимі"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Дозволяє додатку використовувати активні сервіси типу health"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"запускати сервіс типу remoteMessaging в активному режимі"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Дозволяє додатку використовувати активні сервіси типу remoteMessaging"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"запускати сервіс типу systemExempted в активному режимі"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Дозволяє додатку використовувати активні сервіси типу systemExempted"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"запускати сервіс типу specialUse в активному режимі"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Дозволяє додатку використовувати активні сервіси типу specialUse"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"визначати об’єм пам’яті програми"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Дозволяє програмі отримувати її код, дані та розміри кеш-пам’яті"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"змінювати налаштування системи"</string>
@@ -497,10 +474,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Цей додаток може записувати звук за допомогою мікрофона, коли ви використовуєте його."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"записувати звук у фоновому режимі"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Цей додаток може будь-коли записувати звук за допомогою мікрофона."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"виявляти знімки екрана вікон додатка"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Цей додаток отримуватиме сповіщення, коли під час його роботи створюватимуться знімки екрана."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"надсилати команди на SIM-карту"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Дозволяє програмі надсилати команди на SIM-карту. Це дуже небезпечно."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"розпізнавати фізичну активність"</string>
@@ -1219,8 +1194,8 @@
     <string name="no" msgid="5122037903299899715">"Скасувати"</string>
     <string name="dialog_alert_title" msgid="651856561974090712">"Увага"</string>
     <string name="loading" msgid="3138021523725055037">"Завантаження..."</string>
-    <string name="capital_on" msgid="2770685323900821829">"УВІМК"</string>
-    <string name="capital_off" msgid="7443704171014626777">"ВИМК"</string>
+    <string name="capital_on" msgid="2770685323900821829">"УВІМКНЕНО"</string>
+    <string name="capital_off" msgid="7443704171014626777">"ВИМКНЕНО"</string>
     <string name="checked" msgid="9179896827054513119">"вибрано"</string>
     <string name="not_checked" msgid="7972320087569023342">"не вибрано"</string>
     <string name="selected" msgid="6614607926197755875">"вибрано"</string>
@@ -2344,8 +2319,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Не вдається отримати доступ до камери телефона з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Не вдається отримати доступ до камери планшета з пристрою <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Цей контент недоступний під час потокового передавання. Спробуйте натомість скористатися телефоном."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ви не можете переглядати картинку в картинці під час трансляції"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Налаштування системи за умовчанням"</string>
     <string name="default_card_name" msgid="9198284935962911468">"КАРТКА <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 69bf5e3..9d15d64 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"صوتی میل"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"‏کنکشن مسئلہ یا غلط MMI کوڈ۔"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"خصوصیت تعاون یافتہ نہیں ہے۔"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"آپریشن صرف متعین ڈائلنگ نمبرز تک محدود ہے۔"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"جب آپ رومنگ پر ہوں تو اپنے فون سے کال فارورڈنگ کی ترتیبات تبدیل نہیں کی جا سکتیں۔"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"سروس فعال کی گئی۔"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"ایپ کو خود اپنے ہی حصوں کو میموری میں استقلال پذیر بنانے کی اجازت دیتا ہے۔ یہ فون کو سست بناکر دوسری ایپس کیلئے دستیاب میموری کو محدود کرسکتا ہے۔"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"پیش منظر سروس چلائیں"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"ایپ کو پیش منظر سروسز کے استعمال کی اجازت دیتا ہے۔"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"\"کیمرا\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"ایپ کو \"کیمرا\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"‏\"connectedDevice\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"‏ایپ کو \"connectedDevice\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"‏\"dataSync\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"‏ایپ کو \"dataSync\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"\"مقام\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"ایپ کو \"مقام\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"‏\"mediaPlayback\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"‏ایپ کو \"mediaPlayback\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"‏\"mediaProjection\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"‏ایپ کو \"mediaProjection\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"\"مائیکروفون\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"ایپ کو \"مائیکروفون\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"‏\"phoneCall\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"‏ایپ کو \"phoneCall\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"\"صحت\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"ایپ کو \"صحت\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"‏\"remoteMessaging\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"‏ایپ کو \"remoteMessaging\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"‏\"systemExempted\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"‏ایپ کو \"systemExempted\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"‏\"specialUse\" کی قسم کے ساتھ پیش منظر کی سروس چلائیں"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"‏ایپ کو \"specialUse\" کی قسم کے ساتھ پیش منظر کی سروسز کے استعمال کی اجازت دیتی ہے"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ایپ اسٹوریج کی جگہ کی پیمائش کریں"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"ایپ کو اپنے کوڈ، ڈیٹا اور کیش کے سائزوں کی بازیافت کرنے دیتا ہے"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"سسٹم کی ترتیبات میں ترمیم کریں"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"ایپ کے استعمال ہونے کے دوران یہ ایپ مائیکروفون استعمال کرتے ہوئے آڈیو ریکارڈ کر سکتی ہے۔"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"پس منظر میں آڈیو ریکارڈ کریں"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"یہ ایپ کسی بھی وقت مائیکروفون استعمال کرتے ہوئے آڈیو ریکارڈ کر سکتی ہے۔"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"ایپ کی ونڈوز کے اسکرین کیپچرز کا پتہ لگائیں"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"اس ایپ کے استعمال کے دوران اسکرین شاٹ لینے پر اس ایپ کو مطلع کیا جائے گا۔"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"‏SIM کو ہدایات بھیجیں"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"‏ایپ کو SIM کو کمانڈز بھیجنے کی اجازت دیتا ہے۔ یہ بہت خطرناک ہے۔"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"جسمانی سرگرمی کی شناخت کریں"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے فون کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"آپ کے <xliff:g id="DEVICE">%1$s</xliff:g> سے ٹیبلیٹ کے کیمرا تک رسائی حاصل نہیں کی جا سکتی"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"سلسلہ بندی کے دوران اس تک رسائی حاصل نہیں کی جا سکتی۔ اس کے بجائے اپنے فون پر کوشش کریں۔"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"سلسلہ بندی کے دوران تصویر میں تصویر نہیں دیکھ سکتے"</string>
     <string name="system_locale_title" msgid="711882686834677268">"سسٹم ڈیفالٹ"</string>
     <string name="default_card_name" msgid="9198284935962911468">"کارڈ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index c5e6f57..f987eae 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Ovozli pochta"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Tarmoqda xato yoki MMI kod noto‘g‘ri."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Ishlamaydigan funksiya."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Bu amal faqat ruxsat etilgan raqamlar uchun mavjud."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Rouming vaqtida telefondagi chaqiruvni boshqa raqamga uzatish sozlamalarini o‘zgartirib bo‘lmadi."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Xizmat yoqildi."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Ilovaga o‘zining komponentlarini xotirada doimiy saqlashga ruxsat beradi. Bu mavjud xotirani cheklashi va telefonni sekin ishlashiga sabab bo‘lishi mumkin."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"faol xizmatlarni ishga tushirish"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Ilovaga faol xizmatlardan foydalanishga ruxsat beradi."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"“camera” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Ilovaga “camera” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"“connectedDevice” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Ilovaga “connectedDevice” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"“dataSync” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Ilovaga “dataSync” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"“location” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Ilovaga “location” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"“mediaPlayback” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Ilovaga “mediaPlayback” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"“mediaProjection” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Ilovaga “mediaProjection” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"“microphone” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Ilovaga “microphone” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"“phoneCall” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Ilovaga “phoneCall” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"“health” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Ilovaga “health” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"“remoteMessaging” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Ilovaga “remoteMessaging” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"“systemExempted” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Ilovaga “systemExempted” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"“specialUse” turidagi faol xizmatni ishga tushirish"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Ilovaga “specialUse” turidagi faol xizmatlardan foydalanishga ruxsat beradi"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"ilovalar egallagan xotira joyini hisoblash"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Ilova o‘zining kodi, ma’lumotlari va kesh o‘lchami to‘g‘risidagi ma’lumotlarni olishi mumkin"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"tizim sozlamalarini o‘zgartirish"</string>
@@ -2340,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan telefonning kamerasiga kirish imkonsiz"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"<xliff:g id="DEVICE">%1$s</xliff:g> qurilmasidan planshetning kamerasiga kirish imkonsiz"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Bu kontent striming vaqtida ochilmaydi. Telefon orqali urininb koʻring."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Striming vaqtida tasvir ustida tasvir rejimida koʻrib boʻlmaydi"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Tizim standarti"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM KARTA <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ed0e98a..af1ae05 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Thư thoại"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Sự cố kết nối hoặc mã MMI không hợp lệ."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Tính năng không được hỗ trợ."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Chỉ hạn chế thao tác đối với số quay số định sẵn."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Không thể thay đổi cài đặt chuyển tiếp cuộc gọi từ điện thoại của bạn khi bạn đang chuyển vùng."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Dịch vụ đã được bật."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Cho phép ứng dụng tạo sự đồng nhất cho các phần của mình trong bộ nhớ. Việc này có thể hạn chế bộ nhớ đối với các ứng dụng khác đang làm chậm điện thoại."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"chạy dịch vụ trên nền trước"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Cho phép ứng dụng sử dụng các dịch vụ trên nền trước."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"chạy dịch vụ trên nền trước thuộc loại \"camera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"camera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"chạy dịch vụ trên nền trước thuộc loại \"connectedDevice\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"chạy dịch vụ trên nền trước thuộc loại \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"chạy dịch vụ trên nền trước thuộc loại \"location\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"location\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"chạy dịch vụ trên nền trước thuộc loại \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"chạy dịch vụ trên nền trước thuộc loại \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"chạy dịch vụ trên nền trước thuộc loại \"microphone\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"microphone\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"chạy dịch vụ trên nền trước thuộc loại \"phoneCall\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"chạy dịch vụ trên nền trước thuộc loại \"health\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"health\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"chạy dịch vụ trên nền trước thuộc loại \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"chạy dịch vụ trên nền trước thuộc loại \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"chạy dịch vụ trên nền trước thuộc loại \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Cho phép ứng dụng dùng các dịch vụ trên nền trước thuộc loại \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"đo dung lượng lưu trữ ứng dụng"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Cho phép ứng dụng truy xuất mã, dữ liệu và kích thước bộ nhớ đệm của chính ứng dụng"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"sửa đổi các chế độ cài đặt hệ thống"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Ứng dụng này có thể ghi âm bằng micrô khi bạn đang dùng ứng dụng."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"ghi âm trong nền"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Ứng dụng này có thể ghi âm bằng micrô bất kỳ lúc nào."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"phát hiện ảnh chụp màn hình các cửa sổ ứng dụng"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Ứng dụng này sẽ nhận được thông báo nếu người dùng chụp màn hình trong khi đang dùng ứng dụng."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"gửi lệnh đến SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Cho phép ứng dụng gửi lệnh đến SIM. Việc này rất nguy hiểm."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"nhận dạng hoạt động thể chất"</string>
@@ -1262,7 +1237,7 @@
     <string name="aerr_application_repeated" msgid="7804378743218496566">"<xliff:g id="APPLICATION">%1$s</xliff:g> tiếp tục dừng"</string>
     <string name="aerr_process_repeated" msgid="1153152413537954974">"<xliff:g id="PROCESS">%1$s</xliff:g> tiếp tục dừng"</string>
     <string name="aerr_restart" msgid="2789618625210505419">"Mở lại ứng dụng"</string>
-    <string name="aerr_report" msgid="3095644466849299308">"Gửi phản hồi"</string>
+    <string name="aerr_report" msgid="3095644466849299308">"Gửi ý kiến phản hồi"</string>
     <string name="aerr_close" msgid="3398336821267021852">"Đóng"</string>
     <string name="aerr_mute" msgid="2304972923480211376">"Tắt tiếng cho đến khi thiết bị khởi động lại"</string>
     <string name="aerr_wait" msgid="3198677780474548217">"Đợi"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Không truy cập được vào máy ảnh trên điện thoại từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Không truy cập được vào máy ảnh trên máy tính bảng từ <xliff:g id="DEVICE">%1$s</xliff:g> của bạn"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Bạn không thể truy cập vào nội dung này trong khi phát trực tuyến. Hãy thử trên điện thoại."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Không thể xem video ở chế độ hình trong hình khi đang truyền trực tuyến"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Theo chế độ mặc định của hệ thống"</string>
     <string name="default_card_name" msgid="9198284935962911468">"THẺ <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-watch/dimens_material.xml b/core/res/res/values-watch/dimens_material.xml
index 82c088b..51d4018 100644
--- a/core/res/res/values-watch/dimens_material.xml
+++ b/core/res/res/values-watch/dimens_material.xml
@@ -45,6 +45,13 @@
     <dimen name="progress_bar_size_medium">32dip</dimen>
     <dimen name="progress_bar_size_large">64dip</dimen>
 
+    <!-- Progress bar message dimens -->
+    <dimen name="message_progress_dialog_text_size">18sp</dimen>
+    <dimen name="message_progress_dialog_bottom_padding">80px</dimen>
+    <dimen name="message_progress_dialog_top_padding">0dp</dimen>
+    <dimen name="message_progress_dialog_start_padding">0dp</dimen>
+    <dimen name="message_progress_dialog_end_padding">0dp</dimen>
+
     <!-- fallback for screen percentage widths -->
     <dimen name="screen_percentage_05">0dp</dimen>
     <dimen name="screen_percentage_10">0dp</dimen>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
index 5093aa8..f34d9f9 100644
--- a/core/res/res/values-watch/styles_material.xml
+++ b/core/res/res/values-watch/styles_material.xml
@@ -97,4 +97,14 @@
         <item name="gravity">center_horizontal|top</item>
         <item name="ellipsize">end</item>
     </style>
+
+    <style name="ProgressDialogMessage">
+        <item name="android:textAlignment">center</item>
+        <item name="textAppearance">@android:style/TextAppearance.DeviceDefault.Medium</item>
+        <item name="textSize">@dimen/message_progress_dialog_text_size</item>
+        <item name="paddingBottom">@dimen/message_progress_dialog_bottom_padding</item>
+        <item name="paddingEnd">@dimen/message_progress_dialog_end_padding</item>
+        <item name="paddingStart">@dimen/message_progress_dialog_start_padding</item>
+        <item name="paddingTop">@dimen/message_progress_dialog_top_padding</item>
+    </style>
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f73900c..73f5b034 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"语音信箱"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"出现连接问题或 MMI 码无效。"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"不支持此功能。"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"只能对固定拨号号码执行此类操作。"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"漫游时无法通过您的手机来更改来电转接设置。"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"已启用服务。"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"允许该应用在内存中持续保留其自身的某些组件。这会限制其他应用可用的内存,从而减缓手机运行速度。"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"运行前台服务"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"允许该应用使用前台服务。"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"运行“camera”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"允许该应用使用“camera”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"运行“connectedDevice”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"允许该应用使用“connectedDevice”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"运行“dataSync”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"允许该应用使用“dataSync”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"运行“location”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"允许该应用使用“location”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"运行“mediaPlayback”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"允许该应用使用“mediaPlayback”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"运行“mediaProjection”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"允许该应用使用“mediaProjection”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"运行“microphone”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"允许该应用使用“microphone”类型的前台服务"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"运行“phoneCall”类型的前台服务"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"允许该应用使用“phoneCall”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"运行“health”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"允许该应用使用“health”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"运行“remoteMessaging”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"允许该应用使用“remoteMessaging”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"运行“systemExempted”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允许该应用使用“systemExempted”类型的前台服务"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"运行“specialUse”类型的前台服务"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允许该应用使用“specialUse”类型的前台服务"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"计算应用存储空间"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"允许应用检索其代码、数据和缓存大小"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"修改系统设置"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"当您使用此应用时,它可以使用麦克风录音。"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在后台录音"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"此应用可以随时使用麦克风录音。"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"检测应用窗口的屏幕截图"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"在应用使用过程中截取屏幕截图时,此应用将收到通知。"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"向 SIM 卡发送命令"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"允许应用向SIM卡发送命令(此权限具有很高的危险性)。"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"识别身体活动"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问手机的摄像头"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"无法从<xliff:g id="DEVICE">%1$s</xliff:g>上访问平板电脑的摄像头"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"流式传输时无法访问此内容。您可以尝试在手机上访问。"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"在线播放时无法查看画中画"</string>
     <string name="system_locale_title" msgid="711882686834677268">"系统默认设置"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 072ce46..4993c89 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"留言信箱"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"連線發生問題或 MMI 碼無效。"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"不支援的功能。"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"僅限對固定撥號號碼執行這項運作。"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"使用漫遊服務時,不可從手機變更來電轉駁設定。"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"服務已啟用。"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"允許應用程式設定本身的某些部分持續佔用記憶體。這樣可能會限制其他應用程式可用的記憶體,並拖慢手機的運作速度。"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"執行前景服務"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"允許應用程式使用前景服務。"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"配搭「camera」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"允許應用程式配搭「camera」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"配搭「connectedDevice」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"允許應用程式配搭「connectedDevice」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"配搭「dataSync」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"允許應用程式配搭「dataSync」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"配搭「location」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"允許應用程式配搭「location」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"配搭「mediaPlayback」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"允許應用程式配搭「mediaPlayback」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"配搭「mediaProjection」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"允許應用程式配搭「mediaProjection」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"配搭「microphone」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"允許應用程式配搭「microphone」類型使用前景服務"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"配搭「phoneCall」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"允許應用程式配搭「phoneCall」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"配搭「health」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"允許應用程式配搭「health」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"配搭「remoteMessaging」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"允許應用程式配搭「remoteMessaging」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"配搭「systemExempted」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允許應用程式配搭「systemExempted」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"配搭「specialUse」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允許應用程式配搭「specialUse」類型使用前景服務"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"測量應用程式儲存空間"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"允許應用程式擷取本身的程式碼、資料和快取大小"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"修改系統設定"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"此應用程式在使用期間可使用麥克風錄音。"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在背景錄音"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"此應用程式可隨時使用麥克風錄音。"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"偵測應用程式視窗是否擷取螢幕畫面"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"如有人在應用程式使用期間擷取螢幕截圖,此應用程式將會收到通知"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"發送指令至 SIM 卡"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這項操作具有高危險性。"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"識別體能活動"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法使用,請改用手機。"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流期間無法查看畫中畫"</string>
     <string name="system_locale_title" msgid="711882686834677268">"系統預設"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index f1b0f23..7dde343 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"語音留言"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"連線發生問題或錯誤的 MMI 碼。"</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"不支援的功能。"</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"僅限對固定撥號號碼執行此作業。"</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"漫遊時無法透過你的手機變更來電轉接設定。"</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"服務已啟用。"</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"允許應用程式讓部分內容佔用記憶體,持續執行。這項設定可能會限制其他應用程式可用的記憶體,並拖慢手機運作速度。"</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"執行前景服務"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"允許應用程式使用前景服務。"</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"搭配「camera」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"允許應用程式搭配「camera」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"搭配「connectedDevice」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"允許應用程式搭配「connectedDevice」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"搭配「dataSync」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"允許應用程式搭配「dataSync」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"搭配「location」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"允許應用程式搭配「location」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"搭配「mediaPlayback」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"允許應用程式搭配「mediaPlayback」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"搭配「mediaProjection」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"允許應用程式搭配「mediaProjection」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"搭配「microphone」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"允許應用程式搭配「microphone」類型使用前景服務"</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"搭配「phoneCall」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"允許應用程式搭配「phoneCall」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"搭配「health」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"允許應用程式搭配「health」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"搭配「remoteMessaging」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"允許應用程式搭配「remoteMessaging」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"搭配「systemExempted」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"允許應用程式搭配「systemExempted」類型使用前景服務"</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"搭配「specialUse」類型執行前景服務"</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"允許應用程式搭配「specialUse」類型使用前景服務"</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"測量應用程式儲存空間"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"允許應用程式擷取本身的程式碼、資料及快取大小"</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"修改系統設定"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"這個應用程式在使用期間可以使用麥克風錄音。"</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"在背景錄音"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"這個應用程式隨時可以使用麥克風錄音。"</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"偵測應用程式視窗是否擷取螢幕畫面"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"如果在使用應用程式過程中拍攝了螢幕截圖,這個應用程式將會收到通知。"</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"傳送指令到 SIM 卡"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"允許應用程式傳送指令到 SIM 卡。這麼做非常危險。"</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"辨識體能活動"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取手機的相機"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"無法從 <xliff:g id="DEVICE">%1$s</xliff:g> 存取平板電腦的相機"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"串流播放時無法存取這項內容,請改用手機。"</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"串流播放時無法查看子母畫面"</string>
     <string name="system_locale_title" msgid="711882686834677268">"系統預設"</string>
     <string name="default_card_name" msgid="9198284935962911468">"SIM 卡 <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c0a2874..86f869d 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -28,6 +28,7 @@
     <string name="defaultVoiceMailAlphaTag" msgid="2190754495304236490">"Ivoyisimeyili"</string>
     <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string>
     <string name="mmiError" msgid="2862759606579822246">"Inkinga yoxhumano noma ikhadi ye-MMI engalungile."</string>
+    <string name="mmiErrorNotSupported" msgid="5001803469335286099">"Isakhi asisekelwa."</string>
     <string name="mmiFdnError" msgid="3975490266767565852">"Umsebenzi uvinjelwe ekudayeleni izinombolo ezingaguquki kuphela."</string>
     <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"Ayikwazi ukushintsha izilungiselelo zokudluliselwa kwekholi kusuka efonini yakho ngenkathi uzula."</string>
     <string name="serviceEnabled" msgid="7549025003394765639">"Isevisi ivaliwe."</string>
@@ -395,54 +396,30 @@
     <string name="permdesc_persistentActivity" product="default" msgid="1914841924366562051">"Ivumela uhlelo kusebenza ukwenza izingxenye yazo ezicindezelayo kumemori. Lokhu kungakhawulela imemori ekhona kwezinye izinhlelo zokusebenza ukwenza ukuthi ifoni ingasheshi."</string>
     <string name="permlab_foregroundService" msgid="1768855976818467491">"qalisa amasevisi waphambili"</string>
     <string name="permdesc_foregroundService" msgid="8720071450020922795">"Vumela uhlelo lokusebenza ukusebenzisa amasevisi wangaphambili."</string>
-    <!-- no translation found for permlab_foregroundServiceCamera (7814751737955715297) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceCamera (6973701931250595727) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceConnectedDevice (3019650546176872501) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceConnectedDevice (1067457315741352963) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceDataSync (5847463514326881076) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceDataSync (2267140263423973050) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceLocation (3745428302378535690) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceLocation (118894034365177183) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaPlayback (4002687983891935514) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaPlayback (3638032446063968043) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMediaProjection (2630868915733312527) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMediaProjection (4805677128082002298) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceMicrophone (7390033424890545399) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceMicrophone (1206041516173483201) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServicePhoneCall (627937743867697892) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServicePhoneCall (5941660252587015147) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceHealth (3675776442080928184) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceHealth (2024586220562667185) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceRemoteMessaging (105670277002780950) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceRemoteMessaging (8767598075877576277) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSystemExempted (1597663713590612685) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSystemExempted (947381760834649622) -->
-    <skip />
-    <!-- no translation found for permlab_foregroundServiceSpecialUse (7973536745876645082) -->
-    <skip />
-    <!-- no translation found for permdesc_foregroundServiceSpecialUse (646713654541885919) -->
-    <skip />
+    <string name="permlab_foregroundServiceCamera" msgid="7814751737955715297">"qalisa isevisi ephambili ngohlobo lokuthi \"ikhamera\""</string>
+    <string name="permdesc_foregroundServiceCamera" msgid="6973701931250595727">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"ikhamera\""</string>
+    <string name="permlab_foregroundServiceConnectedDevice" msgid="3019650546176872501">"qalisa isevisi ephambili ngohlobo lokuthi \"Idivayisi exhunyiwe\""</string>
+    <string name="permdesc_foregroundServiceConnectedDevice" msgid="1067457315741352963">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"connectedDevice\""</string>
+    <string name="permlab_foregroundServiceDataSync" msgid="5847463514326881076">"qalisa isevisi ephambili ngohlobo lokuthi \"dataSync\""</string>
+    <string name="permdesc_foregroundServiceDataSync" msgid="2267140263423973050">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"dataSync\""</string>
+    <string name="permlab_foregroundServiceLocation" msgid="3745428302378535690">"qalisa isevisi ephambili ngohlobo lokuthi \"indawo\""</string>
+    <string name="permdesc_foregroundServiceLocation" msgid="118894034365177183">"Vumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"indawo\""</string>
+    <string name="permlab_foregroundServiceMediaPlayback" msgid="4002687983891935514">"qalisa isevisi ephambili ngohlobo lokuthi \"mediaPlayback\""</string>
+    <string name="permdesc_foregroundServiceMediaPlayback" msgid="3638032446063968043">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"mediaPlayback\""</string>
+    <string name="permlab_foregroundServiceMediaProjection" msgid="2630868915733312527">"qalisa isevisi ephambili ngohlobo lokuthi \"mediaProjection\""</string>
+    <string name="permdesc_foregroundServiceMediaProjection" msgid="4805677128082002298">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"mediaProjection\""</string>
+    <string name="permlab_foregroundServiceMicrophone" msgid="7390033424890545399">"qalisa isevisi ephambili ngohlobo lokuthi \"imakrofoni\""</string>
+    <string name="permdesc_foregroundServiceMicrophone" msgid="1206041516173483201">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"imakrofoni\""</string>
+    <string name="permlab_foregroundServicePhoneCall" msgid="627937743867697892">"qalisa isevisi ephambili ngohlobo lokuthi \"Ikholi yefoni\""</string>
+    <string name="permdesc_foregroundServicePhoneCall" msgid="5941660252587015147">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"phoneCall\""</string>
+    <string name="permlab_foregroundServiceHealth" msgid="3675776442080928184">"qalisa isevisi ephambili ngohlobo lokuthi \"impilo\""</string>
+    <string name="permdesc_foregroundServiceHealth" msgid="2024586220562667185">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"impilo\""</string>
+    <string name="permlab_foregroundServiceRemoteMessaging" msgid="105670277002780950">"qalisa isevisi ephambili ngohlobo lokuthi \"remoteMessaging\""</string>
+    <string name="permdesc_foregroundServiceRemoteMessaging" msgid="8767598075877576277">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"remoteMessaging\""</string>
+    <string name="permlab_foregroundServiceSystemExempted" msgid="1597663713590612685">"qalisa isevisi ephambili ngohlobo lokuthi \"systemExempted\""</string>
+    <string name="permdesc_foregroundServiceSystemExempted" msgid="947381760834649622">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"systemExempted\""</string>
+    <string name="permlab_foregroundServiceSpecialUse" msgid="7973536745876645082">"qalisa isevisi ephambili ngohlobo lokuthi \"specialUse\""</string>
+    <string name="permdesc_foregroundServiceSpecialUse" msgid="646713654541885919">"Kuvumela i-app ukusebenzisa amasevisi aphambili ngohlobo lokuthi \"specialUse\""</string>
     <string name="permlab_getPackageSize" msgid="375391550792886641">"linganisa isikhala sokugcina uhlelo lokusebenza"</string>
     <string name="permdesc_getPackageSize" msgid="742743530909966782">"Ivuela uhlelo lokusebenza ukuthi ithole kabusha ikhodi yayo, i-dat kanye nosayizi abagcinwe okwesikhashana."</string>
     <string name="permlab_writeSettings" msgid="8057285063719277394">"shintsha amasethingi esistimu"</string>
@@ -495,10 +472,8 @@
     <string name="permdesc_recordAudio" msgid="5857246765327514062">"Lolu hlelo lokusebenza lungarekhoda umsindo lisebenzisa imakrofoni kuyilapho uhlelo lokusebenza lusetshenziswa."</string>
     <string name="permlab_recordBackgroundAudio" msgid="5891032812308878254">"rekhoda umsindo ngemuva"</string>
     <string name="permdesc_recordBackgroundAudio" msgid="1992623135737407516">"Lolu hlelo lokusebenza lungafunda umsindo lisebenzisa imakrofoni noma kunini."</string>
-    <!-- no translation found for permlab_detectScreenCapture (4447042362828799433) -->
-    <skip />
-    <!-- no translation found for permdesc_detectScreenCapture (3485784917960342284) -->
-    <skip />
+    <string name="permlab_detectScreenCapture" msgid="4447042362828799433">"thola izithombe zesikrini zamawindi e-app"</string>
+    <string name="permdesc_detectScreenCapture" msgid="3485784917960342284">"Loe-app izokwaziswa uma isithombe-skrini sithathwa ngenkathi i-app isetshenziswa."</string>
     <string name="permlab_sim_communication" msgid="176788115994050692">"thumela imilayezo ku-SIM"</string>
     <string name="permdesc_sim_communication" msgid="4179799296415957960">"Ivumela uhlelo lokusebenza ukuthumela imiyalo ku-SIM. Lokhu kuyingozi kakhulu."</string>
     <string name="permlab_activityRecognition" msgid="1782303296053990884">"bona umsebenzi"</string>
@@ -2342,8 +2317,7 @@
     <string name="vdm_camera_access_denied" product="default" msgid="6102378580971542473">"Ayikwazi ukufinyelela ikhamera yefoni kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string>
     <string name="vdm_camera_access_denied" product="tablet" msgid="6895968310395249076">"Ayikwazi ukufinyelela ikhamera yethebulethi kusuka ku-<xliff:g id="DEVICE">%1$s</xliff:g> yakho"</string>
     <string name="vdm_secure_window" msgid="161700398158812314">"Lokhu akukwazi ukufinyelelwa ngenkathi usakaza. Zama efonini yakho kunalokho."</string>
-    <!-- no translation found for vdm_pip_blocked (4036107522497281397) -->
-    <skip />
+    <string name="vdm_pip_blocked" msgid="4036107522497281397">"Ayikwazi ukubuka isithombe esiphakathi kwesithombe ngenkathi isakaza"</string>
     <string name="system_locale_title" msgid="711882686834677268">"Okuzenzakalelayo kwesistimu"</string>
     <string name="default_card_name" msgid="9198284935962911468">"IKHADI <xliff:g id="CARDNUMBER">%d</xliff:g>"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 2d832bc..7946493 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8955,6 +8955,9 @@
         <!-- Flag indicating whether a recognition service can be selected as default. The default
              value of this flag is true. -->
         <attr name="selectableAsDefault" format="boolean" />
+        <!-- The maximal number of recognition sessions ongoing at the same time.
+             The default value is 1, meaning no concurrency. -->
+        <attr name="maxConcurrentSessionsCount" format="integer" />
     </declare-styleable>
 
     <!-- Use <code>voice-interaction-service</code> as the root tag of the XML resource that
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index a5c0827..c8a65a7 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1594,7 +1594,7 @@
             {@link android.app.Service#startForeground(int, android.app.Notification, int)} with
             this type on devices running {@link android.os.Build.VERSION_CODES#UPSIDE_DOWN_CAKE}
             is still allowed, but calling it with this type on devices running future platform
-            releases may get a {@link android.app.ForegroundServiceTypeNotAllowedException}.
+            releases may get a {@link android.app.InvalidForegroundServiceTypeException}.
         -->
         <flag name="dataSync" value="0x01" />
         <!-- Music, video, news or other media play.
@@ -1705,11 +1705,17 @@
         -->
         <flag name="systemExempted" value="0x400" />
         <!-- "Short service" foreground service type. See
-           TODO: Change it to a real link
-           {@code android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+           {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
            for more details.
         -->
         <flag name="shortService" value="0x800" />
+        <!-- The file management use case which manages files/directories, often involving file I/O
+            across the file system.
+            <p>Requires the app to hold the permission
+            {@link android.Manifest.permission#FOREGROUND_SERVICE_FILE_MANAGEMENT} in order to use
+            this type.
+        -->
+        <flag name="fileManagement" value="0x1000" />
         <!-- Use cases that can't be categorized into any other foreground service types, but also
             can't use @link android.app.job.JobInfo.Builder} APIs.
             See {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SPECIAL_USE} for the
@@ -3166,20 +3172,20 @@
         <attr name="canDisplayOnRemoteDevices" format="boolean"/>
         <attr name="allowUntrustedActivityEmbedding" />
         <attr name="knownActivityEmbeddingCerts" />
-        <!-- Specifies the category of the target display the activity is expected to run on. Upon
-             creation, a virtual display can specify which display categories it supports and one of
-             the category must be present in the activity's manifest to allow this activity to run.
-             The default value is {@code null}, which indicates the activity does not belong to a
-             restricted display category and thus can only run on a display that didn't specify any
-             display categories. Each activity can only specify one category it targets to but a
-             virtual display can accommodate multiple restricted categories.
+        <!-- Specifies the required display category of the activity. Upon creation, a display can
+             specify which display categories it supports and one of the categories must be present
+             in the {@code <activity>} element to allow this activity to run. The default value is
+             {@code null}, which indicates the activity does not have a required display category
+             and thus can only run on a display that didn't specify any display categories. Each
+             activity can only specify one required category but a display can accommodate multiple
+             display categories.
 
              <p> This field should be formatted as a Java-language-style free form string(for
              example, com.google.automotive_entertainment), which may contain uppercase or lowercase
              letters ('A' through 'Z'), numbers, and underscores ('_') but may only start with
              letters.
          -->
-        <attr name="targetDisplayCategory" format="string"/>
+        <attr name="requiredDisplayCategory" format="string"/>
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b92d96f..9a585a1 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1828,6 +1828,14 @@
          config_enableFusedLocationOverlay is false. -->
     <string name="config_fusedLocationProviderPackageName" translatable="false">com.android.location.fused</string>
 
+    <!-- If true will use the GNSS hardware implementation to service the GPS_PROVIDER. If false
+         will allow the GPS_PROVIDER to be replaced by an app at run-time (restricted to the package
+         specified by config_gnssLocationProviderPackageName). -->
+    <bool name="config_useGnssHardwareProvider" translatable="false">true</bool>
+    <!-- Package name providing GNSS location support. Used only when
+         config_useGnssHardwareProvider is false. -->
+    <string name="config_gnssLocationProviderPackageName" translatable="false">@null</string>
+
     <!-- Default value for the ADAS GNSS Location Enabled setting if this setting has never been
          set before. -->
     <bool name="config_defaultAdasGnssLocationEnabled" translatable="false">false</bool>
@@ -2070,6 +2078,13 @@
     <!-- Flag indicating whether the current device supports "Ask every time" for sms-->
     <bool name="config_sms_ask_every_time_support">true</bool>
 
+    <!-- Flag indicating whether the current device allows acknowledgement of SIM operation like
+         SM-PP or saving SMS to SIM can be done via the IMS interfaces.
+         If true,this means that the device supports sending of sim operation response via the
+         IMS interface APIs. This can be overridden to false for devices which can't send
+         sim operation acknowledgements via IMS interface APIs. -->
+    <bool name="config_smppsim_response_via_ims">false</bool>
+
     <!-- Flag indicating whether the current device allows data.
          If true, this means that the device supports data connectivity through
          the telephony network.
@@ -5354,6 +5369,12 @@
     <bool name="config_cecRoutingControlDisabled_allowed">true</bool>
     <bool name="config_cecRoutingControlDisabled_default">true</bool>
 
+    <bool name="config_cecSoundbarMode_userConfigurable">true</bool>
+    <bool name="config_cecSoundbarModeEnabled_allowed">true</bool>
+    <bool name="config_cecSoundbarModeEnabled_default">false</bool>
+    <bool name="config_cecSoundbarModeDisabled_allowed">true</bool>
+    <bool name="config_cecSoundbarModeDisabled_default">true</bool>
+
     <bool name="config_cecPowerControlMode_userConfigurable">true</bool>
     <bool name="config_cecPowerControlModeTv_allowed">true</bool>
     <bool name="config_cecPowerControlModeTv_default">false</bool>
@@ -5539,6 +5560,13 @@
     <bool name="config_cecQuerySadMaxDisabled_allowed">true</bool>
     <bool name="config_cecQuerySadMaxDisabled_default">false</bool>
 
+    <!-- eARC Configuration -->
+    <bool name="config_earcEnabled_userConfigurable">true</bool>
+    <bool name="config_earcFeatureEnabled_allowed">true</bool>
+    <bool name="config_earcFeatureEnabled_default">true</bool>
+    <bool name="config_earcFeatureDisabled_allowed">true</bool>
+    <bool name="config_earcFeatureDisabled_default">false</bool>
+
     <!-- Whether app hibernation deletes OAT artifact files as part of global hibernation. -->
     <bool name="config_hibernationDeletesOatArtifactsEnabled">true</bool>
 
@@ -5964,4 +5992,35 @@
     <string-array translatable="false" name="config_fontManagerServiceCerts">
     </string-array>
 
+    <!-- A string config in svg path format for the main display shape.
+         (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+         This config must be set unless:
+         1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+            and the system will auto-generate a circular shape.
+         2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+         (@see DisplayShape#createDefaultDisplayShape)
+
+         Note: If the display supports multiple resolutions, please define the path config based on
+         the highest resolution so that it can be scaled correctly in each resolution. -->
+    <string name="config_mainDisplayShape" translatable="false"></string>
+
+    <!-- A string config in svg path format for the secondary display shape.
+         (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+         This config must be set unless:
+         1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+            and the system will auto-generate a circular shape.
+         2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+         (@see DisplayShape#createDefaultDisplayShape)
+
+         Note: If the display supports multiple resolutions, please define the path config based on
+         the highest resolution so that it can be scaled correctly in each resolution. -->
+    <string name="config_secondaryDisplayShape" translatable="false"></string>
+
+    <!-- The display shape config for each display in a multi-display device. -->
+    <string-array name="config_displayShapeArray" translatable="false">
+        <item>@string/config_mainDisplayShape</item>
+        <item>@string/config_secondaryDisplayShape</item>
+    </string-array>
 </resources>
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 61229cb..a9bec7a9 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -116,7 +116,8 @@
     <public name="handwritingBoundsOffsetBottom" />
     <public name="accessibilityDataPrivate" />
     <public name="enableTextStylingShortcuts" />
-    <public name="targetDisplayCategory"/>
+    <public name="requiredDisplayCategory"/>
+    <public name="maxConcurrentSessionsCount" />
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01cd0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d0372ea..6aea32f 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1201,6 +1201,11 @@
     <string name="permdesc_foregroundServiceSystemExempted">Allows the app to make use of foreground services with the type \"systemExempted\"</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permlab_foregroundServiceFileManagement">run foreground service with the type \"fileManagement\"</string>
+    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+    <string name="permdesc_foregroundServiceFileManagement">Allows the app to make use of foreground services with the type \"fileManagement\"</string>
+
+    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_foregroundServiceSpecialUse">run foreground service with the type \"specialUse\"</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_foregroundServiceSpecialUse">Allows the app to make use of foreground services with the type \"specialUse\"</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9d7e6f8..ace7e4c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -153,6 +153,7 @@
   <java-symbol type="id" name="progress_horizontal" />
   <java-symbol type="id" name="progress_number" />
   <java-symbol type="id" name="progress_percent" />
+  <java-symbol type="id" name="progress_dialog_message" />
   <java-symbol type="id" name="progressContainer" />
   <java-symbol type="id" name="rew" />
   <java-symbol type="id" name="rightSpacer" />
@@ -314,6 +315,7 @@
   <java-symbol type="bool" name="config_sms_ask_every_time_support" />
   <java-symbol type="bool" name="config_sms_capable" />
   <java-symbol type="bool" name="config_sms_utf8_support" />
+  <java-symbol type="bool" name="config_smppsim_response_via_ims" />
   <java-symbol type="bool" name="config_mobile_data_capable" />
   <java-symbol type="bool" name="config_suspendWhenScreenOffDueToProximity" />
   <java-symbol type="bool" name="config_swipeDisambiguation" />
@@ -1962,6 +1964,7 @@
   <java-symbol type="bool" name="config_enableActivityRecognitionHardwareOverlay" />
   <java-symbol type="bool" name="config_defaultAdasGnssLocationEnabled" />
   <java-symbol type="bool" name="config_enableFusedLocationOverlay" />
+  <java-symbol type="bool" name="config_useGnssHardwareProvider" />
   <java-symbol type="bool" name="config_enableGeocoderOverlay" />
   <java-symbol type="bool" name="config_enableGeofenceOverlay" />
   <java-symbol type="bool" name="config_enableNetworkLocationOverlay" />
@@ -2124,6 +2127,7 @@
   <java-symbol type="string" name="config_datause_iface" />
   <java-symbol type="string" name="config_activityRecognitionHardwarePackageName" />
   <java-symbol type="string" name="config_fusedLocationProviderPackageName" />
+  <java-symbol type="string" name="config_gnssLocationProviderPackageName" />
   <java-symbol type="string" name="config_geocoderProviderPackageName" />
   <java-symbol type="string" name="config_geofenceProviderPackageName" />
   <java-symbol type="string" name="config_networkLocationProviderPackageName" />
@@ -4555,6 +4559,12 @@
   <java-symbol type="bool" name="config_cecRoutingControlDisabled_allowed" />
   <java-symbol type="bool" name="config_cecRoutingControlDisabled_default" />
 
+  <java-symbol type="bool" name="config_cecSoundbarMode_userConfigurable" />
+  <java-symbol type="bool" name="config_cecSoundbarModeEnabled_allowed" />
+  <java-symbol type="bool" name="config_cecSoundbarModeEnabled_default" />
+  <java-symbol type="bool" name="config_cecSoundbarModeDisabled_allowed" />
+  <java-symbol type="bool" name="config_cecSoundbarModeDisabled_default" />
+
   <java-symbol type="bool" name="config_cecPowerControlMode_userConfigurable" />
   <java-symbol type="bool" name="config_cecPowerControlModeTv_allowed" />
   <java-symbol type="bool" name="config_cecPowerControlModeTv_default" />
@@ -4740,6 +4750,13 @@
   <java-symbol type="bool" name="config_cecQuerySadMaxDisabled_allowed" />
   <java-symbol type="bool" name="config_cecQuerySadMaxDisabled_default" />
 
+  <!-- eARC Configuration -->
+  <java-symbol type="bool" name="config_earcEnabled_userConfigurable" />
+  <java-symbol type="bool" name="config_earcFeatureEnabled_allowed" />
+  <java-symbol type="bool" name="config_earcFeatureEnabled_default" />
+  <java-symbol type="bool" name="config_earcFeatureDisabled_allowed" />
+  <java-symbol type="bool" name="config_earcFeatureDisabled_default" />
+
   <!-- Ids for RemoteViews -->
   <java-symbol type="id" name="remote_views_next_child" />
   <java-symbol type="id" name="remote_views_stable_id" />
@@ -4899,4 +4916,8 @@
   <java-symbol type="dimen" name="status_bar_height_default" />
 
   <java-symbol type="string" name="default_card_name"/>
+
+  <java-symbol type="string" name="config_mainDisplayShape"/>
+  <java-symbol type="string" name="config_secondaryDisplayShape"/>
+  <java-symbol type="array" name="config_displayShapeArray" />
 </resources>
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java
index 36aa915..1cc0a985 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImplTest.java
@@ -210,9 +210,9 @@
                 any(IServiceCallback.class)));
 
         doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
-                eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class)));
+                eq(FM_RADIO_MODULE_ID), anyString(), any(IBinder.class)));
         doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
-                eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class), any(Object.class)));
+                eq(DAB_RADIO_MODULE_ID), anyString(), any(IBinder.class)));
 
         when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock);
         when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
index 7a8475f..a034653 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/RadioModuleTest.java
@@ -58,14 +58,13 @@
     @Mock
     private android.hardware.broadcastradio.ICloseHandle mHalCloseHandleMock;
 
-    private final Object mLock = new Object();
     // RadioModule under test
     private RadioModule mRadioModule;
     private android.hardware.broadcastradio.IAnnouncementListener mHalListener;
 
     @Before
     public void setup() throws RemoteException {
-        mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES, mLock);
+        mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES);
 
         // TODO(b/241118988): test non-null image for getImage method
         when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(null);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
index 87d0ea4..993ca77 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/aidl/TunerSessionTest.java
@@ -83,7 +83,6 @@
     @Mock private IBroadcastRadio mBroadcastRadioMock;
     private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
 
-    private final Object mLock = new Object();
     // RadioModule under test
     private RadioModule mRadioModule;
 
@@ -104,7 +103,7 @@
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
-                AidlTestUtils.makeDefaultModuleProperties(), mLock);
+                AidlTestUtils.makeDefaultModuleProperties());
 
         doAnswer(invocation -> {
             mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java
index 0b7bbea..c9224bf 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/BroadcastRadioServiceHidlTest.java
@@ -59,8 +59,6 @@
             new ArrayList<>(Arrays.asList("FmService", "DabService"));
     private static final int[] TEST_ENABLED_TYPES = new int[]{Announcement.TYPE_TRAFFIC};
 
-    private final Object mLock = new Object();
-
     private BroadcastRadioService mBroadcastRadioService;
     private DeathRecipient mFmDeathRecipient;
 
@@ -200,7 +198,7 @@
 
         mockServiceManager();
         mBroadcastRadioService = new BroadcastRadioService(/* nextModuleId= */ FM_RADIO_MODULE_ID,
-                mLock, mServiceManagerMock);
+                mServiceManagerMock);
     }
 
     private void mockServiceManager() throws RemoteException {
@@ -221,9 +219,9 @@
                 }).thenReturn(true);
 
         doReturn(mFmRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
-                eq(FM_RADIO_MODULE_ID), anyString(), any(Object.class)));
+                eq(FM_RADIO_MODULE_ID), anyString()));
         doReturn(mDabRadioModuleMock).when(() -> RadioModule.tryLoadingModule(
-                eq(DAB_RADIO_MODULE_ID), anyString(), any(Object.class)));
+                eq(DAB_RADIO_MODULE_ID), anyString()));
 
         when(mFmRadioModuleMock.getProperties()).thenReturn(mFmModuleMock);
         when(mDabRadioModuleMock.getProperties()).thenReturn(mDabModuleMock);
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/RadioModuleHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/RadioModuleHidlTest.java
index 48f5a46..1f5e770 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/RadioModuleHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/RadioModuleHidlTest.java
@@ -62,13 +62,12 @@
     @Mock
     private android.hardware.broadcastradio.V2_0.ICloseHandle mHalCloseHandleMock;
 
-    private final Object mLock = new Object();
     private RadioModule mRadioModule;
     private android.hardware.broadcastradio.V2_0.IAnnouncementListener mHalListener;
 
     @Before
     public void setup() throws RemoteException {
-        mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES, mLock);
+        mRadioModule = new RadioModule(mBroadcastRadioMock, TEST_MODULE_PROPERTIES);
 
         when(mBroadcastRadioMock.getImage(anyInt())).thenReturn(new ArrayList<Byte>(0));
 
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
index e3c9faa..7d604d4 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/StartProgramListUpdatesFanoutTest.java
@@ -64,7 +64,6 @@
     @Mock ITunerSession mHalTunerSessionMock;
     private android.hardware.radio.ITunerCallback[] mAidlTunerCallbackMocks;
 
-    private final Object mLock = new Object();
     // RadioModule under test
     private RadioModule mRadioModule;
 
@@ -100,7 +99,7 @@
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
-                TestUtils.makeDefaultModuleProperties(), mLock);
+                TestUtils.makeDefaultModuleProperties());
 
         doAnswer((Answer) invocation -> {
             mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
diff --git a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
index b7da5d0..ff988a2 100644
--- a/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
+++ b/core/tests/BroadcastRadioTests/src/com/android/server/broadcastradio/hal2/TunerSessionHidlTest.java
@@ -84,7 +84,6 @@
             new RadioManager.FmBandConfig(FM_BAND_DESCRIPTOR);
     private static final int UNSUPPORTED_CONFIG_FLAG = 0;
 
-    private final Object mLock = new Object();
     private final ArrayMap<Integer, Boolean> mHalConfigMap = new ArrayMap<>();
     private RadioModule mRadioModule;
     private ITunerCallback mHalTunerCallback;
@@ -105,7 +104,7 @@
         doReturn(true).when(() -> RadioServiceUserController.isCurrentOrSystemUser());
 
         mRadioModule = new RadioModule(mBroadcastRadioMock,
-                TestUtils.makeDefaultModuleProperties(), mLock);
+                TestUtils.makeDefaultModuleProperties());
 
         doAnswer(invocation -> {
             mHalTunerCallback = (ITunerCallback) invocation.getArguments()[0];
diff --git a/core/tests/GameManagerTests/AndroidManifest.xml b/core/tests/GameManagerTests/AndroidManifest.xml
index 6a01abe..f1ab696 100644
--- a/core/tests/GameManagerTests/AndroidManifest.xml
+++ b/core/tests/GameManagerTests/AndroidManifest.xml
@@ -17,7 +17,9 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.app.gamemanagertests"
-          android:sharedUserId="android.uid.system" >
+          android:sharedUserId="com.android.uid.test" >
+
+    <uses-permission android:name="android.permission.MANAGE_GAME_MODE" />
 
     <application android:appCategory="game">
         <uses-library android:name="android.test.runner" />
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 48cfc87..e811bb6 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -43,10 +43,12 @@
         "mockwebserver",
         "guava",
         "androidx.core_core",
+        "androidx.core_core-ktx",
         "androidx.test.espresso.core",
         "androidx.test.ext.junit",
         "androidx.test.runner",
         "androidx.test.rules",
+        "junit-params",
         "kotlin-test",
         "mockito-target-minus-junit4",
         "ub-uiautomator",
diff --git a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
index 4d5b0d2..561c10ba 100644
--- a/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupAgentTest.java
@@ -21,7 +21,8 @@
 import static org.mockito.Mockito.when;
 
 import android.app.backup.BackupAgent.IncludeExcludeRules;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
 import android.app.backup.FullBackup.BackupScheme.PathWithRequiredFlags;
 import android.os.ParcelFileDescriptor;
 import android.os.UserHandle;
@@ -66,7 +67,7 @@
         excludePaths.add(path);
         IncludeExcludeRules expectedRules = new IncludeExcludeRules(includePaths, excludePaths);
 
-        mBackupAgent = getAgentForOperationType(OperationType.BACKUP);
+        mBackupAgent = getAgentForBackupDestination(BackupDestination.CLOUD);
         when(mBackupScheme.maybeParseAndGetCanonicalExcludePaths()).thenReturn(excludePaths);
         when(mBackupScheme.maybeParseAndGetCanonicalIncludePaths()).thenReturn(includePaths);
 
@@ -84,24 +85,26 @@
     @Test
     public void getBackupRestoreEventLogger_afterOnCreateForBackup_initializedForBackup() {
         BackupAgent agent = new TestFullBackupAgent();
-        agent.onCreate(USER_HANDLE, OperationType.BACKUP); // TODO: pass in new operation type
+        agent.onCreate(USER_HANDLE, BackupDestination.CLOUD, OperationType.BACKUP);
 
-        assertThat(agent.getBackupRestoreEventLogger().getOperationType()).isEqualTo(1);
+        assertThat(agent.getBackupRestoreEventLogger().getOperationType()).isEqualTo(
+                OperationType.BACKUP);
     }
 
     @Test
     public void getBackupRestoreEventLogger_afterOnCreateForRestore_initializedForRestore() {
         BackupAgent agent = new TestFullBackupAgent();
-        agent.onCreate(USER_HANDLE, OperationType.BACKUP); // TODO: pass in new operation type
+        agent.onCreate(USER_HANDLE, BackupDestination.CLOUD, OperationType.RESTORE);
 
-        assertThat(agent.getBackupRestoreEventLogger().getOperationType()).isEqualTo(1);
+        assertThat(agent.getBackupRestoreEventLogger().getOperationType()).isEqualTo(
+                OperationType.RESTORE);
     }
 
     @Test
     public void getBackupRestoreEventLogger_afterBackup_containsLogsLoggedByAgent()
             throws Exception {
         BackupAgent agent = new TestFullBackupAgent();
-        agent.onCreate(USER_HANDLE, OperationType.BACKUP); // TODO: pass in new operation type
+        agent.onCreate(USER_HANDLE, BackupDestination.CLOUD, OperationType.BACKUP);
 
         // TestFullBackupAgent logs DATA_TYPE_BACKED_UP when onFullBackup is called.
         agent.onFullBackup(new FullBackupDataOutput(/* quota = */ 0));
@@ -110,9 +113,9 @@
                 .isEqualTo(DATA_TYPE_BACKED_UP);
     }
 
-    private BackupAgent getAgentForOperationType(@OperationType int operationType) {
+    private BackupAgent getAgentForBackupDestination(@BackupDestination int backupDestination) {
         BackupAgent agent = new TestFullBackupAgent();
-        agent.onCreate(USER_HANDLE, operationType);
+        agent.onCreate(USER_HANDLE, backupDestination);
         return agent;
     }
 
diff --git a/core/tests/coretests/src/android/app/backup/BackupManagerTest.java b/core/tests/coretests/src/android/app/backup/BackupManagerTest.java
new file mode 100644
index 0000000..cbf167c
--- /dev/null
+++ b/core/tests/coretests/src/android/app/backup/BackupManagerTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app.backup;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+
+import android.app.backup.BackupAnnotations.BackupDestination;
+import android.app.backup.BackupAnnotations.OperationType;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.function.ThrowingRunnable;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupManagerTest {
+    private BackupManager mBackupManager;
+
+    @Mock
+    Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mBackupManager = new BackupManager(mContext);
+    }
+
+    @Test
+    public void testGetBackupRestoreEventLogger_returnsBackupLoggerForBackup() {
+        BackupAgent agent = getTestAgent();
+        agent.onCreate(UserHandle.SYSTEM, BackupDestination.CLOUD,
+                OperationType.BACKUP);
+
+        BackupRestoreEventLogger logger = mBackupManager.getBackupRestoreEventLogger(agent);
+
+        assertThat(logger.getOperationType()).isEqualTo(OperationType.BACKUP);
+    }
+
+    @Test
+    public void testGetBackupRestoreEventLogger_returnsRestoreLoggerForRestore() {
+        BackupAgent agent = getTestAgent();
+        agent.onCreate(UserHandle.SYSTEM, BackupDestination.CLOUD,
+                OperationType.RESTORE);
+
+        BackupRestoreEventLogger logger = mBackupManager.getBackupRestoreEventLogger(agent);
+
+        assertThat(logger.getOperationType()).isEqualTo(OperationType.RESTORE);
+    }
+
+    @Test
+    public void testGetBackupRestoreEventLogger_uninitialisedAgent_throwsException() {
+        BackupAgent agent = getTestAgent();
+
+        assertThrows(IllegalStateException.class,
+                () -> mBackupManager.getBackupRestoreEventLogger(agent));
+    }
+
+    private static BackupAgent getTestAgent() {
+        return new BackupAgent() {
+            @Override
+            public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+                    ParcelFileDescriptor newState) throws IOException {
+
+            }
+
+            @Override
+            public void onRestore(BackupDataInput data, int appVersionCode,
+                    ParcelFileDescriptor newState) throws IOException {
+
+            }
+        };
+    }
+
+}
diff --git a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
index b9fdc6d..112d394 100644
--- a/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
+++ b/core/tests/coretests/src/android/app/backup/BackupRestoreEventLoggerTest.java
@@ -16,8 +16,8 @@
 
 package android.app.backup;
 
-import static android.app.backup.BackupRestoreEventLogger.OperationType.BACKUP;
-import static android.app.backup.BackupRestoreEventLogger.OperationType.RESTORE;
+import static android.app.backup.BackupAnnotations.OperationType.BACKUP;
+import static android.app.backup.BackupAnnotations.OperationType.RESTORE;
 
 import static com.google.common.truth.Truth.assertThat;
 
diff --git a/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java b/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
index a648a88..fc69f69 100644
--- a/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
+++ b/core/tests/coretests/src/android/app/time/LocationTimeZoneAlgorithmStatusTest.java
@@ -17,19 +17,26 @@
 package android.app.time;
 
 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_RUNNING;
+import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED;
 import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_RUNNING;
+import static android.app.time.DetectorStatusTypes.DETECTION_ALGORITHM_STATUS_UNKNOWN;
 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_CERTAIN;
 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_IS_UNCERTAIN;
 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_PRESENT;
 import static android.app.time.LocationTimeZoneAlgorithmStatus.PROVIDER_STATUS_NOT_READY;
 import static android.app.time.ParcelableTestSupport.assertEqualsAndHashCode;
 import static android.app.time.ParcelableTestSupport.assertRoundTripParcelable;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_NOT_APPLICABLE;
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_NOT_APPLICABLE;
 import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
 
 import android.app.time.LocationTimeZoneAlgorithmStatus.ProviderStatus;
 import android.service.timezone.TimeZoneProviderStatus;
@@ -207,4 +214,114 @@
         assertEquals(status,
                 LocationTimeZoneAlgorithmStatus.parseCommandlineArg(status.toString()));
     }
+
+    @Test
+    public void testCouldEnableTelephonyFallback_notRunning() {
+        LocationTimeZoneAlgorithmStatus notRunning =
+                new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_RUNNING,
+                        PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
+        assertFalse(notRunning.couldEnableTelephonyFallback());
+    }
+
+    @Test
+    public void testCouldEnableTelephonyFallback_unknown() {
+        // DETECTION_ALGORITHM_STATUS_UNKNOWN must never allow fallback
+        LocationTimeZoneAlgorithmStatus unknown =
+                new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_UNKNOWN,
+                        PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
+        assertFalse(unknown.couldEnableTelephonyFallback());
+    }
+
+    @Test
+    public void testCouldEnableTelephonyFallback_notSupported() {
+        // DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED must never allow fallback
+        LocationTimeZoneAlgorithmStatus notSupported =
+                new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_NOT_SUPPORTED,
+                        PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
+        assertFalse(notSupported.couldEnableTelephonyFallback());
+    }
+
+    @Test
+    public void testCouldEnableTelephonyFallback_running() {
+        // DETECTION_ALGORITHM_STATUS_RUNNING may allow fallback
+
+        // Sample provider-reported statuses that do / do not enable fallback.
+        TimeZoneProviderStatus enableTelephonyFallbackProviderStatus =
+                new TimeZoneProviderStatus.Builder()
+                        .setLocationDetectionDependencyStatus(
+                                DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT)
+                        .setConnectivityDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
+                        .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_NOT_APPLICABLE)
+                        .build();
+        assertTrue(enableTelephonyFallbackProviderStatus.couldEnableTelephonyFallback());
+
+        TimeZoneProviderStatus notEnableTelephonyFallbackProviderStatus =
+                new TimeZoneProviderStatus.Builder()
+                        .setLocationDetectionDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
+                        .setConnectivityDependencyStatus(DEPENDENCY_STATUS_NOT_APPLICABLE)
+                        .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_NOT_APPLICABLE)
+                        .build();
+        assertFalse(notEnableTelephonyFallbackProviderStatus.couldEnableTelephonyFallback());
+
+        // Provider not ready: Never enable fallback
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_NOT_READY, null, PROVIDER_STATUS_NOT_READY, null);
+            assertFalse(status.couldEnableTelephonyFallback());
+        }
+
+        // Provider uncertain without reported status: Never enable fallback
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, null, PROVIDER_STATUS_NOT_READY, null);
+            assertFalse(status.couldEnableTelephonyFallback());
+        }
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, null, PROVIDER_STATUS_NOT_PRESENT, null);
+            assertFalse(status.couldEnableTelephonyFallback());
+        }
+
+        // Provider uncertain with reported status: Fallback is based on the status for present
+        // providers that report their status. All present providers must have reported status and
+        // agree that fallback is a good idea.
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus,
+                            PROVIDER_STATUS_NOT_READY, null);
+            assertFalse(status.couldEnableTelephonyFallback());
+        }
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus,
+                            PROVIDER_STATUS_NOT_PRESENT, null);
+            assertTrue(status.couldEnableTelephonyFallback());
+        }
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus);
+            assertTrue(status.couldEnableTelephonyFallback());
+        }
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus,
+                            PROVIDER_STATUS_IS_UNCERTAIN, notEnableTelephonyFallbackProviderStatus);
+            assertFalse(status.couldEnableTelephonyFallback());
+        }
+        {
+            LocationTimeZoneAlgorithmStatus status =
+                    new LocationTimeZoneAlgorithmStatus(DETECTION_ALGORITHM_STATUS_RUNNING,
+                            PROVIDER_STATUS_NOT_PRESENT, null,
+                            PROVIDER_STATUS_IS_UNCERTAIN, enableTelephonyFallbackProviderStatus);
+            assertTrue(status.couldEnableTelephonyFallback());
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
new file mode 100644
index 0000000..11afd04
--- /dev/null
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorConfigTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+import static android.hardware.Sensor.TYPE_ACCELEROMETER;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.verify;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import android.os.Parcel;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.BackgroundThread;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+import java.time.Duration;
+
+@RunWith(AndroidJUnit4.class)
+public class VirtualSensorConfigTest {
+
+    private static final String SENSOR_NAME = "VirtualSensorName";
+    private static final String SENSOR_VENDOR = "VirtualSensorVendor";
+
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    @Mock
+    private VirtualSensor.SensorStateChangeCallback mSensorCallback;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void parcelAndUnparcel_matches() {
+        final VirtualSensorConfig originalConfig =
+                new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
+                        .setVendor(SENSOR_VENDOR)
+                        .setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
+                        .build();
+        final Parcel parcel = Parcel.obtain();
+        originalConfig.writeToParcel(parcel, /* flags= */ 0);
+        parcel.setDataPosition(0);
+        final VirtualSensorConfig recreatedConfig =
+                VirtualSensorConfig.CREATOR.createFromParcel(parcel);
+        assertThat(recreatedConfig.getType()).isEqualTo(originalConfig.getType());
+        assertThat(recreatedConfig.getName()).isEqualTo(originalConfig.getName());
+        assertThat(recreatedConfig.getVendor()).isEqualTo(originalConfig.getVendor());
+        assertThat(recreatedConfig.getStateChangeCallback()).isNotNull();
+    }
+
+    @Test
+    public void sensorConfig_onlyRequiredFields() {
+        final VirtualSensorConfig config =
+                new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME).build();
+        assertThat(config.getVendor()).isNull();
+        assertThat(config.getStateChangeCallback()).isNull();
+    }
+
+    @Test
+    public void sensorConfig_sensorCallbackInvocation() throws Exception {
+        final VirtualSensorConfig config =
+                new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
+                        .setStateChangeCallback(BackgroundThread.getExecutor(), mSensorCallback)
+                        .build();
+
+        final Duration samplingPeriod = Duration.ofMillis(123);
+        final Duration batchLatency = Duration.ofMillis(456);
+
+        config.getStateChangeCallback().onStateChanged(true,
+                (int) MILLISECONDS.toMicros(samplingPeriod.toMillis()),
+                (int) MILLISECONDS.toMicros(batchLatency.toMillis()));
+
+        verify(mSensorCallback, timeout(1000)).onStateChanged(true, samplingPeriod, batchLatency);
+    }
+}
diff --git a/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java
new file mode 100644
index 0000000..a9583fd
--- /dev/null
+++ b/core/tests/coretests/src/android/companion/virtual/sensor/VirtualSensorEventTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual.sensor;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class VirtualSensorEventTest {
+
+    private static final long TIMESTAMP_NANOS = SystemClock.elapsedRealtimeNanos();
+    private static final float[] SENSOR_VALUES = new float[] {1.2f, 3.4f, 5.6f};
+
+    @Test
+    public void parcelAndUnparcel_matches() {
+        final VirtualSensorEvent originalEvent = new VirtualSensorEvent.Builder(SENSOR_VALUES)
+                .setTimestampNanos(TIMESTAMP_NANOS)
+                .build();
+        final Parcel parcel = Parcel.obtain();
+        originalEvent.writeToParcel(parcel, /* flags= */ 0);
+        parcel.setDataPosition(0);
+        final VirtualSensorEvent recreatedEvent =
+                VirtualSensorEvent.CREATOR.createFromParcel(parcel);
+        assertThat(recreatedEvent.getValues()).isEqualTo(originalEvent.getValues());
+        assertThat(recreatedEvent.getTimestampNanos()).isEqualTo(originalEvent.getTimestampNanos());
+    }
+
+    @Test
+    public void sensorEvent_nullValues() {
+        assertThrows(
+                IllegalArgumentException.class, () -> new VirtualSensorEvent.Builder(null).build());
+    }
+
+    @Test
+    public void sensorEvent_noValues() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> new VirtualSensorEvent.Builder(new float[0]).build());
+    }
+
+    @Test
+    public void sensorEvent_noTimestamp_usesCurrentTime() {
+        final VirtualSensorEvent event = new VirtualSensorEvent.Builder(SENSOR_VALUES).build();
+        assertThat(event.getValues()).isEqualTo(SENSOR_VALUES);
+        assertThat(TIMESTAMP_NANOS).isLessThan(event.getTimestampNanos());
+        assertThat(event.getTimestampNanos()).isLessThan(SystemClock.elapsedRealtimeNanos());
+    }
+
+    @Test
+    public void sensorEvent_created() {
+        final VirtualSensorEvent event = new VirtualSensorEvent.Builder(SENSOR_VALUES)
+                .setTimestampNanos(TIMESTAMP_NANOS)
+                .build();
+        assertThat(event.getTimestampNanos()).isEqualTo(TIMESTAMP_NANOS);
+        assertThat(event.getValues()).isEqualTo(SENSOR_VALUES);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
new file mode 100644
index 0000000..625c318
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterFactoryTest.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.res
+
+import androidx.core.util.forEach
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.LargeTest
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import kotlin.math.ceil
+import kotlin.math.floor
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class FontScaleConverterFactoryTest {
+
+    @Test
+    fun scale200IsTwiceAtSmallSizes() {
+        val table = FontScaleConverterFactory.forScale(2F)!!
+        assertThat(table.convertSpToDp(1F)).isWithin(CONVERSION_TOLERANCE).of(2f)
+        assertThat(table.convertSpToDp(8F)).isWithin(CONVERSION_TOLERANCE).of(16f)
+        assertThat(table.convertSpToDp(10F)).isWithin(CONVERSION_TOLERANCE).of(20f)
+        assertThat(table.convertSpToDp(5F)).isWithin(CONVERSION_TOLERANCE).of(10f)
+        assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
+    }
+
+    @SmallTest
+    fun missingLookupTableReturnsNull() {
+        assertThat(FontScaleConverterFactory.forScale(3F)).isNull()
+    }
+
+    @SmallTest
+    fun missingLookupTable105ReturnsNull() {
+        assertThat(FontScaleConverterFactory.forScale(1.05F)).isNull()
+    }
+
+    @SmallTest
+    fun missingLookupTableNegativeReturnsNull() {
+        assertThat(FontScaleConverterFactory.forScale(-1F)).isNull()
+    }
+
+    @SmallTest
+    fun unnecessaryFontScalesReturnsNull() {
+        assertThat(FontScaleConverterFactory.forScale(0F)).isNull()
+        assertThat(FontScaleConverterFactory.forScale(1F)).isNull()
+        assertThat(FontScaleConverterFactory.forScale(0.85F)).isNull()
+    }
+
+    @SmallTest
+    fun tablesMatchAndAreMonotonicallyIncreasing() {
+        FontScaleConverterFactory.LOOKUP_TABLES.forEach { _, lookupTable ->
+            assertThat(lookupTable.mToDpValues).hasLength(lookupTable.mFromSpValues.size)
+            assertThat(lookupTable.mToDpValues).isNotEmpty()
+
+            assertThat(lookupTable.mFromSpValues.asList()).isInStrictOrder()
+            assertThat(lookupTable.mToDpValues.asList()).isInStrictOrder()
+
+            assertThat(lookupTable.mFromSpValues.asList()).containsNoDuplicates()
+            assertThat(lookupTable.mToDpValues.asList()).containsNoDuplicates()
+        }
+    }
+
+    @LargeTest
+    @Test
+    fun allFeasibleScalesAndConversionsDoNotCrash() {
+        generateSequenceOfFractions(-10000f..10000f, step = 0.01f)
+            .mapNotNull{ FontScaleConverterFactory.forScale(it) }
+            .flatMap{ table ->
+                generateSequenceOfFractions(-10000f..10000f, step = 0.01f)
+                    .map{ Pair(table, it) }
+            }
+            .forEach { (table, sp) ->
+                try {
+                    assertWithMessage(
+                        "convertSpToDp(%s) on table: %s",
+                        sp.toString(),
+                        table.toString()
+                    )
+                        .that(table.convertSpToDp(sp))
+                        .isFinite()
+                } catch (e: Exception) {
+                    throw AssertionError("Exception during convertSpToDp($sp) on table: $table", e)
+                }
+            }
+    }
+
+    @Test
+    fun testGenerateSequenceOfFractions() {
+        val fractions = generateSequenceOfFractions(-1000f..1000f, step = 0.1f)
+            .toList()
+        fractions.forEach {
+            assertThat(it).isAtLeast(-1000f)
+            assertThat(it).isAtMost(1000f)
+        }
+
+        assertThat(fractions).isInStrictOrder()
+        assertThat(fractions).hasSize(1000 * 2 * 10 + 1) // Don't forget the 0 in the middle!
+
+        assertThat(fractions).contains(100f)
+        assertThat(fractions).contains(500.1f)
+        assertThat(fractions).contains(500.2f)
+        assertThat(fractions).contains(0.2f)
+        assertThat(fractions).contains(0f)
+        assertThat(fractions).contains(-10f)
+        assertThat(fractions).contains(-10f)
+        assertThat(fractions).contains(-10.3f)
+
+        assertThat(fractions).doesNotContain(-10.31f)
+        assertThat(fractions).doesNotContain(0.35f)
+        assertThat(fractions).doesNotContain(0.31f)
+        assertThat(fractions).doesNotContain(-.35f)
+    }
+
+    companion object {
+        private const val CONVERSION_TOLERANCE = 0.05f
+    }
+}
+
+fun generateSequenceOfFractions(
+    range: ClosedFloatingPointRange<Float>,
+    step: Float
+): Sequence<Float> {
+    val multiplier = 1f / step
+    val start = floor(range.start * multiplier).toInt()
+    val endInclusive = ceil(range.endInclusive * multiplier).toInt()
+    return generateSequence(start) { it + 1 }
+        .takeWhile { it <= endInclusive }
+        .map{ it.toFloat() / multiplier }
+}
diff --git a/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
new file mode 100644
index 0000000..e405c55
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/FontScaleConverterTest.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.content.res
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class FontScaleConverterTest {
+
+    @Test
+    fun straightInterpolation() {
+        val table = createTable(8f to 8f, 10f to 10f, 20f to 20f)
+        assertThat(table.convertSpToDp(1F)).isWithin(CONVERSION_TOLERANCE).of(1f)
+        assertThat(table.convertSpToDp(8F)).isWithin(CONVERSION_TOLERANCE).of(8f)
+        assertThat(table.convertSpToDp(10F)).isWithin(CONVERSION_TOLERANCE).of(10f)
+        assertThat(table.convertSpToDp(30F)).isWithin(CONVERSION_TOLERANCE).of(30f)
+        assertThat(table.convertSpToDp(20F)).isWithin(CONVERSION_TOLERANCE).of(20f)
+        assertThat(table.convertSpToDp(5F)).isWithin(CONVERSION_TOLERANCE).of(5f)
+        assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
+    }
+
+    @Test
+    fun interpolate200Percent() {
+        val table = createTable(8f to 16f, 10f to 20f, 30f to 60f)
+        assertThat(table.convertSpToDp(1F)).isWithin(CONVERSION_TOLERANCE).of(2f)
+        assertThat(table.convertSpToDp(8F)).isWithin(CONVERSION_TOLERANCE).of(16f)
+        assertThat(table.convertSpToDp(10F)).isWithin(CONVERSION_TOLERANCE).of(20f)
+        assertThat(table.convertSpToDp(30F)).isWithin(CONVERSION_TOLERANCE).of(60f)
+        assertThat(table.convertSpToDp(20F)).isWithin(CONVERSION_TOLERANCE).of(40f)
+        assertThat(table.convertSpToDp(5F)).isWithin(CONVERSION_TOLERANCE).of(10f)
+        assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
+    }
+
+    @Test
+    fun interpolate150Percent() {
+        val table = createTable(2f to 3f, 10f to 15f, 20f to 30f, 100f to 150f)
+        assertThat(table.convertSpToDp(2F)).isWithin(CONVERSION_TOLERANCE).of(3f)
+        assertThat(table.convertSpToDp(1F)).isWithin(CONVERSION_TOLERANCE).of(1.5f)
+        assertThat(table.convertSpToDp(8F)).isWithin(CONVERSION_TOLERANCE).of(12f)
+        assertThat(table.convertSpToDp(10F)).isWithin(CONVERSION_TOLERANCE).of(15f)
+        assertThat(table.convertSpToDp(20F)).isWithin(CONVERSION_TOLERANCE).of(30f)
+        assertThat(table.convertSpToDp(50F)).isWithin(CONVERSION_TOLERANCE).of(75f)
+        assertThat(table.convertSpToDp(5F)).isWithin(CONVERSION_TOLERANCE).of(7.5f)
+        assertThat(table.convertSpToDp(0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
+    }
+
+    @Test
+    fun pastEndsUsesLastScalingFactor() {
+        val table = createTable(8f to 16f, 10f to 20f, 30f to 60f)
+        assertThat(table.convertSpToDp(100F)).isWithin(CONVERSION_TOLERANCE).of(200f)
+        assertThat(table.convertSpToDp(31F)).isWithin(CONVERSION_TOLERANCE).of(62f)
+        assertThat(table.convertSpToDp(1000F)).isWithin(CONVERSION_TOLERANCE).of(2000f)
+        assertThat(table.convertSpToDp(2000F)).isWithin(CONVERSION_TOLERANCE).of(4000f)
+        assertThat(table.convertSpToDp(10000F)).isWithin(CONVERSION_TOLERANCE).of(20000f)
+    }
+
+    @Test
+    fun negativeSpIsNegativeDp() {
+        val table = createTable(8f to 16f, 10f to 20f, 30f to 60f)
+        assertThat(table.convertSpToDp(-1F)).isWithin(CONVERSION_TOLERANCE).of(-2f)
+        assertThat(table.convertSpToDp(-8F)).isWithin(CONVERSION_TOLERANCE).of(-16f)
+        assertThat(table.convertSpToDp(-10F)).isWithin(CONVERSION_TOLERANCE).of(-20f)
+        assertThat(table.convertSpToDp(-30F)).isWithin(CONVERSION_TOLERANCE).of(-60f)
+        assertThat(table.convertSpToDp(-20F)).isWithin(CONVERSION_TOLERANCE).of(-40f)
+        assertThat(table.convertSpToDp(-5F)).isWithin(CONVERSION_TOLERANCE).of(-10f)
+        assertThat(table.convertSpToDp(-0F)).isWithin(CONVERSION_TOLERANCE).of(0f)
+    }
+
+    private fun createTable(vararg pairs: Pair<Float, Float>) =
+        FontScaleConverter(
+            pairs.map { it.first }.toFloatArray(),
+            pairs.map { it.second }.toFloatArray()
+        )
+
+    companion object {
+        private const val CONVERSION_TOLERANCE = 0.05f
+    }
+}
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index a528c19..6bf8f56 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -203,16 +203,22 @@
                 fallbackMap);
         SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
         Map<String, Typeface> copiedFontMap = new ArrayMap<>();
-        Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
-                copiedFontMap);
-        assertEquals(systemFontMap.size(), copiedFontMap.size());
-        for (String key : systemFontMap.keySet()) {
-            assertTrue(copiedFontMap.containsKey(key));
-            Typeface original = systemFontMap.get(key);
-            Typeface copied = copiedFontMap.get(key);
-            assertEquals(original.getStyle(), copied.getStyle());
-            assertEquals(original.getWeight(), copied.getWeight());
-            assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+        try {
+            Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
+                    copiedFontMap);
+            assertEquals(systemFontMap.size(), copiedFontMap.size());
+            for (String key : systemFontMap.keySet()) {
+                assertTrue(copiedFontMap.containsKey(key));
+                Typeface original = systemFontMap.get(key);
+                Typeface copied = copiedFontMap.get(key);
+                assertEquals(original.getStyle(), copied.getStyle());
+                assertEquals(original.getWeight(), copied.getWeight());
+                assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+            }
+        } finally {
+            for (Typeface typeface : copiedFontMap.values()) {
+                typeface.releaseNativeObjectForTest();
+            }
         }
     }
 
diff --git a/core/tests/coretests/src/android/os/EnvironmentTest.java b/core/tests/coretests/src/android/os/EnvironmentTest.java
index c0325ca..8e63a0f 100644
--- a/core/tests/coretests/src/android/os/EnvironmentTest.java
+++ b/core/tests/coretests/src/android/os/EnvironmentTest.java
@@ -47,29 +47,6 @@
         return InstrumentationRegistry.getContext();
     }
 
-    /**
-     * Sets {@code mode} for the given {@code ops} and the given {@code uid}.
-     *
-     * <p>This method drops shell permission identity.
-     */
-    private static void setAppOpsModeForUid(int uid, int mode, String... ops) {
-        if (ops == null) {
-            return;
-        }
-        InstrumentationRegistry.getInstrumentation()
-                .getUiAutomation()
-                .adoptShellPermissionIdentity();
-        try {
-            for (String op : ops) {
-                getContext().getSystemService(AppOpsManager.class).setUidMode(op, uid, mode);
-            }
-        } finally {
-            InstrumentationRegistry.getInstrumentation()
-                    .getUiAutomation()
-                    .dropShellPermissionIdentity();
-        }
-    }
-
     @Before
     public void setUp() throws Exception {
         dir = getContext().getDir("testing", Context.MODE_PRIVATE);
@@ -127,17 +104,4 @@
         Environment.buildPath(dir, "Taxes.pdf").createNewFile();
         assertEquals(HAS_OTHER, classifyExternalStorageDirectory(dir));
     }
-
-    @Test
-    public void testIsExternalStorageManager() throws Exception {
-        assertFalse(Environment.isExternalStorageManager());
-        try {
-            setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_ALLOWED,
-                    AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
-            assertTrue(Environment.isExternalStorageManager());
-        } finally {
-            setAppOpsModeForUid(Process.myUid(), AppOpsManager.MODE_DEFAULT,
-                    AppOpsManager.OPSTR_MANAGE_EXTERNAL_STORAGE);
-        }
-    }
 }
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index d1d14f6..44923b6 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -117,7 +117,8 @@
     public void testSendHint() {
         Session s = createSession();
         assumeNotNull(s);
-        s.sendHint(Session.CPU_LOAD_UP);
+        s.sendHint(Session.CPU_LOAD_RESET);
+        // ensure we can also send within the rate limit without exception
         s.sendHint(Session.CPU_LOAD_RESET);
     }
 
diff --git a/core/tests/coretests/src/android/os/VibrationEffectTest.java b/core/tests/coretests/src/android/os/VibrationEffectTest.java
index f7ca822..0c7ff4a 100644
--- a/core/tests/coretests/src/android/os/VibrationEffectTest.java
+++ b/core/tests/coretests/src/android/os/VibrationEffectTest.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import static android.os.VibrationEffect.DEFAULT_AMPLITUDE;
 import static android.os.VibrationEffect.VibrationParameter.targetAmplitude;
 import static android.os.VibrationEffect.VibrationParameter.targetFrequency;
 
@@ -48,6 +49,7 @@
 import org.mockito.junit.MockitoJUnitRunner;
 
 import java.time.Duration;
+import java.util.Arrays;
 
 @Presubmit
 @RunWith(MockitoJUnitRunner.class)
@@ -62,16 +64,363 @@
     private static final int TEST_AMPLITUDE = 100;
     private static final long[] TEST_TIMINGS = new long[] { 100, 100, 200 };
     private static final int[] TEST_AMPLITUDES =
-            new int[] { 255, 0, VibrationEffect.DEFAULT_AMPLITUDE };
+            new int[] { 255, 0, DEFAULT_AMPLITUDE };
 
     private static final VibrationEffect TEST_ONE_SHOT =
             VibrationEffect.createOneShot(TEST_TIMING, TEST_AMPLITUDE);
     private static final VibrationEffect DEFAULT_ONE_SHOT =
-            VibrationEffect.createOneShot(TEST_TIMING, VibrationEffect.DEFAULT_AMPLITUDE);
+            VibrationEffect.createOneShot(TEST_TIMING, DEFAULT_AMPLITUDE);
     private static final VibrationEffect TEST_WAVEFORM =
             VibrationEffect.createWaveform(TEST_TIMINGS, TEST_AMPLITUDES, -1);
 
     @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_zeroAmplitudesOnEvenIndices() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4, 5},
+                /* amplitudes= */ new int[] {0, DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {1, 2, 3, 4, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_zeroAmplitudesOnOddIndices() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4, 5},
+                /* amplitudes= */ new int[] {
+                        DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 1, 2, 3, 4, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_zeroAmplitudesAtTheStart() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3},
+                /* amplitudes= */ new int[] {0, 0, DEFAULT_AMPLITUDE},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {3, 3};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_zeroAmplitudesAtTheEnd() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3},
+                /* amplitudes= */ new int[] {DEFAULT_AMPLITUDE, 0, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 1, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_allDefaultAmplitudes() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3},
+                /* amplitudes= */ new int[] {
+                        DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 6};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_allZeroAmplitudes() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3},
+                /* amplitudes= */ new int[] {0, 0, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {6};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_sparsedZeroAmplitudes() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4, 5, 6, 7},
+                /* amplitudes= */ new int[] {
+                        0, 0, DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {3, 3, 4, 11, 7};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_oneTimingWithDefaultAmplitude() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1},
+                /* amplitudes= */ new int[] {DEFAULT_AMPLITUDE},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 1};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_oneTimingWithZeroAmplitude() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1},
+                /* amplitudes= */ new int[] {0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {1};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_repeating() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4, 5},
+                /* amplitudes= */ new int[] {0, DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE, 0},
+                /* repeatIndex= */ 0);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+        effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4, 5},
+                /* amplitudes= */ new int[] {0, DEFAULT_AMPLITUDE, 0, DEFAULT_AMPLITUDE, 0},
+                /* repeatIndex= */ 3);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+        effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2},
+                /* amplitudes= */ new int[] {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE},
+                /* repeatIndex= */ 1);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsAndAmplitudes_badAmplitude() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1},
+                /* amplitudes= */ new int[] {200},
+                /* repeatIndex= */ -1);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_nonZeroTimings() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {1, 2, 3};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_oneValue() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {5},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_zeroesAtTheEnd() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 0, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {1, 2, 3, 0, 0};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_zeroesAtTheStart() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {0, 0, 1, 2, 3},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 0, 1, 2, 3};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_zeroesAtTheMiddle() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 0, 0, 3, 4, 5},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {1, 2, 0, 0, 3, 4, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_sparsedZeroes() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {0, 1, 2, 0, 0, 3, 4, 5, 0},
+                /* repeatIndex= */ -1);
+        long[] expectedPattern = new long[] {0, 1, 2, 0, 0, 3, 4, 5, 0};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_timingsOnly_repeating() {
+        VibrationEffect effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {0, 1, 2, 0, 0, 3, 4, 5, 0},
+                /* repeatIndex= */ 0);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+        effect = VibrationEffect.createWaveform(
+                /* timings= */ new long[] {1, 2, 3, 4},
+                /* repeatIndex= */ 2);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_notPatternPased() {
+        VibrationEffect effect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_oneShot_defaultAmplitude() {
+        VibrationEffect effect = VibrationEffect.createOneShot(
+                /* milliseconds= */ 5, /* ampliutde= */ DEFAULT_AMPLITUDE);
+        long[] expectedPattern = new long[] {0, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_oneShot_badAmplitude() {
+        VibrationEffect effect = VibrationEffect.createOneShot(
+                /* milliseconds= */ 5, /* ampliutde= */ 50);
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_composition_noOffDuration() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {5},
+                                /* repeatIndex= */ -1))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {2, 3},
+                                /* repeatIndex= */ -1))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {10, 20},
+                                /* amplitudes= */ new int[] {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE},
+                                /* repeatIndex= */ -1))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {4, 5},
+                                /* amplitudes= */ new int[] {0, DEFAULT_AMPLITUDE},
+                                /* repeatIndex= */ -1))
+                .compose();
+        long[] expectedPattern = new long[] {7, 33, 4, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_composition_withOffDuration() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addOffDuration(Duration.ofMillis(20))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {10, 20},
+                                /* amplitudes= */ new int[] {0, DEFAULT_AMPLITUDE},
+                                /* repeatIndex= */ -1))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {30, 40},
+                                /* amplitudes= */ new int[] {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE},
+                                /* repeatIndex= */ -1))
+                .addOffDuration(Duration.ofMillis(10))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {4, 5},
+                                /* repeatIndex= */ -1))
+                .addOffDuration(Duration.ofMillis(5))
+                .compose();
+        long[] expectedPattern = new long[] {30, 90, 14, 5, 5};
+
+        assertArrayEq(expectedPattern, effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_composition_withPrimitives() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK)
+                .addOffDuration(Duration.ofMillis(20))
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {5},
+                                /* repeatIndex= */ -1))
+                .compose();
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_composition_repeating() {
+        VibrationEffect effect = VibrationEffect.startComposition()
+                .addEffect(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {5},
+                                /* repeatIndex= */ -1))
+                .repeatEffectIndefinitely(
+                        VibrationEffect.createWaveform(
+                                /* timings= */ new long[] {2, 3},
+                                /* repeatIndex= */ -1))
+                .compose();
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
+    public void computeLegacyPattern_effectsViaStartWaveform() {
+        // Effects created via startWaveform are not expected to be converted to long[] patterns, as
+        // they are not configured to always play with the default amplitude.
+        VibrationEffect effect = VibrationEffect.startWaveform(targetFrequency(60))
+                .addTransition(Duration.ofMillis(100), targetAmplitude(1), targetFrequency(120))
+                .addSustain(Duration.ofMillis(200))
+                .addTransition(Duration.ofMillis(100), targetAmplitude(0), targetFrequency(60))
+                .build();
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+        effect = VibrationEffect.startWaveform(targetFrequency(60))
+                .addTransition(Duration.ofMillis(80), targetAmplitude(1))
+                .addSustain(Duration.ofMillis(200))
+                .addTransition(Duration.ofMillis(100), targetAmplitude(0))
+                .build();
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+
+        effect = VibrationEffect.startWaveform(targetFrequency(60))
+                .addTransition(Duration.ofMillis(100), targetFrequency(50))
+                .addSustain(Duration.ofMillis(50))
+                .addTransition(Duration.ofMillis(20), targetFrequency(75))
+                .build();
+
+        assertNull(effect.computeCreateWaveformOffOnTimingsOrNull());
+    }
+
+    @Test
     public void getRingtones_noPrebakedRingtones() {
         Resources r = mockRingtoneResources(new String[0]);
         Context context = mockContext(r);
@@ -100,7 +449,7 @@
     @Test
     public void testValidateOneShot() {
         VibrationEffect.createOneShot(1, 255).validate();
-        VibrationEffect.createOneShot(1, VibrationEffect.DEFAULT_AMPLITUDE).validate();
+        VibrationEffect.createOneShot(1, DEFAULT_AMPLITUDE).validate();
 
         assertThrows(IllegalArgumentException.class,
                 () -> VibrationEffect.createOneShot(-1, 255).validate());
@@ -501,6 +850,13 @@
         assertTrue(VibrationEffect.get(VibrationEffect.EFFECT_TICK).isHapticFeedbackCandidate());
     }
 
+    private void assertArrayEq(long[] expected, long[] actual) {
+        assertTrue(
+                String.format("Expected pattern %s, but was %s",
+                        Arrays.toString(expected), Arrays.toString(actual)),
+                Arrays.equals(expected, actual));
+    }
+
     private Resources mockRingtoneResources() {
         return mockRingtoneResources(new String[]{
                 RINGTONE_URI_1,
diff --git a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
index 9006cd9..0c1630e 100644
--- a/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
+++ b/core/tests/coretests/src/android/service/timezone/TimeZoneProviderStatusTest.java
@@ -16,15 +16,31 @@
 
 package android.service.timezone;
 
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT;
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS;
 import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_OK;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_UNKNOWN;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_FAILED;
 import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_OK;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_UNKNOWN;
 
 import static org.junit.Assert.assertEquals;
 
+import android.service.timezone.TimeZoneProviderStatus.DependencyStatus;
+import android.service.timezone.TimeZoneProviderStatus.OperationStatus;
+
 import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.IntStream;
+
+import junitparams.JUnitParamsRunner;
+import junitparams.Parameters;
 
 /** Non-SDK tests. See CTS for SDK API tests. */
+@RunWith(JUnitParamsRunner.class)
 public class TimeZoneProviderStatusTest {
 
     @Test
@@ -37,4 +53,51 @@
 
         assertEquals(status, TimeZoneProviderStatus.parseProviderStatus(status.toString()));
     }
+
+    @Test
+    @Parameters(method = "couldEnableTelephonyFallbackParams")
+    public void couldEnableTelephonyFallback(@DependencyStatus int locationDetectionStatus,
+            @DependencyStatus int connectivityStatus, @OperationStatus int tzResolutionStatus) {
+        TimeZoneProviderStatus providerStatus =
+                new TimeZoneProviderStatus.Builder()
+                        .setLocationDetectionDependencyStatus(locationDetectionStatus)
+                        .setConnectivityDependencyStatus(connectivityStatus)
+                        .setTimeZoneResolutionOperationStatus(tzResolutionStatus)
+                        .build();
+        boolean locationDetectionStatusCouldEnableFallback =
+                (locationDetectionStatus == DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT
+                        || locationDetectionStatus == DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS);
+        boolean connectivityStatusCouldEnableFallback =
+                (connectivityStatus == DEPENDENCY_STATUS_BLOCKED_BY_ENVIRONMENT
+                        || connectivityStatus == DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS);
+        boolean tzResolutionStatusCouldEnableFallback = false;
+
+        assertEquals(locationDetectionStatusCouldEnableFallback
+                        || connectivityStatusCouldEnableFallback
+                        || tzResolutionStatusCouldEnableFallback,
+                providerStatus.couldEnableTelephonyFallback());
+    }
+
+    public static Integer[][] couldEnableTelephonyFallbackParams() {
+        List<Integer[]> params = new ArrayList<>();
+        @DependencyStatus int[] dependencyStatuses =
+                IntStream.rangeClosed(
+                        DEPENDENCY_STATUS_UNKNOWN, DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS).toArray();
+        @OperationStatus int[] operationStatuses =
+                IntStream.rangeClosed(OPERATION_STATUS_UNKNOWN, OPERATION_STATUS_FAILED).toArray();
+
+        // Cartesian product: dependencyStatus x dependencyStatus x operationStatus
+        for (@DependencyStatus int locationDetectionStatus : dependencyStatuses) {
+            for (@DependencyStatus int connectivityStatus : dependencyStatuses) {
+                for (@OperationStatus int tzResolutionStatus : operationStatuses) {
+                    params.add(new Integer[] {
+                            locationDetectionStatus,
+                            connectivityStatus,
+                            tzResolutionStatus
+                    });
+                }
+            }
+        }
+        return params.toArray(new Integer[0][0]);
+    }
 }
diff --git a/core/tests/coretests/src/android/util/RotationUtilsTest.java b/core/tests/coretests/src/android/util/RotationUtilsTest.java
index 826eb30..1b1ee4f 100644
--- a/core/tests/coretests/src/android/util/RotationUtilsTest.java
+++ b/core/tests/coretests/src/android/util/RotationUtilsTest.java
@@ -18,6 +18,7 @@
 
 import static android.util.RotationUtils.rotateBounds;
 import static android.util.RotationUtils.rotatePoint;
+import static android.util.RotationUtils.rotatePointF;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
@@ -25,6 +26,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.graphics.Point;
+import android.graphics.PointF;
 import android.graphics.Rect;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -79,4 +81,26 @@
         rotatePoint(testResult, ROTATION_270, parentW, parentH);
         assertEquals(new Point(560, 60), testResult);
     }
+
+    @Test
+    public void testRotatePointF() {
+        float parentW = 1000f;
+        float parentH = 600f;
+        PointF testPt = new PointF(60f, 40f);
+
+        PointF testResult = new PointF(testPt);
+        rotatePointF(testResult, ROTATION_90, parentW, parentH);
+        assertEquals(40f, testResult.x, .1f);
+        assertEquals(940f, testResult.y, .1f);
+
+        testResult.set(testPt.x, testPt.y);
+        rotatePointF(testResult, ROTATION_180, parentW, parentH);
+        assertEquals(940f, testResult.x, .1f);
+        assertEquals(560f, testResult.y, .1f);
+
+        testResult.set(testPt.x, testPt.y);
+        rotatePointF(testResult, ROTATION_270, parentW, parentH);
+        assertEquals(560f, testResult.x, .1f);
+        assertEquals(60f, testResult.y, .1f);
+    }
 }
diff --git a/core/tests/coretests/src/android/util/TypedValueTest.kt b/core/tests/coretests/src/android/util/TypedValueTest.kt
index 7a05d97..7d98a7d 100644
--- a/core/tests/coretests/src/android/util/TypedValueTest.kt
+++ b/core/tests/coretests/src/android/util/TypedValueTest.kt
@@ -16,16 +16,17 @@
 
 package android.util
 
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.LargeTest
 import androidx.test.filters.SmallTest
-import androidx.test.runner.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlin.math.abs
+import kotlin.math.min
+import kotlin.math.roundToInt
 import org.junit.Assert.assertEquals
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
-import kotlin.math.abs
-import kotlin.math.min
-import kotlin.math.roundToInt
 
 @RunWith(AndroidJUnit4::class)
 class TypedValueTest {
@@ -152,4 +153,19 @@
         val widthPx = TypedValue.complexToDimensionPixelSize(widthDimen, metrics)
         assertEquals(widthFloat.roundToInt(), widthPx)
     }
-}
\ No newline at end of file
+
+    @SmallTest
+    @Test
+    fun testNonLinearFontScaling_nullLookupFallsBackToScaledDensity() {
+        val metrics: DisplayMetrics = mock(DisplayMetrics::class.java)
+        val fontScale = 2f
+        metrics.density = 1f
+        metrics.scaledDensity = fontScale * metrics.density
+        metrics.fontScaleConverter = null
+
+        assertThat(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10f, metrics))
+                .isEqualTo(20f)
+        assertThat(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 50f, metrics))
+                .isEqualTo(100f)
+    }
+}
diff --git a/core/tests/coretests/src/android/view/DisplayShapeTest.java b/core/tests/coretests/src/android/view/DisplayShapeTest.java
new file mode 100644
index 0000000..77dd8bd
--- /dev/null
+++ b/core/tests/coretests/src/android/view/DisplayShapeTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link DisplayShape}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayShapeTest {
+    // Rectangle with w=100, height=200
+    private static final String SPEC_RECTANGULAR_SHAPE = "M0,0 L100,0 L100,200 L0,200 Z";
+
+    @Test
+    public void testGetPath() {
+        final DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 100f, 200f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testDefaultShape_screenIsRound() {
+        final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 100, true);
+
+        // A circle with radius = 50.
+        final String expect = "M0,50.0 A50.0,50.0 0 1,1 100,50.0 A50.0,50.0 0 1,1 0,50.0 Z";
+        assertEquals(displayShape.mDisplayShapeSpec, expect);
+    }
+
+    @Test
+    public void testDefaultShape_screenIsNotRound() {
+        final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 200, false);
+
+        // A rectangle with width/height = 100/200.
+        final String expect = "M0,0 L100,0 L100,200 L0,200 Z";
+        assertEquals(displayShape.mDisplayShapeSpec, expect);
+    }
+
+    @Test
+    public void testFromSpecString_cache() {
+        final DisplayShape cached = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        assertThat(DisplayShape.fromSpecString(SPEC_RECTANGULAR_SHAPE, 1f, 100, 200),
+                sameInstance(cached));
+    }
+
+    @Test
+    public void testGetPath_cache() {
+        final Path cached = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath();
+        assertThat(DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath(),
+                sameInstance(cached));
+    }
+
+    @Test
+    public void testRotate_90() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setRotation(ROTATION_90);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testRotate_270() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setRotation(ROTATION_270);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testOffset() {
+        DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+        displayShape = displayShape.setOffset(-10, -20);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(-10f, -20f, 90f, 180f);
+        assertEquals(actualRect, expectRect);
+    }
+
+    @Test
+    public void testPhysicalPixelDisplaySizeRatio() {
+        final DisplayShape displayShape = DisplayShape.fromSpecString(
+                SPEC_RECTANGULAR_SHAPE, 0.5f, 100, 200);
+        final Path path = displayShape.getPath();
+        final RectF actualRect = new RectF();
+        path.computeBounds(actualRect, false);
+
+        final RectF expectRect = new RectF(0f, 0f, 50f, 100f);
+        assertEquals(actualRect, expectRect);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index be9da11..6a96f28 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -517,6 +517,19 @@
                 windowInsets.getRoundedCorner(POSITION_BOTTOM_LEFT));
     }
 
+    @Test
+    public void testCalculateRelativeDisplayShape() {
+        mState.setDisplayFrame(new Rect(0, 0, 200, 400));
+        mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
+        WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
+                false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+                WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+
+        final DisplayShape expect =
+                DisplayShape.createDefaultDisplayShape(200, 400, false).setOffset(-10, -20);
+        assertEquals(expect, windowInsets.getDisplayShape());
+    }
+
     private void assertEqualsAndHashCode() {
         assertEquals(mState, mState2);
         assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java b/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
deleted file mode 100644
index 5664e0b..0000000
--- a/core/tests/coretests/src/android/view/InsetsVisibilitiesTest.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 static android.view.InsetsState.FIRST_TYPE;
-import static android.view.InsetsState.LAST_TYPE;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertTrue;
-
-import android.platform.test.annotations.Presubmit;
-import android.view.InsetsState.InternalInsetsType;
-
-import androidx.test.runner.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests for {@link InsetsVisibilities}.
- *
- * <p>Build/Install/Run:
- *  atest FrameworksCoreTests:InsetsVisibilities
- *
- * <p>This test class is a part of Window Manager Service tests and specified in
- * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
- */
-@Presubmit
-@RunWith(AndroidJUnit4.class)
-public class InsetsVisibilitiesTest {
-
-    @Test
-    public void testEquals() {
-        final InsetsVisibilities v1 = new InsetsVisibilities();
-        final InsetsVisibilities v2 = new InsetsVisibilities();
-        final InsetsVisibilities v3 = new InsetsVisibilities();
-        assertEquals(v1, v2);
-        assertEquals(v1, v3);
-
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            v1.setVisibility(type, false);
-            v2.setVisibility(type, false);
-        }
-        assertEquals(v1, v2);
-        assertNotEquals(v1, v3);
-
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            v1.setVisibility(type, true);
-            v2.setVisibility(type, true);
-        }
-        assertEquals(v1, v2);
-        assertNotEquals(v1, v3);
-    }
-
-    @Test
-    public void testSet() {
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            final InsetsVisibilities v1 = new InsetsVisibilities();
-            final InsetsVisibilities v2 = new InsetsVisibilities();
-
-            v1.setVisibility(type, true);
-            assertNotEquals(v1, v2);
-
-            v2.set(v1);
-            assertEquals(v1, v2);
-
-            v2.setVisibility(type, false);
-            assertNotEquals(v1, v2);
-
-            v1.set(v2);
-            assertEquals(v1, v2);
-        }
-    }
-
-    @Test
-    public void testCopyConstructor() {
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            final InsetsVisibilities v1 = new InsetsVisibilities();
-            v1.setVisibility(type, true);
-            final InsetsVisibilities v2 = new InsetsVisibilities(v1);
-            assertEquals(v1, v2);
-
-            v2.setVisibility(type, false);
-            assertNotEquals(v1, v2);
-        }
-    }
-
-    @Test
-    public void testGetterAndSetter() {
-        final InsetsVisibilities v1 = new InsetsVisibilities();
-        final InsetsVisibilities v2 = new InsetsVisibilities();
-
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            assertEquals(InsetsState.getDefaultVisibility(type), v1.getVisibility(type));
-        }
-
-        for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
-            v1.setVisibility(type, true);
-            assertTrue(v1.getVisibility(type));
-
-            v2.setVisibility(type, false);
-            assertFalse(v2.getVisibility(type));
-        }
-    }
-}
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index dd9634b..4fed396 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -39,13 +39,16 @@
 
     @Test
     public void systemWindowInsets_afterConsuming_isConsumed() {
-        assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, false, false, null)
+        assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
+                null, false, false, null, null, null, null,
+                WindowInsets.Type.systemBars(), false)
                 .consumeSystemWindowInsets().isConsumed());
     }
 
     @Test
     public void multiNullConstructor_isConsumed() {
-        assertTrue(new WindowInsets((Rect) null, null, false, false, null).isConsumed());
+        assertTrue(new WindowInsets(null, null, null, false, false, null, null, null, null,
+                WindowInsets.Type.systemBars(), false).isConsumed());
     }
 
     @Test
@@ -61,7 +64,8 @@
         WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
         WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
         WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
-                null, null, systemBars(), true /* compatIgnoreVisibility */);
+                null, null, DisplayShape.NONE, systemBars(),
+                true /* compatIgnoreVisibility */);
         assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
     }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
index ee1e10f..7cbf3ffa 100644
--- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
+++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java
@@ -263,10 +263,24 @@
     }
 
     private class MyAccessibilityProxy extends AccessibilityDisplayProxy {
-        // TODO(241429275): Will override A11yProxy methods in the future.
         MyAccessibilityProxy(int displayId,
                 @NonNull List<AccessibilityServiceInfo> serviceInfos) {
             super(displayId, Executors.newSingleThreadExecutor(), serviceInfos);
         }
+
+        @Override
+        public void onAccessibilityEvent(@NonNull AccessibilityEvent event) {
+
+        }
+
+        @Override
+        public void onProxyConnected() {
+
+        }
+
+        @Override
+        public void interrupt() {
+
+        }
     }
 }
diff --git a/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
new file mode 100644
index 0000000..281d677
--- /dev/null
+++ b/core/tests/coretests/src/android/window/SnapshotDrawerUtilsTest.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.window;
+
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager.TaskDescription;
+import android.content.ComponentName;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorSpace;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.hardware.HardwareBuffer;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.WindowInsets;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link SnapshotDrawerUtils}.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class SnapshotDrawerUtilsTest {
+
+    private SnapshotDrawerUtils.SnapshotSurface mSnapshotSurface;
+
+    private void setupSurface(int width, int height) {
+        setupSurface(width, height, new Rect(), FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, width, height));
+    }
+
+    private void setupSurface(int width, int height, Rect contentInsets,
+            int windowFlags, Rect taskBounds) {
+        // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
+        // this behavior set the taskSize to be the same as the taskBounds width and height. The
+        // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
+        // taken. We assume there is no aspect ratio mismatch between the screenshot and the
+        // taskBounds
+        assertEquals(width, taskBounds.width());
+        assertEquals(height, taskBounds.height());
+        Point taskSize = new Point(taskBounds.width(), taskBounds.height());
+
+        final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
+        TaskDescription taskDescription = createTaskDescription(Color.WHITE,
+                Color.RED, Color.BLUE);
+
+        mSnapshotSurface = new SnapshotDrawerUtils.SnapshotSurface(
+                new SurfaceControl(), snapshot, "Test", taskBounds);
+        mSnapshotSurface.initiateSystemBarPainter(windowFlags, 0, 0,
+                taskDescription, WindowInsets.Type.defaultVisible());
+    }
+
+    private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
+            Rect contentInsets) {
+        final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
+                1, HardwareBuffer.USAGE_CPU_READ_RARELY);
+        return new TaskSnapshot(
+                System.currentTimeMillis(),
+                new ComponentName("", ""), buffer,
+                ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
+                Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */,
+                false, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
+                0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
+    }
+
+    private static TaskDescription createTaskDescription(int background,
+            int statusBar, int navigationBar) {
+        final TaskDescription td = new TaskDescription();
+        td.setBackgroundColor(background);
+        td.setStatusBarColor(statusBar);
+        td.setNavigationBarColor(navigationBar);
+        return td;
+    }
+
+    @Test
+    public void fillEmptyBackground_fillHorizontally() {
+        setupSurface(200, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(200);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
+        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_fillVertically() {
+        setupSurface(100, 200);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(200);
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
+        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_fillBoth() {
+        setupSurface(200, 200);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(200);
+        when(mockCanvas.getHeight()).thenReturn(200);
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
+        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_dontFill_sameSize() {
+        setupSurface(100, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void fillEmptyBackground_dontFill_bitmapLarger() {
+        setupSurface(100, 100);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 100, 90), mSnapshotSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_taskNotOnTop() {
+        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, new Rect(0, 50, 100, 150));
+        assertEquals(new Rect(0, 10, 100, 90), mSnapshotSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarLeft() {
+        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(10, 0, 100, 100), mSnapshotSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_navBarRight() {
+        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(0, 0, 90, 100), mSnapshotSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotCrop_waterfall() {
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, new Rect(0, 0, 100, 100));
+        assertEquals(new Rect(5, 0, 95, 90), mSnapshotSurface.calculateSnapshotCrop());
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 0, 10);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        assertEquals(new Rect(0, 0, 100, 80),
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame_navBarLeft() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(10, 10, 0, 0);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        assertEquals(new Rect(10, 0, 100, 90),
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
+    }
+
+    @Test
+    public void testCalculateSnapshotFrame_waterfall() {
+        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, new Rect(0, 0, 100, 100));
+        final Rect insets = new Rect(0, 10, 0, 10);
+        mSnapshotSurface.setFrames(new Rect(5, 0, 95, 100), insets);
+        assertEquals(new Rect(0, 0, 90, 90),
+                mSnapshotSurface.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
+    }
+
+    @Test
+    public void testDrawStatusBarBackground() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
+        verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
+    public void testDrawStatusBarBackground_nullFrame() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, null);
+        verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
+    }
+
+    @Test
+    public void testDrawStatusBarBackground_nope() {
+        setupSurface(100, 100);
+        final Rect insets = new Rect(0, 10, 10, 0);
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
+        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground() {
+        final Rect insets = new Rect(0, 10, 0, 10);
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_left() {
+        final Rect insets = new Rect(10, 10, 0, 0);
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
+    }
+
+    @Test
+    public void testDrawNavigationBarBackground_right() {
+        final Rect insets = new Rect(0, 10, 10, 0);
+        setupSurface(100, 100, insets, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
+                new Rect(0, 0, 100, 100));
+        mSnapshotSurface.setFrames(new Rect(0, 0, 100, 100), insets);
+        final Canvas mockCanvas = mock(Canvas.class);
+        when(mockCanvas.getWidth()).thenReturn(100);
+        when(mockCanvas.getHeight()).thenReturn(100);
+        mSnapshotSurface.drawNavigationBarBackground(mockCanvas);
+        verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
+    }
+}
diff --git a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
index f370ebd..9d6b29e 100644
--- a/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
+++ b/core/tests/coretests/src/android/window/WindowOnBackInvokedDispatcherTest.java
@@ -17,6 +17,7 @@
 package android.window;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
@@ -60,8 +61,8 @@
     private OnBackAnimationCallback mCallback1;
     @Mock
     private OnBackAnimationCallback mCallback2;
-    @Mock
-    private BackEvent mBackEvent;
+    private final BackMotionEvent mBackEvent = new BackMotionEvent(
+            0, 0, 0, BackEvent.EDGE_LEFT, null);
 
     @Before
     public void setUp() throws Exception {
@@ -89,12 +90,12 @@
                 captor.capture());
         captor.getAllValues().get(0).getCallback().onBackStarted(mBackEvent);
         waitForIdle();
-        verify(mCallback1).onBackStarted(mBackEvent);
+        verify(mCallback1).onBackStarted(any(BackEvent.class));
         verifyZeroInteractions(mCallback2);
 
         captor.getAllValues().get(1).getCallback().onBackStarted(mBackEvent);
         waitForIdle();
-        verify(mCallback2).onBackStarted(mBackEvent);
+        verify(mCallback2).onBackStarted(any(BackEvent.class));
         verifyNoMoreInteractions(mCallback1);
     }
 
@@ -114,7 +115,7 @@
         assertEquals(captor.getValue().getPriority(), OnBackInvokedDispatcher.PRIORITY_OVERLAY);
         captor.getValue().getCallback().onBackStarted(mBackEvent);
         waitForIdle();
-        verify(mCallback1).onBackStarted(mBackEvent);
+        verify(mCallback1).onBackStarted(any(BackEvent.class));
     }
 
     @Test
@@ -152,6 +153,6 @@
         verify(mWindowSession).setOnBackInvokedCallbackInfo(Mockito.eq(mWindow), captor.capture());
         captor.getValue().getCallback().onBackStarted(mBackEvent);
         waitForIdle();
-        verify(mCallback2).onBackStarted(mBackEvent);
+        verify(mCallback2).onBackStarted(any(BackEvent.class));
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java
index 875cd0b..eead4ed 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityOverrideData.java
@@ -16,9 +16,11 @@
 
 package com.android.internal.app;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
-import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.database.Cursor;
@@ -26,10 +28,12 @@
 import android.os.UserHandle;
 import android.util.Pair;
 
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.QuietModeManager;
 import com.android.internal.app.chooser.TargetInfo;
 import com.android.internal.logging.MetricsLogger;
 
-import java.util.List;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 
@@ -71,7 +75,10 @@
     public boolean isQuietModeEnabled;
     public boolean isWorkProfileUserRunning;
     public boolean isWorkProfileUserUnlocked;
-    public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector;
+    public Integer myUserId;
+    public QuietModeManager mQuietModeManager;
+    public MyUserIdProvider mMyUserIdProvider;
+    public CrossProfileIntentsChecker mCrossProfileIntentsChecker;
     public PackageManager packageManager;
 
     public void reset() {
@@ -95,14 +102,9 @@
         isQuietModeEnabled = false;
         isWorkProfileUserRunning = true;
         isWorkProfileUserUnlocked = true;
+        myUserId = null;
         packageManager = null;
-        multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() {
-            @Override
-            public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
-                    int targetUserId) {
-                return hasCrossProfileIntents;
-            }
-
+        mQuietModeManager = new QuietModeManager() {
             @Override
             public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
                 return isQuietModeEnabled;
@@ -113,7 +115,27 @@
                     UserHandle workProfileUserHandle) {
                 isQuietModeEnabled = enabled;
             }
+
+            @Override
+            public void markWorkProfileEnabledBroadcastReceived() {
+            }
+
+            @Override
+            public boolean isWaitingToEnableWorkProfile() {
+                return false;
+            }
         };
+
+        mMyUserIdProvider = new MyUserIdProvider() {
+            @Override
+            public int getMyUserId() {
+                return myUserId != null ? myUserId : UserHandle.myUserId();
+            }
+        };
+
+        mCrossProfileIntentsChecker = mock(CrossProfileIntentsChecker.class);
+        when(mCrossProfileIntentsChecker.hasCrossProfileIntents(any(), anyInt(), anyInt()))
+                .thenAnswer(invocation -> hasCrossProfileIntents);
     }
 
     private ChooserActivityOverrideData() {}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java
new file mode 100644
index 0000000..c6537c0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityWorkProfileTest.java
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.swipeUp;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.NO_BLOCKER;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.PERSONAL_PROFILE_ACCESS_BLOCKER;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.PERSONAL_PROFILE_SHARE_BLOCKER;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.WORK_PROFILE_ACCESS_BLOCKER;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.ExpectedBlocker.WORK_PROFILE_SHARE_BLOCKER;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.Tab.PERSONAL;
+import static com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.Tab.WORK;
+import static com.android.internal.app.ChooserWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.companion.DeviceFilter;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.ChooserActivityWorkProfileTest.TestCase.Tab;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@DeviceFilter.MediumType
+@RunWith(Parameterized.class)
+public class ChooserActivityWorkProfileTest {
+
+    private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
+            .getInstrumentation().getTargetContext().getUser();
+    private static final UserHandle WORK_USER_HANDLE = UserHandle.of(10);
+
+    @Rule
+    public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
+            new ActivityTestRule<>(ChooserWrapperActivity.class, false,
+                    false);
+    private final TestCase mTestCase;
+
+    public ChooserActivityWorkProfileTest(TestCase testCase) {
+        mTestCase = testCase;
+    }
+
+    @Before
+    public void cleanOverrideData() {
+        sOverrides.reset();
+    }
+
+    @Test
+    public void testBlocker() {
+        setUpPersonalAndWorkComponentInfos();
+        sOverrides.hasCrossProfileIntents = mTestCase.hasCrossProfileIntents();
+        sOverrides.myUserId = mTestCase.getMyUserHandle().getIdentifier();
+
+        launchActivity(mTestCase.getIsSendAction());
+        switchToTab(mTestCase.getTab());
+
+        switch (mTestCase.getExpectedBlocker()) {
+            case NO_BLOCKER:
+                assertNoBlockerDisplayed();
+                break;
+            case PERSONAL_PROFILE_SHARE_BLOCKER:
+                assertCantSharePersonalAppsBlockerDisplayed();
+                break;
+            case WORK_PROFILE_SHARE_BLOCKER:
+                assertCantShareWorkAppsBlockerDisplayed();
+                break;
+            case PERSONAL_PROFILE_ACCESS_BLOCKER:
+                assertCantAccessPersonalAppsBlockerDisplayed();
+                break;
+            case WORK_PROFILE_ACCESS_BLOCKER:
+                assertCantAccessWorkAppsBlockerDisplayed();
+                break;
+        }
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection tests() {
+        return Arrays.asList(
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+//                TODO(b/256869196) ChooserActivity goes into requestLayout loop
+//                new TestCase(
+//                        /* isSendAction= */ true,
+//                        /* hasCrossProfileIntents= */ false,
+//                        /* myUserHandle= */ WORK_USER_HANDLE,
+//                        /* tab= */ WORK,
+//                        /* expectedBlocker= */ NO_BLOCKER
+//                ),
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ WORK_PROFILE_SHARE_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+//                TODO(b/256869196) ChooserActivity goes into requestLayout loop
+//                new TestCase(
+//                        /* isSendAction= */ true,
+//                        /* hasCrossProfileIntents= */ false,
+//                        /* myUserHandle= */ WORK_USER_HANDLE,
+//                        /* tab= */ PERSONAL,
+//                        /* expectedBlocker= */ PERSONAL_PROFILE_SHARE_BLOCKER
+//                ),
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ true,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ WORK_PROFILE_ACCESS_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ PERSONAL_PROFILE_ACCESS_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* isSendAction= */ false,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                )
+        );
+    }
+
+    private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
+            int numberOfResults, int userId) {
+        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+        for (int i = 0; i < numberOfResults; i++) {
+            infoList.add(
+                    ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+        }
+        return infoList;
+    }
+
+    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
+        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+        for (int i = 0; i < numberOfResults; i++) {
+            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+        }
+        return infoList;
+    }
+
+    private void setUpPersonalAndWorkComponentInfos() {
+        // enable the work tab feature flag
+        ResolverActivity.ENABLE_TABBED_VIEW = true;
+        markWorkProfileUserAvailable();
+        int workProfileTargets = 4;
+        List<ResolvedComponentInfo> personalResolvedComponentInfos =
+                createResolvedComponentsForTestWithOtherProfile(3,
+                        /* userId */ WORK_USER_HANDLE.getIdentifier());
+        List<ResolvedComponentInfo> workResolvedComponentInfos =
+                createResolvedComponentsForTest(workProfileTargets);
+        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+    }
+
+    private void setupResolverControllers(
+            List<ResolvedComponentInfo> personalResolvedComponentInfos,
+            List<ResolvedComponentInfo> workResolvedComponentInfos) {
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class)))
+                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+        when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+        when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class),
+                eq(UserHandle.SYSTEM)))
+                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+    }
+
+    private void waitForIdle() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    private void markWorkProfileUserAvailable() {
+        ChooserWrapperActivity.sOverrides.workProfileUserHandle = WORK_USER_HANDLE;
+    }
+
+    private void assertCantAccessWorkAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_access_work_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertCantAccessPersonalAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_access_personal_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertCantShareWorkAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_share_with_work_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertCantSharePersonalAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_share_with_personal_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertNoBlockerDisplayed() {
+        try {
+            onView(withText(R.string.resolver_cross_profile_blocked))
+                    .check(matches(not(isDisplayed())));
+        } catch (NoMatchingViewException ignored) {
+        }
+    }
+
+    private void switchToTab(Tab tab) {
+        final int stringId = tab == Tab.WORK ? R.string.resolver_work_tab
+                : R.string.resolver_personal_tab;
+
+        onView(withText(stringId)).perform(click());
+        waitForIdle();
+
+        onView(withId(R.id.contentPanel))
+                .perform(swipeUp());
+        waitForIdle();
+    }
+
+    private Intent createTextIntent(boolean isSendAction) {
+        Intent sendIntent = new Intent();
+        if (isSendAction) {
+            sendIntent.setAction(Intent.ACTION_SEND);
+        }
+        sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
+        sendIntent.setType("text/plain");
+        return sendIntent;
+    }
+
+    private void launchActivity(boolean isSendAction) {
+        Intent sendIntent = createTextIntent(isSendAction);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, "Test"));
+        waitForIdle();
+    }
+
+    public static class TestCase {
+        private final boolean mIsSendAction;
+        private final boolean mHasCrossProfileIntents;
+        private final UserHandle mMyUserHandle;
+        private final Tab mTab;
+        private final ExpectedBlocker mExpectedBlocker;
+
+        public enum ExpectedBlocker {
+            NO_BLOCKER,
+            PERSONAL_PROFILE_SHARE_BLOCKER,
+            WORK_PROFILE_SHARE_BLOCKER,
+            PERSONAL_PROFILE_ACCESS_BLOCKER,
+            WORK_PROFILE_ACCESS_BLOCKER
+        }
+
+        public enum Tab {
+            WORK,
+            PERSONAL
+        }
+
+        public TestCase(boolean isSendAction, boolean hasCrossProfileIntents,
+                UserHandle myUserHandle, Tab tab, ExpectedBlocker expectedBlocker) {
+            mIsSendAction = isSendAction;
+            mHasCrossProfileIntents = hasCrossProfileIntents;
+            mMyUserHandle = myUserHandle;
+            mTab = tab;
+            mExpectedBlocker = expectedBlocker;
+        }
+
+        public boolean getIsSendAction() {
+            return mIsSendAction;
+        }
+
+        public boolean hasCrossProfileIntents() {
+            return mHasCrossProfileIntents;
+        }
+
+        public UserHandle getMyUserHandle() {
+            return mMyUserHandle;
+        }
+
+        public Tab getTab() {
+            return mTab;
+        }
+
+        public ExpectedBlocker getExpectedBlocker() {
+            return mExpectedBlocker;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder result = new StringBuilder("test");
+
+            if (mTab == WORK) {
+                result.append("WorkTab_");
+            } else {
+                result.append("PersonalTab_");
+            }
+
+            if (mIsSendAction) {
+                result.append("sendAction_");
+            } else {
+                result.append("notSendAction_");
+            }
+
+            if (mHasCrossProfileIntents) {
+                result.append("hasCrossProfileIntents_");
+            } else {
+                result.append("doesNotHaveCrossProfileIntents_");
+            }
+
+            if (mMyUserHandle.equals(PERSONAL_USER_HANDLE)) {
+                result.append("myUserIsPersonal_");
+            } else {
+                result.append("myUserIsWork_");
+            }
+
+            if (mExpectedBlocker == ExpectedBlocker.NO_BLOCKER) {
+                result.append("thenNoBlocker");
+            } else if (mExpectedBlocker == PERSONAL_PROFILE_ACCESS_BLOCKER) {
+                result.append("thenAccessBlockerOnPersonalProfile");
+            } else if (mExpectedBlocker == PERSONAL_PROFILE_SHARE_BLOCKER) {
+                result.append("thenShareBlockerOnPersonalProfile");
+            } else if (mExpectedBlocker == WORK_PROFILE_ACCESS_BLOCKER) {
+                result.append("thenAccessBlockerOnWorkProfile");
+            } else if (mExpectedBlocker == WORK_PROFILE_SHARE_BLOCKER) {
+                result.append("thenShareBlockerOnWorkProfile");
+            }
+
+            return result.toString();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 4c3235c..5dc0c8b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -16,6 +16,10 @@
 
 package com.android.internal.app;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.annotation.Nullable;
@@ -34,6 +38,8 @@
 import android.util.Pair;
 import android.util.Size;
 
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
 import com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter;
 import com.android.internal.app.chooser.DisplayResolveInfo;
 import com.android.internal.app.chooser.TargetInfo;
@@ -60,15 +66,6 @@
     }
 
     @Override
-    protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
-            Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed) {
-        AbstractMultiProfilePagerAdapter multiProfilePagerAdapter =
-                super.createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
-        multiProfilePagerAdapter.setInjector(sOverrides.multiPagerAdapterInjector);
-        return multiProfilePagerAdapter;
-    }
-
-    @Override
     public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents,
             Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed,
             ResolverListController resolverListController) {
@@ -135,6 +132,30 @@
     }
 
     @Override
+    protected MyUserIdProvider createMyUserIdProvider() {
+        if (sOverrides.mMyUserIdProvider != null) {
+            return sOverrides.mMyUserIdProvider;
+        }
+        return super.createMyUserIdProvider();
+    }
+
+    @Override
+    protected CrossProfileIntentsChecker createCrossProfileIntentsChecker() {
+        if (sOverrides.mCrossProfileIntentsChecker != null) {
+            return sOverrides.mCrossProfileIntentsChecker;
+        }
+        return super.createCrossProfileIntentsChecker();
+    }
+
+    @Override
+    protected AbstractMultiProfilePagerAdapter.QuietModeManager createQuietModeManager() {
+        if (sOverrides.mQuietModeManager != null) {
+            return sOverrides.mQuietModeManager;
+        }
+        return super.createQuietModeManager();
+    }
+
+    @Override
     public void safelyStartActivity(com.android.internal.app.chooser.TargetInfo cti) {
         if (sOverrides.onSafelyStartCallback != null &&
                 sOverrides.onSafelyStartCallback.apply(cti)) {
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverActivityWorkProfileTest.java b/core/tests/coretests/src/com/android/internal/app/ResolverActivityWorkProfileTest.java
new file mode 100644
index 0000000..ce68906
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverActivityWorkProfileTest.java
@@ -0,0 +1,429 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.app;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.action.ViewActions.click;
+import static androidx.test.espresso.action.ViewActions.swipeUp;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+
+import static com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.ExpectedBlocker.NO_BLOCKER;
+import static com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.ExpectedBlocker.PERSONAL_PROFILE_BLOCKER;
+import static com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.ExpectedBlocker.WORK_PROFILE_BLOCKER;
+import static com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.Tab.PERSONAL;
+import static com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.Tab.WORK;
+import static com.android.internal.app.ResolverWrapperActivity.sOverrides;
+
+import static org.hamcrest.CoreMatchers.not;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.annotation.Nullable;
+import android.companion.DeviceFilter;
+import android.content.Intent;
+import android.os.UserHandle;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.espresso.NoMatchingViewException;
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.internal.R;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.app.ResolverActivityWorkProfileTest.TestCase.Tab;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@DeviceFilter.MediumType
+@RunWith(Parameterized.class)
+public class ResolverActivityWorkProfileTest {
+
+    private static final UserHandle PERSONAL_USER_HANDLE = InstrumentationRegistry
+            .getInstrumentation().getTargetContext().getUser();
+    private static final UserHandle WORK_USER_HANDLE = UserHandle.of(10);
+
+    @Rule
+    public ActivityTestRule<ResolverWrapperActivity> mActivityRule =
+            new ActivityTestRule<>(ResolverWrapperActivity.class, false,
+                    false);
+    private final TestCase mTestCase;
+
+    public ResolverActivityWorkProfileTest(TestCase testCase) {
+        mTestCase = testCase;
+    }
+
+    @Before
+    public void cleanOverrideData() {
+        sOverrides.reset();
+    }
+
+    @Test
+    public void testBlocker() {
+        setUpPersonalAndWorkComponentInfos();
+        sOverrides.hasCrossProfileIntents = mTestCase.hasCrossProfileIntents();
+        sOverrides.myUserId = mTestCase.getMyUserHandle().getIdentifier();
+
+        launchActivity(/* callingUser= */ mTestCase.getExtraCallingUser());
+        switchToTab(mTestCase.getTab());
+
+        switch (mTestCase.getExpectedBlocker()) {
+            case NO_BLOCKER:
+                assertNoBlockerDisplayed();
+                break;
+            case PERSONAL_PROFILE_BLOCKER:
+                assertCantAccessPersonalAppsBlockerDisplayed();
+                break;
+            case WORK_PROFILE_BLOCKER:
+                assertCantAccessWorkAppsBlockerDisplayed();
+                break;
+        }
+    }
+
+    @Parameterized.Parameters(name = "{0}")
+    public static Collection tests() {
+        return Arrays.asList(
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ WORK_PROFILE_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ PERSONAL_PROFILE_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ null,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ WORK,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ WORK_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ true,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                ),
+                new TestCase(
+                        /* extraCallingUser= */ WORK_USER_HANDLE,
+                        /* hasCrossProfileIntents= */ false,
+                        /* myUserHandle= */ PERSONAL_USER_HANDLE,
+                        /* tab= */ PERSONAL,
+                        /* expectedBlocker= */ NO_BLOCKER
+                )
+        );
+    }
+
+    private List<ResolvedComponentInfo> createResolvedComponentsForTestWithOtherProfile(
+            int numberOfResults, int userId) {
+        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+        for (int i = 0; i < numberOfResults; i++) {
+            infoList.add(
+                    ResolverDataProvider.createResolvedComponentInfoWithOtherId(i, userId));
+        }
+        return infoList;
+    }
+
+    private List<ResolvedComponentInfo> createResolvedComponentsForTest(int numberOfResults) {
+        List<ResolvedComponentInfo> infoList = new ArrayList<>(numberOfResults);
+        for (int i = 0; i < numberOfResults; i++) {
+            infoList.add(ResolverDataProvider.createResolvedComponentInfo(i));
+        }
+        return infoList;
+    }
+
+    private void setUpPersonalAndWorkComponentInfos() {
+        // enable the work tab feature flag
+        ResolverActivity.ENABLE_TABBED_VIEW = true;
+        markWorkProfileUserAvailable();
+        int workProfileTargets = 4;
+        List<ResolvedComponentInfo> personalResolvedComponentInfos =
+                createResolvedComponentsForTestWithOtherProfile(3,
+                        /* userId */ WORK_USER_HANDLE.getIdentifier());
+        List<ResolvedComponentInfo> workResolvedComponentInfos =
+                createResolvedComponentsForTest(workProfileTargets);
+        setupResolverControllers(personalResolvedComponentInfos, workResolvedComponentInfos);
+    }
+
+    private void setupResolverControllers(
+            List<ResolvedComponentInfo> personalResolvedComponentInfos,
+            List<ResolvedComponentInfo> workResolvedComponentInfos) {
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class)))
+                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+        when(sOverrides.workResolverListController.getResolversForIntent(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class))).thenReturn(workResolvedComponentInfos);
+        when(sOverrides.workResolverListController.getResolversForIntentAsUser(Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.anyBoolean(),
+                Mockito.isA(List.class),
+                eq(UserHandle.SYSTEM)))
+                .thenReturn(new ArrayList<>(personalResolvedComponentInfos));
+    }
+
+    private void waitForIdle() {
+        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+    }
+
+    private void markWorkProfileUserAvailable() {
+        ResolverWrapperActivity.sOverrides.workProfileUserHandle = WORK_USER_HANDLE;
+    }
+
+    private void assertCantAccessWorkAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_access_work_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertCantAccessPersonalAppsBlockerDisplayed() {
+        onView(withText(R.string.resolver_cross_profile_blocked))
+                .check(matches(isDisplayed()));
+        onView(withText(R.string.resolver_cant_access_personal_apps_explanation))
+                .check(matches(isDisplayed()));
+    }
+
+    private void assertNoBlockerDisplayed() {
+        try {
+            onView(withText(R.string.resolver_cross_profile_blocked))
+                    .check(matches(not(isDisplayed())));
+        } catch (NoMatchingViewException ignored) {
+        }
+    }
+
+    private void switchToTab(Tab tab) {
+        final int stringId = tab == Tab.WORK ? R.string.resolver_work_tab
+                : R.string.resolver_personal_tab;
+
+        onView(withText(stringId)).perform(click());
+        waitForIdle();
+
+        onView(withId(R.id.contentPanel))
+                .perform(swipeUp());
+        waitForIdle();
+    }
+
+    private Intent createSendImageIntent() {
+        Intent sendIntent = new Intent();
+        sendIntent.setAction(Intent.ACTION_SEND);
+        sendIntent.putExtra(Intent.EXTRA_TEXT, "testing intent sending");
+        sendIntent.setType("image/jpeg");
+        return sendIntent;
+    }
+
+    private void launchActivity(UserHandle callingUser) {
+        Intent sendIntent = createSendImageIntent();
+        sendIntent.setType("TestType");
+
+        if (callingUser != null) {
+            sendIntent.putExtra(ResolverActivity.EXTRA_CALLING_USER, callingUser);
+        }
+
+        mActivityRule.launchActivity(sendIntent);
+        waitForIdle();
+    }
+
+    public static class TestCase {
+        @Nullable
+        private final UserHandle mExtraCallingUser;
+        private final boolean mHasCrossProfileIntents;
+        private final UserHandle mMyUserHandle;
+        private final Tab mTab;
+        private final ExpectedBlocker mExpectedBlocker;
+
+        public enum ExpectedBlocker {
+            NO_BLOCKER,
+            PERSONAL_PROFILE_BLOCKER,
+            WORK_PROFILE_BLOCKER
+        }
+
+        public enum Tab {
+            WORK,
+            PERSONAL
+        }
+
+        public TestCase(@Nullable UserHandle extraCallingUser, boolean hasCrossProfileIntents,
+                UserHandle myUserHandle, Tab tab, ExpectedBlocker expectedBlocker) {
+            mExtraCallingUser = extraCallingUser;
+            mHasCrossProfileIntents = hasCrossProfileIntents;
+            mMyUserHandle = myUserHandle;
+            mTab = tab;
+            mExpectedBlocker = expectedBlocker;
+        }
+
+        @Nullable
+        public UserHandle getExtraCallingUser() {
+            return mExtraCallingUser;
+        }
+
+        public boolean hasCrossProfileIntents() {
+            return mHasCrossProfileIntents;
+        }
+
+        public UserHandle getMyUserHandle() {
+            return mMyUserHandle;
+        }
+
+        public Tab getTab() {
+            return mTab;
+        }
+
+        public ExpectedBlocker getExpectedBlocker() {
+            return mExpectedBlocker;
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder result = new StringBuilder("test");
+
+            if (mTab == WORK) {
+                result.append("WorkTab_");
+            } else {
+                result.append("PersonalTab_");
+            }
+
+            if (mExtraCallingUser != null
+                    && !mExtraCallingUser.equals(PERSONAL_USER_HANDLE)) {
+                result.append("callingUserIsNonPersonal_");
+            } else {
+                result.append("callingUserIsPersonal_");
+            }
+
+            if (mHasCrossProfileIntents) {
+                result.append("hasCrossProfileIntents_");
+            } else {
+                result.append("doesNotHaveCrossProfileIntents_");
+            }
+
+            if (mMyUserHandle.equals(PERSONAL_USER_HANDLE)) {
+                result.append("myUserIsPersonal_");
+            } else {
+                result.append("myUserIsWork_");
+            }
+
+            if (mExpectedBlocker == ExpectedBlocker.NO_BLOCKER) {
+                result.append("thenNoBlocker");
+            } else if (mExpectedBlocker == ExpectedBlocker.PERSONAL_PROFILE_BLOCKER) {
+                result.append("thenBlockerOnPersonalProfile");
+            } else if (mExpectedBlocker == WORK_PROFILE_BLOCKER) {
+                result.append("thenBlockerOnWorkProfile");
+            }
+
+            return result.toString();
+        }
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
index 4cf9c3f..c778dfe 100644
--- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
@@ -27,6 +29,9 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.CrossProfileIntentsChecker;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.MyUserIdProvider;
+import com.android.internal.app.AbstractMultiProfilePagerAdapter.QuietModeManager;
 import com.android.internal.app.chooser.TargetInfo;
 
 import java.util.List;
@@ -52,12 +57,27 @@
     }
 
     @Override
-    protected AbstractMultiProfilePagerAdapter createMultiProfilePagerAdapter(
-            Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed) {
-        AbstractMultiProfilePagerAdapter multiProfilePagerAdapter =
-                super.createMultiProfilePagerAdapter(initialIntents, rList, filterLastUsed);
-        multiProfilePagerAdapter.setInjector(sOverrides.multiPagerAdapterInjector);
-        return multiProfilePagerAdapter;
+    protected MyUserIdProvider createMyUserIdProvider() {
+        if (sOverrides.mMyUserIdProvider != null) {
+            return sOverrides.mMyUserIdProvider;
+        }
+        return super.createMyUserIdProvider();
+    }
+
+    @Override
+    protected CrossProfileIntentsChecker createCrossProfileIntentsChecker() {
+        if (sOverrides.mCrossProfileIntentsChecker != null) {
+            return sOverrides.mCrossProfileIntentsChecker;
+        }
+        return super.createCrossProfileIntentsChecker();
+    }
+
+    @Override
+    protected QuietModeManager createQuietModeManager() {
+        if (sOverrides.mQuietModeManager != null) {
+            return sOverrides.mQuietModeManager;
+        }
+        return super.createQuietModeManager();
     }
 
     ResolverWrapperAdapter getAdapter() {
@@ -137,9 +157,12 @@
         public ResolverListController workResolverListController;
         public Boolean isVoiceInteraction;
         public UserHandle workProfileUserHandle;
+        public Integer myUserId;
         public boolean hasCrossProfileIntents;
         public boolean isQuietModeEnabled;
-        public AbstractMultiProfilePagerAdapter.Injector multiPagerAdapterInjector;
+        public QuietModeManager mQuietModeManager;
+        public MyUserIdProvider mMyUserIdProvider;
+        public CrossProfileIntentsChecker mCrossProfileIntentsChecker;
 
         public void reset() {
             onSafelyStartCallback = null;
@@ -148,15 +171,11 @@
             resolverListController = mock(ResolverListController.class);
             workResolverListController = mock(ResolverListController.class);
             workProfileUserHandle = null;
+            myUserId = null;
             hasCrossProfileIntents = true;
             isQuietModeEnabled = false;
-            multiPagerAdapterInjector = new AbstractMultiProfilePagerAdapter.Injector() {
-                @Override
-                public boolean hasCrossProfileIntents(List<Intent> intents, int sourceUserId,
-                        int targetUserId) {
-                    return hasCrossProfileIntents;
-                }
 
+            mQuietModeManager = new QuietModeManager() {
                 @Override
                 public boolean isQuietModeEnabled(UserHandle workProfileUserHandle) {
                     return isQuietModeEnabled;
@@ -167,7 +186,27 @@
                         UserHandle workProfileUserHandle) {
                     isQuietModeEnabled = enabled;
                 }
+
+                @Override
+                public void markWorkProfileEnabledBroadcastReceived() {
+                }
+
+                @Override
+                public boolean isWaitingToEnableWorkProfile() {
+                    return false;
+                }
             };
+
+            mMyUserIdProvider = new MyUserIdProvider() {
+                @Override
+                public int getMyUserId() {
+                    return myUserId != null ? myUserId : UserHandle.myUserId();
+                }
+            };
+
+            mCrossProfileIntentsChecker = mock(CrossProfileIntentsChecker.class);
+            when(mCrossProfileIntentsChecker.hasCrossProfileIntents(any(), anyInt(), anyInt()))
+                    .thenAnswer(invocation -> hasCrossProfileIntents);
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
index caec365..0f30cfe 100644
--- a/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
+++ b/core/tests/coretests/src/com/android/internal/content/res/OverlayConfigTest.java
@@ -286,6 +286,39 @@
     }
 
     @Test
+    public void testPartialConfigPartitionPrecedence() throws IOException {
+        createFile("/odm/overlay/config/config.xml",
+                "<config>"
+                        + "  <overlay package=\"two\" enabled=\"true\" />"
+                        + "</config>");
+
+        mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
+                1);
+        mScannerRule.addOverlay(createFile("/odm/overlay/two.apk"), "two");
+        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three", "android", 0,
+                true, 0);
+
+        final OverlayConfig overlayConfig = createConfigImpl();
+        assertConfig(overlayConfig, "one", false, true, 0);
+        assertConfig(overlayConfig, "two", true, true, 1);
+        assertConfig(overlayConfig, "three", false, true, 2);
+    }
+
+    @Test
+    public void testNoConfigPartitionPrecedence() throws IOException {
+        mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
+                1);
+        mScannerRule.addOverlay(createFile("/odm/overlay/two.apk"), "two", "android", 0, true, 2);
+        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three", "android", 0,
+                true, 0);
+
+        final OverlayConfig overlayConfig = createConfigImpl();
+        assertConfig(overlayConfig, "one", false, true, 0);
+        assertConfig(overlayConfig, "two", false, true, 1);
+        assertConfig(overlayConfig, "three", false, true, 2);
+    }
+
+    @Test
     public void testImmutable() throws IOException {
         createFile("/product/overlay/config/config.xml",
                 "<config>"
@@ -507,37 +540,6 @@
     }
 
     @Test
-    public void testNoConfigsAllowPartitionReordering() throws IOException {
-        mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
-                1);
-        mScannerRule.addOverlay(createFile("/product/overlay/two.apk"), "two", "android", 0, true,
-                0);
-
-        final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", false, true, 1);
-        assertConfig(overlayConfig, "two", false, true, 0);
-    }
-
-    @Test
-    public void testConfigDisablesPartitionReordering() throws IOException {
-        createFile("/odm/overlay/config/config.xml",
-                "<config>"
-                        + "  <overlay package=\"two\" enabled=\"true\" />"
-                        + "</config>");
-
-        mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
-                1);
-        mScannerRule.addOverlay(createFile("/odm/overlay/two.apk"), "two");
-        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three", "android", 0,
-                true, 0);
-
-        final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", false, true, 0);
-        assertConfig(overlayConfig, "two", true, true, 1);
-        assertConfig(overlayConfig, "three", false, true, 2);
-    }
-
-    @Test
     public void testStaticOverlayOutsideOverlayDir() throws IOException {
         mScannerRule.addOverlay(createFile("/product/app/one.apk"), "one", "android", 0, true, 0);
 
@@ -550,7 +552,7 @@
     @Test
     public void testSortStaticOverlaysDifferentTargets() throws IOException {
         mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "other", 0, true, 0);
-        mScannerRule.addOverlay(createFile("/product/overlay/two.apk"), "two", "android", 0, true,
+        mScannerRule.addOverlay(createFile("/vendor/overlay/two.apk"), "two", "android", 0, true,
                 0);
 
         final OverlayConfig overlayConfig = createConfigImpl();
@@ -559,15 +561,33 @@
     }
 
     @Test
+    public void testSortStaticOverlaysDifferentPartitions() throws IOException {
+        mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
+                2);
+        mScannerRule.addOverlay(createFile("/vendor/overlay/two.apk"), "two", "android", 0, true,
+                3);
+        mScannerRule.addOverlay(createFile("/product/overlay/three.apk"), "three", "android", 0,
+                true, 0);
+        mScannerRule.addOverlay(createFile("/product/overlay/four.apk"), "four", "android", 0,
+                true, 1);
+
+        final OverlayConfig overlayConfig = createConfigImpl();
+        assertConfig(overlayConfig, "one", false, true, 0);
+        assertConfig(overlayConfig, "two", false, true, 1);
+        assertConfig(overlayConfig, "three", false, true, 2);
+        assertConfig(overlayConfig, "four", false, true, 3);
+    }
+
+    @Test
     public void testSortStaticOverlaysSamePriority() throws IOException {
         mScannerRule.addOverlay(createFile("/vendor/overlay/one.apk"), "one", "android", 0, true,
                 0);
-        mScannerRule.addOverlay(createFile("/product/overlay/two.apk"), "two", "android", 0, true,
+        mScannerRule.addOverlay(createFile("/vendor/overlay/two.apk"), "two", "android", 0, true,
                 0);
 
         final OverlayConfig overlayConfig = createConfigImpl();
-        assertConfig(overlayConfig, "one", false, true, 1);
-        assertConfig(overlayConfig, "two", false, true, 0);
+        assertConfig(overlayConfig, "one", false, true, 0);
+        assertConfig(overlayConfig, "two", false, true, 1);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index d10f173..4d4ec35 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -168,7 +168,8 @@
     }
 
     private WindowInsets insetsWith(Insets content, DisplayCutout cutout) {
-        return new WindowInsets(content.toRect(), null, false, false, cutout);
+        return new WindowInsets(WindowInsets.createCompatTypeMap(content.toRect()), null, null,
+                false, false, cutout, null, null, null, WindowInsets.Type.systemBars(), false);
     }
 
     private ViewGroup createViewGroupWithId(int id) {
diff --git a/core/tests/fuzzers/FuzzService/Android.bp b/core/tests/fuzzers/FuzzService/Android.bp
new file mode 100644
index 0000000..5093185
--- /dev/null
+++ b/core/tests/fuzzers/FuzzService/Android.bp
@@ -0,0 +1,28 @@
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library {
+    name: "random_parcel_lib",
+    srcs: ["FuzzBinder.java"],
+}
+
+cc_library_shared {
+    name: "librandom_parcel_jni",
+    defaults: ["service_fuzzer_defaults"],
+    srcs: [
+        "random_parcel_jni.cpp",
+    ],
+    shared_libs: [
+        "libandroid_runtime",
+        "libbase",
+        "liblog",
+    ],
+    static_libs: [
+        "libnativehelper_lazy",
+        "libbinder_random_parcel",
+    ],
+    cflags: [
+        "-Wno-unused-parameter",
+    ],
+}
diff --git a/core/tests/fuzzers/FuzzService/FuzzBinder.java b/core/tests/fuzzers/FuzzService/FuzzBinder.java
new file mode 100644
index 0000000..52aafeb
--- /dev/null
+++ b/core/tests/fuzzers/FuzzService/FuzzBinder.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 randomparcel;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class FuzzBinder {
+    static {
+        System.loadLibrary("random_parcel_jni");
+    }
+
+    // DO NOT REUSE: This API should be called from fuzzer to setup JNI dependencies from
+    // libandroid_runtime. THIS IS WORKAROUND. Please file a bug if you need to use this.
+    public static void init() {
+        System.loadLibrary("android_runtime");
+        registerNatives();
+    }
+
+    // This API automatically fuzzes provided service
+    public static void fuzzService(IBinder binder, byte[] data) {
+        fuzzServiceInternal(binder, data);
+    }
+
+    // This API creates random parcel object
+    public static void createRandomParcel(Parcel parcel, byte[] data) {
+        getRandomParcel(parcel, data);
+    }
+
+    private static native void fuzzServiceInternal(IBinder binder, byte[] data);
+    private static native void getRandomParcel(Parcel parcel, byte[] data);
+    private static native int registerNatives();
+}
diff --git a/core/tests/fuzzers/FuzzService/random_parcel_jni.cpp b/core/tests/fuzzers/FuzzService/random_parcel_jni.cpp
new file mode 100644
index 0000000..dbeae87
--- /dev/null
+++ b/core/tests/fuzzers/FuzzService/random_parcel_jni.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "random_parcel_jni.h"
+#include <android_util_Binder.h>
+#include <android_os_Parcel.h>
+#include <fuzzbinder/libbinder_driver.h>
+#include <fuzzbinder/random_parcel.h>
+#include <fuzzer/FuzzedDataProvider.h>
+using namespace android;
+
+// JNI interface for fuzzService
+JNIEXPORT void JNICALL Java_randomparcel_FuzzBinder_fuzzServiceInternal(JNIEnv *env, jobject thiz, jobject javaBinder, jbyteArray fuzzData) {
+    size_t len = static_cast<size_t>(env->GetArrayLength(fuzzData));
+    uint8_t data[len];
+    env->GetByteArrayRegion(fuzzData, 0, len, reinterpret_cast<jbyte*>(data));
+
+    FuzzedDataProvider provider(data, len);
+    sp<IBinder> binder = android::ibinderForJavaObject(env, javaBinder);
+    fuzzService(binder, std::move(provider));
+}
+
+// API used by AIDL fuzzers to access JNI functions from libandroid_runtime.
+JNIEXPORT jint JNICALL Java_randomparcel_FuzzBinder_registerNatives(JNIEnv* env) {
+    return registerFrameworkNatives(env);
+}
+
+JNIEXPORT void JNICALL Java_randomparcel_FuzzBinder_getRandomParcel(JNIEnv *env, jobject thiz, jobject jparcel, jbyteArray fuzzData) {
+    size_t len = static_cast<size_t>(env->GetArrayLength(fuzzData));
+    uint8_t data[len];
+    env->GetByteArrayRegion(fuzzData, 0, len, reinterpret_cast<jbyte*>(data));
+
+    FuzzedDataProvider provider(data, len);
+    RandomParcelOptions options;
+
+    Parcel* parcel = parcelForJavaObject(env, jparcel);
+    fillRandomParcel(parcel, std::move(provider), &options);
+}
diff --git a/core/tests/fuzzers/FuzzService/random_parcel_jni.h b/core/tests/fuzzers/FuzzService/random_parcel_jni.h
new file mode 100644
index 0000000..bc18b2f
--- /dev/null
+++ b/core/tests/fuzzers/FuzzService/random_parcel_jni.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <jni.h>
+
+extern "C" {
+    JNIEXPORT void JNICALL Java_randomparcel_FuzzBinder_fuzzServiceInternal(JNIEnv *env, jobject thiz, jobject javaBinder, jbyteArray fuzzData);
+
+    // Function to register libandroid_runtime JNI functions with java env.
+    JNIEXPORT jint JNICALL Java_randomparcel_FuzzBinder_registerNatives(JNIEnv* env);
+
+    // Function from AndroidRuntime
+    jint registerFrameworkNatives(JNIEnv* env);
+
+    JNIEXPORT void JNICALL Java_randomparcel_FuzzBinder_getRandomParcel(JNIEnv *env, jobject thiz, jobject parcel, jbyteArray fuzzData);
+}
diff --git a/core/tests/fuzzers/OWNERS b/core/tests/fuzzers/OWNERS
new file mode 100644
index 0000000..b972ac0
--- /dev/null
+++ b/core/tests/fuzzers/OWNERS
@@ -0,0 +1,2 @@
+smoreland@google.com
+waghpawan@google.com
diff --git a/core/tests/fuzzers/java_service_fuzzer/Android.bp b/core/tests/fuzzers/java_service_fuzzer/Android.bp
new file mode 100644
index 0000000..625de14
--- /dev/null
+++ b/core/tests/fuzzers/java_service_fuzzer/Android.bp
@@ -0,0 +1,40 @@
+package {
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+aidl_interface {
+    name: "fuzzTestInterface",
+    srcs: ["fuzztest/ITestService.aidl"],
+    unstable: true,
+    backend: {
+        java: {
+            enabled: true,
+        },
+    },
+}
+
+java_fuzz {
+    name: "java_binder_service_fuzzer",
+    srcs: [
+        "ServiceFuzzer.java",
+        "TestService.java",
+        ":framework-core-sources-for-fuzzers",
+    ],
+    static_libs: [
+        "jazzer",
+        "fuzzTestInterface-java",
+        "random_parcel_lib",
+    ],
+    jni_libs: [
+        "librandom_parcel_jni",
+        "libc++",
+        "libandroid_runtime",
+    ],
+    libs: [
+        "framework",
+        "unsupportedappusage",
+        "ext",
+        "framework-res",
+    ],
+    native_bridge_supported: true,
+}
diff --git a/core/tests/fuzzers/java_service_fuzzer/ServiceFuzzer.java b/core/tests/fuzzers/java_service_fuzzer/ServiceFuzzer.java
new file mode 100644
index 0000000..a6e0986
--- /dev/null
+++ b/core/tests/fuzzers/java_service_fuzzer/ServiceFuzzer.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import com.code_intelligence.jazzer.api.FuzzedDataProvider;
+
+import randomparcel.FuzzBinder;
+
+public class ServiceFuzzer {
+
+    static {
+        // Initialize fuzzService and JNI dependencies
+        FuzzBinder.init();
+    }
+
+    public static void fuzzerTestOneInput(FuzzedDataProvider data) {
+        TestService service = new TestService();
+        FuzzBinder.fuzzService(service, data.consumeRemainingAsBytes());
+    }
+}
diff --git a/core/tests/fuzzers/java_service_fuzzer/TestService.java b/core/tests/fuzzers/java_service_fuzzer/TestService.java
new file mode 100644
index 0000000..4404386
--- /dev/null
+++ b/core/tests/fuzzers/java_service_fuzzer/TestService.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import fuzztest.ITestService;
+
+public class TestService extends ITestService.Stub {
+
+    @Override
+    public boolean repeatData(boolean token) {
+        return token;
+    }
+}
diff --git a/core/tests/fuzzers/java_service_fuzzer/fuzztest/ITestService.aidl b/core/tests/fuzzers/java_service_fuzzer/fuzztest/ITestService.aidl
new file mode 100644
index 0000000..b766c9f
--- /dev/null
+++ b/core/tests/fuzzers/java_service_fuzzer/fuzztest/ITestService.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 fuzztest;
+
+interface ITestService {
+    boolean repeatData(boolean token);
+}
\ No newline at end of file
diff --git a/core/tests/mockingcoretests/src/android/view/DisplayTest.java b/core/tests/mockingcoretests/src/android/view/DisplayTest.java
index 0c939ec..9ccf3b3 100644
--- a/core/tests/mockingcoretests/src/android/view/DisplayTest.java
+++ b/core/tests/mockingcoretests/src/android/view/DisplayTest.java
@@ -27,6 +27,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertArrayEquals;
+
 import android.app.WindowConfiguration;
 import android.content.Context;
 import android.content.res.Resources;
@@ -399,6 +401,15 @@
         verifyRealMetricsMatchesBounds(display, sDeviceBoundsLandscape);
     }
 
+    @Test
+    public void testSupportedHdrTypesForDisplayModeAreSorted() {
+        int[] nonSortedHdrTypes = new int[]{3, 2, 1};
+        Display.Mode displayMode = new Display.Mode(0, 0, 0, 0, new float[0], nonSortedHdrTypes);
+
+        int[] sortedHdrTypes = new int[]{1, 2, 3};
+        assertArrayEquals(sortedHdrTypes, displayMode.getSupportedHdrTypes());
+    }
+
     // Given rotated display dimensions, calculate the letterboxed app bounds.
     private static Rect buildAppBounds(int displayWidth, int displayHeight) {
         final int midWidth = displayWidth / 2;
diff --git a/core/tests/overlaytests/device_self_targeting/Android.bp b/core/tests/overlaytests/device_self_targeting/Android.bp
new file mode 100644
index 0000000..063c569
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/Android.bp
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test {
+    name: "SelfTargetingOverlayDeviceTests",
+    srcs: ["src/**/*.java"],
+    platform_apis: true,
+    static_libs: [
+        "androidx.test.rules",
+        "androidx.test.runner",
+        "androidx.test.ext.junit",
+        "mockito-target-minus-junit4",
+        "truth-prebuilt",
+    ],
+
+    optimize: {
+        enabled: false,
+    },
+    test_suites: ["device-tests"],
+}
diff --git a/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml b/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml
new file mode 100644
index 0000000..c121bf2
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/AndroidManifest.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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.overlaytest.self_targeting">
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.overlaytest.self_targeting"
+        android:label="Self-Targeting resource overlay tests" />
+</manifest>
diff --git a/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp b/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp
new file mode 100644
index 0000000..aa7d642
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/drawable/mydrawable.webp
Binary files differ
diff --git a/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp b/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp
new file mode 100644
index 0000000..9126ae3
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/raw/overlay_drawable.webp
Binary files differ
diff --git a/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml b/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml
new file mode 100644
index 0000000..5cc214d
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/values/overlayable.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <overlayable name="PublicOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="public">
+            <item type="color" name="public_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="SignatureOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="signature">
+            <item type="color" name="mycolor" />
+            <item type="color" name="signature_overlayable_color" />
+            <item type="string" name="mystring" />
+            <item type="drawable" name="mydrawable" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="SystemAppOverlayable" actor="overlay://theme">
+        <!-- The app in system partition can overlay the below resources -->
+        <policy type="system">
+            <item type="color" name="system_app_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="OdmOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="odm">
+            <item type="color" name="odm_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="OemOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="oem">
+            <item type="color" name="oem_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="VendorOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="vendor">
+            <item type="color" name="vendor_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ProductOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="product">
+            <item type="color" name="product_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ActorOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="actor">
+            <item type="color" name="actor_overlayable_color" />
+        </policy>
+    </overlayable>
+
+    <overlayable name="ConfigOverlayable" actor="overlay://theme">
+        <!-- The app with the same signature can overlay the below resources -->
+        <policy type="config_signature">
+            <item type="color" name="config_overlayable_color" />
+        </policy>
+    </overlayable>
+
+</resources>
diff --git a/core/tests/overlaytests/device_self_targeting/res/values/values.xml b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
new file mode 100644
index 0000000..d82de97
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/res/values/values.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="mycolor">#ff112233</color>
+    <string name="mystring">hello</string>
+
+    <color name="public_overlayable_color">#000</color>
+    <color name="signature_overlayable_color">#000</color>
+    <color name="system_app_overlayable_color">#000</color>
+    <color name="odm_overlayable_color">#000</color>
+    <color name="oem_overlayable_color">#000</color>
+    <color name="vendor_overlayable_color">#000</color>
+    <color name="product_overlayable_color">#000</color>
+    <color name="actor_overlayable_color">#000</color>
+    <color name="config_overlayable_color">#000</color>
+</resources>
diff --git a/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
new file mode 100644
index 0000000..40d0bef
--- /dev/null
+++ b/core/tests/overlaytests/device_self_targeting/src/com/android/overlaytest/OverlayManagerImplTest.java
@@ -0,0 +1,679 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.overlaytest;
+
+import static android.content.Context.MODE_PRIVATE;
+import static android.content.pm.PackageManager.SIGNATURE_NO_MATCH;
+
+import static com.android.internal.content.om.OverlayManagerImpl.SELF_TARGET;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.om.FabricatedOverlay;
+import android.content.om.OverlayInfo;
+import android.content.om.OverlayManagerTransaction;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.graphics.Color;
+import android.os.FabricatedOverlayInternal;
+import android.os.FabricatedOverlayInternalEntry;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Pair;
+import android.util.TypedValue;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.content.om.OverlayManagerImpl;
+import com.android.overlaytest.self_targeting.R;
+
+import com.google.common.truth.Expect;
+import com.google.common.truth.Truth;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This test class verify the interfaces of {@link
+ * com.android.internal.content.om.OverlayManagerImpl}.
+ */
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerImplTest {
+    private static final String TAG = "OverlayManagerImplTest";
+
+    private static final String TARGET_COLOR_RES = "color/mycolor";
+    private static final String TARGET_STRING_RES = "string/mystring";
+    private static final String TARGET_DRAWABLE_RES = "drawable/mydrawable";
+    private static final String PUBLIC_OVERLAYABLE = "PublicOverlayable";
+    private static final String SIGNATURE_OVERLAYABLE = "SignatureOverlayable";
+    private static final String SYSTEM_APP_OVERLAYABLE = "SystemAppOverlayable";
+    private static final String ODM_OVERLAYABLE = "OdmOverlayable";
+    private static final String OEM_OVERLAYABLE = "OemOverlayable";
+    private static final String VENDOR_OVERLAYABLE = "VendorOverlayable";
+    private static final String PRODUCT_OVERLAYABLE = "ProductOverlayable";
+    private static final String ACTOR_OVERLAYABLE = "ActorOverlayable";
+    private static final String CONFIG_OVERLAYABLE = "ConfigOverlayable";
+
+    private Context mContext;
+    private OverlayManagerImpl mOverlayManagerImpl;
+    private String mOverlayName;
+
+    private PackageManager mMockPackageManager;
+    private ApplicationInfo mMockApplicationInfo;
+
+    @Rule public TestName mTestName = new TestName();
+
+    @Rule public Expect expect = Expect.create();
+
+    private void clearDir() throws IOException {
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        final Path basePath = context.getDir(SELF_TARGET, MODE_PRIVATE).toPath();
+        Files.walkFileTree(
+                basePath,
+                new SimpleFileVisitor<>() {
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                            throws IOException {
+                        if (!file.toFile().delete()) {
+                            Log.w(TAG, "Failed to delete file " + file);
+                        }
+                        return super.visitFile(file, attrs);
+                    }
+
+                    @Override
+                    public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                            throws IOException {
+                        if (!dir.toFile().delete()) {
+                            Log.w(TAG, "Failed to delete dir " + dir);
+                        }
+                        return super.postVisitDirectory(dir, exc);
+                    }
+                });
+    }
+
+    @Before
+    public void setUp() throws IOException {
+        clearDir();
+        mOverlayName = mTestName.getMethodName();
+        final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        mMockApplicationInfo = mock(ApplicationInfo.class);
+        when(mMockApplicationInfo.isSystemApp()).thenReturn(false);
+        when(mMockApplicationInfo.isSystemExt()).thenReturn(false);
+        when(mMockApplicationInfo.isOdm()).thenReturn(false);
+        when(mMockApplicationInfo.isOem()).thenReturn(false);
+        when(mMockApplicationInfo.isVendor()).thenReturn(false);
+        when(mMockApplicationInfo.isProduct()).thenReturn(false);
+        when(mMockApplicationInfo.getBaseCodePath()).thenReturn(
+                context.getApplicationInfo().getBaseCodePath());
+        mMockApplicationInfo.sourceDir = context.getApplicationInfo().sourceDir;
+
+        mMockPackageManager = mock(PackageManager.class);
+        when(mMockPackageManager.checkSignatures(anyString(), anyString()))
+                .thenReturn(SIGNATURE_NO_MATCH);
+
+        mContext =
+                new ContextWrapper(context) {
+                    @Override
+                    public ApplicationInfo getApplicationInfo() {
+                        return mMockApplicationInfo;
+                    }
+
+                    @Override
+                    public PackageManager getPackageManager() {
+                        return mMockPackageManager;
+                    }
+                };
+
+        mOverlayManagerImpl = new OverlayManagerImpl(mContext);
+    }
+
+    @After
+    public void tearDown() throws IOException {
+        clearDir();
+    }
+
+    private <T> void addOverlayEntry(
+            FabricatedOverlayInternal overlayInternal,
+            @NonNull List<Pair<String, Pair<String, T>>> entryDefinitions) {
+        List<FabricatedOverlayInternalEntry> entries = new ArrayList<>();
+        for (Pair<String, Pair<String, T>> entryDefinition : entryDefinitions) {
+            FabricatedOverlayInternalEntry internalEntry = new FabricatedOverlayInternalEntry();
+            internalEntry.resourceName = entryDefinition.first;
+            internalEntry.configuration = entryDefinition.second.first;
+            if (entryDefinition.second.second instanceof ParcelFileDescriptor) {
+                internalEntry.binaryData = (ParcelFileDescriptor) entryDefinition.second.second;
+            } else if (entryDefinition.second.second instanceof String) {
+                internalEntry.stringData = (String) entryDefinition.second.second;
+                internalEntry.dataType = TypedValue.TYPE_STRING;
+            } else {
+                internalEntry.data = (int) entryDefinition.second.second;
+                internalEntry.dataType = TypedValue.TYPE_INT_COLOR_ARGB8;
+            }
+            entries.add(internalEntry);
+            overlayInternal.entries = entries;
+        }
+    }
+
+    private <T> FabricatedOverlayInternal createOverlayWithName(
+            @NonNull String overlayName,
+            @NonNull String targetOverlayable,
+            @NonNull String targetPackageName,
+            @NonNull List<Pair<String, Pair<String, T>>> entryDefinitions) {
+        final String packageName = mContext.getPackageName();
+        FabricatedOverlayInternal overlayInternal = new FabricatedOverlayInternal();
+        overlayInternal.overlayName = overlayName;
+        overlayInternal.targetPackageName = targetPackageName;
+        overlayInternal.targetOverlayable = targetOverlayable;
+        overlayInternal.packageName = packageName;
+
+        addOverlayEntry(overlayInternal, entryDefinitions);
+
+        return overlayInternal;
+    }
+
+    @Test
+    public void registerOverlay_forAndroidPackage_shouldFail() {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SYSTEM_APP_OVERLAYABLE,
+                        "android",
+                        List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
+
+        assertThrows(
+                "Wrong target package name",
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void getOverlayInfosForTarget_defaultShouldBeZero() {
+        List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        Truth.assertThat(overlayInfos.size()).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterNonExistingOverlay_shouldBeOk() {
+        mOverlayManagerImpl.unregisterFabricatedOverlay("NotExisting");
+    }
+
+    @Test
+    public void registerOverlay_createColorOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_createStringOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_STRING_RES, Pair.create(null, "HELLO"))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_createFileOverlay_shouldBeSavedInAndLoadFromFile()
+            throws IOException, PackageManager.NameNotFoundException {
+        ParcelFileDescriptor parcelFileDescriptor = mContext.getResources()
+                .openRawResourceFd(R.raw.overlay_drawable).getParcelFileDescriptor();
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_DRAWABLE_RES,
+                                            Pair.create(null, parcelFileDescriptor))));
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void registerOverlay_notExistedResource_shouldFailWithoutSavingAnyFile()
+            throws IOException {
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create("color/not_existed", Pair.create(null, "HELLO"))));
+
+        assertThrows(IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(0);
+        final int[] fileCounts = new int[1];
+        Files.walkFileTree(
+                mContext.getDir(SELF_TARGET, MODE_PRIVATE).toPath(),
+                new SimpleFileVisitor<>() {
+                    @Override
+                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                            throws IOException {
+                        fileCounts[0]++;
+                        return super.visitFile(file, attrs);
+                    }
+                });
+        expect.that(fileCounts[0]).isEqualTo(0);
+    }
+
+    @Test
+    public void registerMultipleOverlays_shouldMatchTheNumberOfOverlays()
+            throws IOException, PackageManager.NameNotFoundException {
+        final String secondOverlayName = mOverlayName + "2nd";
+        final int initNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int firstNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        overlayInternal =
+                createOverlayWithName(
+                        secondOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int secondNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        mOverlayManagerImpl.unregisterFabricatedOverlay(mOverlayName);
+        mOverlayManagerImpl.unregisterFabricatedOverlay(secondOverlayName);
+        final int finalNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        expect.that(initNumberOfOverlays).isEqualTo(0);
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        expect.that(secondNumberOfOverlays).isEqualTo(2);
+        expect.that(finalNumberOfOverlays).isEqualTo(0);
+    }
+
+    @Test
+    public void unregisterOverlay_withIllegalOverlayName_shouldFail() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.unregisterFabricatedOverlay("../../etc/password"));
+    }
+
+    @Test
+    public void registerTheSameOverlay_shouldNotIncreaseTheNumberOfOverlays()
+            throws IOException, PackageManager.NameNotFoundException {
+        final int initNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        FabricatedOverlayInternal overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int firstNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        overlayInternal =
+                createOverlayWithName(
+                        mOverlayName,
+                        SIGNATURE_OVERLAYABLE,
+                        mContext.getPackageName(),
+                        List.of(Pair.create(TARGET_COLOR_RES, Pair.create(null, Color.WHITE))));
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+        final int secondNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+        mOverlayManagerImpl.unregisterFabricatedOverlay(mOverlayName);
+        final int finalNumberOfOverlays =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size();
+
+        expect.that(initNumberOfOverlays).isEqualTo(0);
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        expect.that(secondNumberOfOverlays).isEqualTo(1);
+        expect.that(finalNumberOfOverlays).isEqualTo(0);
+    }
+
+    @Test
+    public void registerOverlay_packageNotOwnedBySelf_shouldFail() {
+        FabricatedOverlayInternal overlayInternal = new FabricatedOverlayInternal();
+        overlayInternal.packageName = "com.android.systemui";
+        overlayInternal.overlayName = mOverlayName;
+        overlayInternal.targetOverlayable = "non-existed-target-overlayable";
+        overlayInternal.targetPackageName = mContext.getPackageName();
+        addOverlayEntry(
+                overlayInternal,
+                List.of(Pair.create("color/white", Pair.create(null, Color.BLACK))));
+
+        assertThrows(
+                "The context doesn't own the package",
+                IllegalArgumentException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void ensureBaseDir_forOtherPackage_shouldFail()
+            throws PackageManager.NameNotFoundException {
+        final Context fakeContext =
+                mContext.createPackageContext("com.android.systemui", 0 /* flags */);
+        final OverlayManagerImpl overlayManagerImpl = new OverlayManagerImpl(fakeContext);
+
+        assertThrows(IllegalArgumentException.class, overlayManagerImpl::ensureBaseDir);
+    }
+
+    @Test
+    public void commit_withNullTransaction_shouldFail() {
+        assertThrows(NullPointerException.class, () -> mOverlayManagerImpl.commit(null));
+    }
+
+    @Test
+    public void commitRegisterOverlay_fromOtherBuilder_shouldWork()
+            throws PackageManager.NameNotFoundException, IOException {
+        FabricatedOverlay overlay =
+                new FabricatedOverlay.Builder(
+                                mContext.getPackageName(), mOverlayName, mContext.getPackageName())
+                        .setTargetOverlayable(SIGNATURE_OVERLAYABLE)
+                        .setResourceValue(
+                                TARGET_COLOR_RES, TypedValue.TYPE_INT_COLOR_ARGB8, Color.WHITE)
+                        .build();
+        OverlayManagerTransaction transaction =
+                new OverlayManagerTransaction.Builder().registerFabricatedOverlay(overlay).build();
+
+        mOverlayManagerImpl.commit(transaction);
+
+        final List<OverlayInfo> overlayInfos =
+                mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName());
+        final int firstNumberOfOverlays = overlayInfos.size();
+        expect.that(firstNumberOfOverlays).isEqualTo(1);
+        final OverlayInfo overlayInfo = overlayInfos.get(0);
+        expect.that(overlayInfo).isNotNull();
+        Truth.assertThat(expect.hasFailures()).isFalse();
+        expect.that(overlayInfo.isFabricated()).isTrue();
+        expect.that(overlayInfo.getOverlayName()).isEqualTo(mOverlayName);
+        expect.that(overlayInfo.getPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getTargetPackageName()).isEqualTo(mContext.getPackageName());
+        expect.that(overlayInfo.getUserId()).isEqualTo(mContext.getUserId());
+    }
+
+    @Test
+    public void newOverlayManagerImpl_forOtherUser_shouldFail() {
+        Context fakeContext =
+                new ContextWrapper(mContext) {
+                    @Override
+                    public UserHandle getUser() {
+                        return UserHandle.of(100);
+                    }
+
+                    @Override
+                    public int getUserId() {
+                        return 100;
+                    }
+                };
+
+        assertThrows(SecurityException.class, () -> new OverlayManagerImpl(fakeContext));
+    }
+
+    FabricatedOverlayInternal prepareFabricatedOverlayInternal(
+            String targetOverlayableName, String targetEntryName) {
+        return createOverlayWithName(
+                mOverlayName,
+                targetOverlayableName,
+                mContext.getPackageName(),
+                List.of(
+                        Pair.create(
+                                targetEntryName,
+                                Pair.create(null, Color.WHITE))));
+    }
+
+    @Test
+    public void registerOverlayOnSystemOverlayable_selfIsNotSystemApp_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                SYSTEM_APP_OVERLAYABLE,
+                "color/system_app_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnOdmOverlayable_selfIsNotOdm_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ODM_OVERLAYABLE,
+                "color/odm_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnOemOverlayable_selfIsNotOem_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                OEM_OVERLAYABLE,
+                "color/oem_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnVendorOverlayable_selfIsNotVendor_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                VENDOR_OVERLAYABLE,
+                "color/vendor_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnProductOverlayable_selfIsNotProduct_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PRODUCT_OVERLAYABLE,
+                "color/product_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnActorOverlayable_notSupport_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ACTOR_OVERLAYABLE,
+                "color/actor_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnConfigOverlayable_notSupport_shouldFail() {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                CONFIG_OVERLAYABLE,
+                "color/config_overlayable_color");
+
+        assertThrows(
+                IOException.class,
+                () -> mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal));
+    }
+
+    @Test
+    public void registerOverlayOnPublicOverlayable_shouldAlwaysSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PUBLIC_OVERLAYABLE,
+                "color/public_overlayable_color");
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnSystemOverlayable_selfIsSystemApp_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                SYSTEM_APP_OVERLAYABLE,
+                "color/system_app_overlayable_color");
+        when(mMockApplicationInfo.isSystemApp()).thenReturn(true);
+        when(mMockApplicationInfo.isSystemExt()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnOdmOverlayable_selfIsOdm_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                ODM_OVERLAYABLE,
+                "color/odm_overlayable_color");
+        when(mMockApplicationInfo.isOdm()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnOemOverlayable_selfIsOem_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                OEM_OVERLAYABLE,
+                "color/oem_overlayable_color");
+        when(mMockApplicationInfo.isOem()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnVendorOverlayable_selfIsVendor_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                VENDOR_OVERLAYABLE,
+                "color/vendor_overlayable_color");
+        when(mMockApplicationInfo.isVendor()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+
+    @Test
+    public void registerOverlayOnProductOverlayable_selfIsProduct_shouldSucceed()
+            throws PackageManager.NameNotFoundException, IOException {
+        final FabricatedOverlayInternal overlayInternal = prepareFabricatedOverlayInternal(
+                PRODUCT_OVERLAYABLE,
+                "color/product_overlayable_color");
+        when(mMockApplicationInfo.isProduct()).thenReturn(true);
+
+        mOverlayManagerImpl.registerFabricatedOverlay(overlayInternal);
+
+        assertThat(mOverlayManagerImpl.getOverlayInfosForTarget(mContext.getPackageName()).size())
+                .isEqualTo(1);
+    }
+}
diff --git a/core/tests/utiltests/src/android/util/IntArrayTest.java b/core/tests/utiltests/src/android/util/IntArrayTest.java
index a76c640..caa7312 100644
--- a/core/tests/utiltests/src/android/util/IntArrayTest.java
+++ b/core/tests/utiltests/src/android/util/IntArrayTest.java
@@ -16,8 +16,8 @@
 
 package android.util;
 
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -25,6 +25,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class IntArrayTest {
@@ -35,51 +37,65 @@
         a.add(1);
         a.add(2);
         a.add(3);
-        verify(new int[]{1, 2, 3}, a);
+        verify(a, 1, 2, 3);
 
         IntArray b = IntArray.fromArray(new int[]{4, 5, 6, 7, 8}, 3);
         a.addAll(b);
-        verify(new int[]{1, 2, 3, 4, 5, 6}, a);
+        verify(a, 1, 2, 3, 4, 5, 6);
 
         a.resize(2);
-        verify(new int[]{1, 2}, a);
+        verify(a, 1, 2);
 
         a.resize(8);
-        verify(new int[]{1, 2, 0, 0, 0, 0, 0, 0}, a);
+        verify(a, 1, 2, 0, 0, 0, 0, 0, 0);
 
         a.set(5, 10);
-        verify(new int[]{1, 2, 0, 0, 0, 10, 0, 0}, a);
+        verify(a, 1, 2, 0, 0, 0, 10, 0, 0);
 
         a.add(5, 20);
-        assertEquals(20, a.get(5));
-        assertEquals(5, a.indexOf(20));
-        verify(new int[]{1, 2, 0, 0, 0, 20, 10, 0, 0}, a);
+        assertThat(a.get(5)).isEqualTo(20);
+        assertThat(a.indexOf(20)).isEqualTo(5);
+        verify(a, 1, 2, 0, 0, 0, 20, 10, 0, 0);
 
-        assertEquals(-1, a.indexOf(99));
+        assertThat(a.indexOf(99)).isEqualTo(-1);
 
         a.resize(15);
         a.set(14, 30);
-        verify(new int[]{1, 2, 0, 0, 0, 20, 10, 0, 0, 0, 0, 0, 0, 0, 30}, a);
+        verify(a, 1, 2, 0, 0, 0, 20, 10, 0, 0, 0, 0, 0, 0, 0, 30);
 
         int[] backingArray = new int[]{1, 2, 3, 4};
         a = IntArray.wrap(backingArray);
         a.set(0, 10);
-        assertEquals(10, backingArray[0]);
+        assertThat(backingArray[0]).isEqualTo(10);
         backingArray[1] = 20;
         backingArray[2] = 30;
-        verify(backingArray, a);
-        assertEquals(2, a.indexOf(30));
+        verify(a, backingArray);
+        assertThat(a.indexOf(30)).isEqualTo(2);
 
         a.resize(2);
-        assertEquals(0, backingArray[2]);
-        assertEquals(0, backingArray[3]);
+        assertThat(backingArray[2]).isEqualTo(0);
+        assertThat(backingArray[3]).isEqualTo(0);
 
         a.add(50);
-        verify(new int[]{10, 20, 50}, a);
+        verify(a, 10, 20, 50);
     }
 
-    public void verify(int[] expected, IntArray intArray) {
-        assertEquals(expected.length, intArray.size());
-        assertArrayEquals(expected, intArray.toArray());
+    @Test
+    public void testToString() {
+        IntArray a = new IntArray(10);
+        a.add(4);
+        a.add(8);
+        a.add(15);
+        a.add(16);
+        a.add(23);
+        a.add(42);
+
+        assertWithMessage("toString()").that(a.toString()).contains("4, 8, 15, 16, 23, 42");
+        assertWithMessage("toString()").that(a.toString()).doesNotContain("0");
+    }
+
+    public void verify(IntArray intArray, int... expected) {
+        assertWithMessage("contents of %s", intArray).that(intArray.toArray()).asList()
+                .containsExactlyElementsIn(Arrays.stream(expected).boxed().toList());
     }
 }
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 4cc06e3..3346740 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -4171,6 +4171,12 @@
       "group": "WM_DEBUG_REMOTE_ANIMATIONS",
       "at": "com\/android\/server\/wm\/RemoteAnimationController.java"
     },
+    "1945495497": {
+      "message": "Focused window didn't have a valid surface drawn.",
+      "level": "DEBUG",
+      "group": "WM_DEBUG_BACK_PREVIEW",
+      "at": "com\/android\/server\/wm\/BackNavigationController.java"
+    },
     "1947239194": {
       "message": "Deferring rotation, still finishing previous rotation",
       "level": "VERBOSE",
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 215b60e..a43e225 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -371,6 +371,10 @@
 # key 413 "KEY_DIGITS"
 # key 414 "KEY_TEEN"
 # key 415 "KEY_TWEN"
+# key 418 "KEY_ZOOM_IN"
+key 418   ZOOM_IN
+# key 419 "KEY_ZOOM_OUT"
+key 419   ZOOM_OUT
 key 528 FOCUS
 
 key 429   CONTACTS
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 54d6428..e62ac46 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -96,7 +96,7 @@
     // These are also implemented in RecordingCanvas so that we can
     // selectively apply on them
     // Everything below here is copy/pasted from Canvas.java
-    // The JNI registration is handled by android_view_Canvas.cpp
+    // The JNI registration is handled by android_graphics_Canvas.cpp
     // ---------------------------------------------------------------------------
 
     public void drawArc(float left, float top, float right, float bottom, float startAngle,
@@ -670,6 +670,17 @@
     /**
      * @hide
      */
+    public void drawMesh(Mesh mesh, BlendMode blendMode, Paint paint) {
+        if (!isHardwareAccelerated() && onHwFeatureInSwMode()) {
+            throw new RuntimeException("software rendering doesn't support meshes");
+        }
+        nDrawMesh(this.mNativeCanvasWrapper, mesh.getNativeWrapperInstance(),
+                blendMode.getXfermode().porterDuffMode, paint.getNativeInstance());
+    }
+
+    /**
+     * @hide
+     */
     public void punchHole(float left, float top, float right, float bottom, float rx, float ry,
             float alpha) {
         nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, alpha);
@@ -801,6 +812,9 @@
             int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
             short[] indices, int indexOffset, int indexCount, long nativePaint);
 
+    private static native void nDrawMesh(
+            long nativeCanvas, long nativeMesh, int mode, long nativePaint);
+
     private static native void nDrawGlyphs(long nativeCanvas, int[] glyphIds, float[] positions,
             int glyphIdStart, int positionStart, int glyphCount, long nativeFont, long nativePaint);
 
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 1ba79b8..eeff694 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -606,6 +606,12 @@
                 indices, indexOffset, indexCount, paint.getNativeInstance());
     }
 
+    @Override
+    public final void drawMesh(Mesh mesh, BlendMode blendMode, Paint paint) {
+        nDrawMesh(mNativeCanvasWrapper, mesh.getNativeWrapperInstance(),
+                blendMode.getXfermode().porterDuffMode, paint.getNativeInstance());
+    }
+
     /**
      * @hide
      */
@@ -708,6 +714,10 @@
             long nativePaint);
 
     @FastNative
+    private static native void nDrawMesh(
+            long canvasHandle, long nativeMesh, int mode, long nativePaint);
+
+    @FastNative
     private static native void nDrawVertices(long nativeCanvas, int mode, int n, float[] verts,
             int vertOffset, float[] texs, int texOffset, int[] colors, int colorOffset,
             short[] indices, int indexOffset, int indexCount, long nativePaint);
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index c93b733..68f2927 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -26,7 +26,7 @@
      @Retention(RetentionPolicy.SOURCE)
      @IntDef(value = {
              UNKNOWN,
-             /**
+             /*
               * Since some APIs accept either ImageFormat or PixelFormat (and the two
               * enums do not overlap since they're both partial versions of the
               * internal format enum), add PixelFormat values here so linting
diff --git a/graphics/java/android/graphics/Mesh.java b/graphics/java/android/graphics/Mesh.java
new file mode 100644
index 0000000..f32e0ee
--- /dev/null
+++ b/graphics/java/android/graphics/Mesh.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.nio.Buffer;
+import java.nio.ShortBuffer;
+
+/**
+ * Class representing a mesh object.
+ *
+ * This class generates Mesh objects via the
+ * {@link #make(MeshSpecification, Mode, Buffer, int, Rect)} and
+ * {@link #makeIndexed(MeshSpecification, Mode, Buffer, int, ShortBuffer, Rect)} methods,
+ * where a {@link MeshSpecification} is required along with various attributes for
+ * detailing the mesh object, including a mode, vertex buffer, optional index buffer, and bounds
+ * for the mesh.
+ *
+ * @hide
+ */
+public class Mesh {
+    private long mNativeMeshWrapper;
+    private boolean mIsIndexed;
+
+    /**
+     * Enum to determine how the mesh is represented.
+     */
+    public enum Mode {Triangles, TriangleStrip}
+
+    private static class MeshHolder {
+        public static final NativeAllocationRegistry MESH_SPECIFICATION_REGISTRY =
+                NativeAllocationRegistry.createMalloced(
+                        MeshSpecification.class.getClassLoader(), nativeGetFinalizer());
+    }
+
+    /**
+     * Generates a {@link Mesh} object.
+     *
+     * @param meshSpec     {@link MeshSpecification} used when generating the mesh.
+     * @param mode         {@link Mode} enum
+     * @param vertexBuffer vertex buffer representing through {@link Buffer}.
+     * @param vertexCount  the number of vertices represented in the vertexBuffer.
+     * @param bounds       bounds of the mesh object.
+     * @return a new Mesh object.
+     */
+    public static Mesh make(MeshSpecification meshSpec, Mode mode, Buffer vertexBuffer,
+            int vertexCount, Rect bounds) {
+        long nativeMesh = nativeMake(meshSpec.mNativeMeshSpec, mode.ordinal(), vertexBuffer,
+                vertexBuffer.isDirect(), vertexCount, vertexBuffer.position(), bounds.left,
+                bounds.top, bounds.right, bounds.bottom);
+        if (nativeMesh == 0) {
+            throw new IllegalArgumentException("Mesh construction failed.");
+        }
+        return new Mesh(nativeMesh, false);
+    }
+
+    /**
+     * Generates an indexed {@link Mesh} object.
+     *
+     * @param meshSpec     {@link MeshSpecification} used when generating the mesh.
+     * @param mode         {@link Mode} enum
+     * @param vertexBuffer vertex buffer representing through {@link Buffer}.
+     * @param vertexCount  the number of vertices represented in the vertexBuffer.
+     * @param indexBuffer  index buffer representing through {@link ShortBuffer}.
+     * @param bounds       bounds of the mesh object.
+     * @return a new Mesh object.
+     */
+    public static Mesh makeIndexed(MeshSpecification meshSpec, Mode mode, Buffer vertexBuffer,
+            int vertexCount, ShortBuffer indexBuffer, Rect bounds) {
+        long nativeMesh = nativeMakeIndexed(meshSpec.mNativeMeshSpec, mode.ordinal(), vertexBuffer,
+                vertexBuffer.isDirect(), vertexCount, vertexBuffer.position(), indexBuffer,
+                indexBuffer.isDirect(), indexBuffer.capacity(), indexBuffer.position(), bounds.left,
+                bounds.top, bounds.right, bounds.bottom);
+        if (nativeMesh == 0) {
+            throw new IllegalArgumentException("Mesh construction failed.");
+        }
+        return new Mesh(nativeMesh, true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the color uniform declared in the shader program.
+     * @param color       the provided sRGB color will be converted into the shader program's output
+     *                    colorspace and be available as a vec4 uniform in the program.
+     */
+    public void setColorUniform(String uniformName, int color) {
+        setUniform(uniformName, Color.valueOf(color).getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the color uniform declared in the shader program.
+     * @param color       the provided sRGB color will be converted into the shader program's output
+     *                    colorspace and be available as a vec4 uniform in the program.
+     */
+    public void setColorUniform(String uniformName, long color) {
+        Color exSRGB = Color.valueOf(color).convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+        setUniform(uniformName, exSRGB.getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the color uniform declared in the shader program.
+     * @param color       the provided sRGB color will be converted into the shader program's output
+     *                    colorspace and will be made available as a vec4 uniform in the program.
+     */
+    public void setColorUniform(String uniformName, Color color) {
+        if (color == null) {
+            throw new NullPointerException("The color parameter must not be null");
+        }
+
+        Color exSRGB = color.convert(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB));
+        setUniform(uniformName, exSRGB.getComponents(), true);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the float uniform declared in the shader program.
+     * @param value       float value corresponding to the float uniform with the given name.
+     */
+    public void setFloatUniform(String uniformName, float value) {
+        setFloatUniform(uniformName, value, 0.0f, 0.0f, 0.0f, 1);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the float uniform declared in the shader program.
+     * @param value1      first float value corresponding to the float uniform with the given name.
+     * @param value2      second float value corresponding to the float uniform with the given name.
+     */
+    public void setFloatUniform(String uniformName, float value1, float value2) {
+        setFloatUniform(uniformName, value1, value2, 0.0f, 0.0f, 2);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the float uniform declared in the shader program.
+     * @param value1      first float value corresponding to the float uniform with the given name.
+     * @param value2      second float value corresponding to the float uniform with the given name.
+     * @param value3      third float value corresponding to the float unifiform with the given
+     *                    name.
+     */
+    public void setFloatUniform(String uniformName, float value1, float value2, float value3) {
+        setFloatUniform(uniformName, value1, value2, value3, 0.0f, 3);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the float uniform declared in the shader program.
+     * @param value1      first float value corresponding to the float uniform with the given name.
+     * @param value2      second float value corresponding to the float uniform with the given name.
+     * @param value3      third float value corresponding to the float uniform with the given name.
+     * @param value4      fourth float value corresponding to the float uniform with the given name.
+     */
+    public void setFloatUniform(
+            String uniformName, float value1, float value2, float value3, float value4) {
+        setFloatUniform(uniformName, value1, value2, value3, value4, 4);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the float uniform declared in the shader program.
+     * @param values      float value corresponding to the vec4 float uniform with the given name.
+     */
+    public void setFloatUniform(String uniformName, float[] values) {
+        setUniform(uniformName, values, false);
+    }
+
+    private void setFloatUniform(
+            String uniformName, float value1, float value2, float value3, float value4, int count) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        nativeUpdateUniforms(
+                mNativeMeshWrapper, uniformName, value1, value2, value3, value4, count);
+    }
+
+    private void setUniform(String uniformName, float[] values, boolean isColor) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        if (values == null) {
+            throw new NullPointerException("The uniform values parameter must not be null");
+        }
+
+        nativeUpdateUniforms(mNativeMeshWrapper, uniformName, values, isColor);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the int uniform delcared in the shader program.
+     * @param value       value corresponding to the int uniform with the given name.
+     */
+    public void setIntUniform(String uniformName, int value) {
+        setIntUniform(uniformName, value, 0, 0, 0, 1);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the int uniform delcared in the shader program.
+     * @param value1      first value corresponding to the int uniform with the given name.
+     * @param value2      second value corresponding to the int uniform with the given name.
+     */
+    public void setIntUniform(String uniformName, int value1, int value2) {
+        setIntUniform(uniformName, value1, value2, 0, 0, 2);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the int uniform delcared in the shader program.
+     * @param value1      first value corresponding to the int uniform with the given name.
+     * @param value2      second value corresponding to the int uniform with the given name.
+     * @param value3      third value corresponding to the int uniform with the given name.
+     */
+    public void setIntUniform(String uniformName, int value1, int value2, int value3) {
+        setIntUniform(uniformName, value1, value2, value3, 0, 3);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the int uniform delcared in the shader program.
+     * @param value1      first value corresponding to the int uniform with the given name.
+     * @param value2      second value corresponding to the int uniform with the given name.
+     * @param value3      third value corresponding to the int uniform with the given name.
+     * @param value4      fourth value corresponding to the int uniform with the given name.
+     */
+    public void setIntUniform(String uniformName, int value1, int value2, int value3, int value4) {
+        setIntUniform(uniformName, value1, value2, value3, value4, 4);
+    }
+
+    /**
+     * Sets the uniform color value corresponding to the shader assigned to the mesh.
+     *
+     * @param uniformName name matching the int uniform delcared in the shader program.
+     * @param values      int values corresponding to the vec4 int uniform with the given name.
+     */
+    public void setIntUniform(String uniformName, int[] values) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+        if (values == null) {
+            throw new NullPointerException("The uniform values parameter must not be null");
+        }
+        nativeUpdateUniforms(mNativeMeshWrapper, uniformName, values);
+    }
+
+    /**
+     * @hide so only calls from module can utilize it
+     */
+    long getNativeWrapperInstance() {
+        nativeUpdateMesh(mNativeMeshWrapper, mIsIndexed);
+        return mNativeMeshWrapper;
+    }
+
+    private void setIntUniform(
+            String uniformName, int value1, int value2, int value3, int value4, int count) {
+        if (uniformName == null) {
+            throw new NullPointerException("The uniformName parameter must not be null");
+        }
+
+        nativeUpdateUniforms(
+                mNativeMeshWrapper, uniformName, value1, value2, value3, value4, count);
+    }
+
+    private Mesh(long nativeMeshWrapper, boolean isIndexed) {
+        mNativeMeshWrapper = nativeMeshWrapper;
+        this.mIsIndexed = isIndexed;
+        MeshHolder.MESH_SPECIFICATION_REGISTRY.registerNativeAllocation(this, mNativeMeshWrapper);
+    }
+
+    private static native long nativeGetFinalizer();
+
+    private static native long nativeMake(long meshSpec, int mode, Buffer vertexBuffer,
+            boolean isDirect, int vertexCount, int vertexOffset, int left, int top, int right,
+            int bottom);
+
+    private static native long nativeMakeIndexed(long meshSpec, int mode, Buffer vertexBuffer,
+            boolean isVertexDirect, int vertexCount, int vertexOffset, ShortBuffer indexBuffer,
+            boolean isIndexDirect, int indexCount, int indexOffset, int left, int top, int right,
+            int bottom);
+
+    private static native void nativeUpdateUniforms(long builder, String uniformName, float value1,
+            float value2, float value3, float value4, int count);
+
+    private static native void nativeUpdateUniforms(
+            long builder, String uniformName, float[] values, boolean isColor);
+
+    private static native void nativeUpdateUniforms(long builder, String uniformName, int value1,
+            int value2, int value3, int value4, int count);
+
+    private static native void nativeUpdateUniforms(long builder, String uniformName, int[] values);
+
+    private static native void nativeUpdateMesh(long nativeMeshWrapper, boolean mIsIndexed);
+}
diff --git a/graphics/java/android/graphics/MeshSpecification.java b/graphics/java/android/graphics/MeshSpecification.java
new file mode 100644
index 0000000..45c13af
--- /dev/null
+++ b/graphics/java/android/graphics/MeshSpecification.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.graphics;
+
+import android.annotation.IntDef;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Class responsible for holding specifications for {@link Mesh} creations. This class
+ * generates a {@link MeshSpecification} via the Make method, where multiple parameters to set up
+ * the mesh are supplied, including attributes, vertex stride, varyings, and
+ * vertex/fragment shaders. There are also additional methods to provide an optional
+ * {@link ColorSpace} as well as an alpha type.
+ *
+ * Note that there are several limitations on various mesh specifications:
+ * 1. The max amount of attributes allowed is 8.
+ * 2. The offset alignment length is 4 bytes.
+ * 2. The max stride length is 1024.
+ * 3. The max amount of varyings is 6.
+ *
+ * These should be kept in mind when generating a mesh specification, as exceeding them will
+ * lead to errors.
+ *
+ * @hide
+ */
+public class MeshSpecification {
+    long mNativeMeshSpec;
+
+    /**
+     * Constants for {@link #make(Attribute[], int, Varying[], String, String, ColorSpace, int)}
+     * to determine alpha type
+     */
+    @IntDef({UNKNOWN, OPAQUE, PREMUL, UNPREMULT})
+    public @interface AlphaType {
+    }
+
+    public static final int UNKNOWN = 0;
+    public static final int OPAQUE = 1;
+    public static final int PREMUL = 2;
+    public static final int UNPREMULT = 3;
+
+    /**
+     * Constants for {@link Attribute} and {@link Varying} for determining the data type.
+     */
+    @IntDef({FLOAT, FLOAT2, FLOAT3, FLOAT4, UBYTE4})
+    public @interface Type {
+    }
+
+    public static final int FLOAT = 0;
+    public static final int FLOAT2 = 1;
+    public static final int FLOAT3 = 2;
+    public static final int FLOAT4 = 3;
+    public static final int UBYTE4 = 4;
+
+    /**
+     * Data class to represent a single attribute in a shader. Note that type parameter must be
+     * one of {@link #FLOAT}, {@link #FLOAT2}, {@link #FLOAT3}, {@link #FLOAT4}, or {@link #UBYTE4}.
+     */
+    public static class Attribute {
+        @Type
+        private int mType;
+        private int mOffset;
+        private String mName;
+
+        public Attribute(@Type int type, int offset, String name) {
+            mType = type;
+            mOffset = offset;
+            mName = name;
+        }
+    }
+
+    /**
+     * Data class to represent a single varying variable. Note that type parameter must be
+     * one of {@link #FLOAT}, {@link #FLOAT2}, {@link #FLOAT3}, {@link #FLOAT4}, or {@link #UBYTE4}.
+     */
+    public static class Varying {
+        @Type
+        private int mType;
+        private String mName;
+
+        public Varying(@Type int type, String name) {
+            mType = type;
+            mName = name;
+        }
+    }
+
+    private static class MeshSpecificationHolder {
+        public static final NativeAllocationRegistry MESH_SPECIFICATION_REGISTRY =
+                NativeAllocationRegistry.createMalloced(
+                        MeshSpecification.class.getClassLoader(), nativeGetFinalizer());
+    }
+
+    /**
+     * Creates a {@link MeshSpecification} object.
+     *
+     * @param attributes     list of attributes represented by {@link Attribute}. Can hold a max of
+     *                       8.
+     * @param vertexStride   length of vertex stride. Max of 1024 is accepted.
+     * @param varyings       List of varyings represented by {@link Varying}. Can hold a max of 6.
+     * @param vertexShader   vertex shader to be supplied to the mesh.
+     * @param fragmentShader fragment shader to be suppied to the mesh.
+     * @return {@link MeshSpecification} object for use when creating {@link Mesh}
+     */
+    public static MeshSpecification make(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader) {
+        long nativeMeshSpec =
+                nativeMake(attributes, vertexStride, varyings, vertexShader, fragmentShader);
+        if (nativeMeshSpec == 0) {
+            throw new IllegalArgumentException("MeshSpecification construction failed");
+        }
+        return new MeshSpecification(nativeMeshSpec);
+    }
+
+    /**
+     * Creates a {@link MeshSpecification} object.
+     *
+     * @param attributes     list of attributes represented by {@link Attribute}. Can hold a max of
+     *                       8.
+     * @param vertexStride   length of vertex stride. Max of 1024 is accepted.
+     * @param varyings       List of varyings represented by {@link Varying}. Can hold a max of
+     *                       6.
+     * @param vertexShader   vertex shader to be supplied to the mesh.
+     * @param fragmentShader fragment shader to be supplied to the mesh.
+     * @param colorSpace     {@link ColorSpace} to tell what color space to work in.
+     * @return {@link MeshSpecification} object for use when creating {@link Mesh}
+     */
+    public static MeshSpecification make(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader, ColorSpace colorSpace) {
+        long nativeMeshSpec = nativeMakeWithCS(attributes, vertexStride, varyings, vertexShader,
+                fragmentShader, colorSpace.getNativeInstance());
+        if (nativeMeshSpec == 0) {
+            throw new IllegalArgumentException("MeshSpecification construction failed");
+        }
+        return new MeshSpecification(nativeMeshSpec);
+    }
+
+    /**
+     * Creates a {@link MeshSpecification} object.
+     *
+     * @param attributes     list of attributes represented by {@link Attribute}. Can hold a max of
+     *                       8.
+     * @param vertexStride   length of vertex stride. Max of 1024 is accepted.
+     * @param varyings       List of varyings represented by {@link Varying}. Can hold a max of 6.
+     * @param vertexShader   vertex shader code to be supplied to the mesh.
+     * @param fragmentShader fragment shader code to be suppied to the mesh.
+     * @param colorSpace     {@link ColorSpace} to tell what color space to work in.
+     * @param alphaType      Describes how to interpret the alpha component for a pixel. Must be
+     *                       one of {@link AlphaType} values.
+     * @return {@link MeshSpecification} object for use when creating {@link Mesh}
+     */
+    public static MeshSpecification make(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader, ColorSpace colorSpace,
+            @AlphaType int alphaType) {
+        long nativeMeshSpec = nativeMakeWithAlpha(attributes, vertexStride, varyings, vertexShader,
+                fragmentShader, colorSpace.getNativeInstance(), alphaType);
+        if (nativeMeshSpec == 0) {
+            throw new IllegalArgumentException("MeshSpecification construction failed");
+        }
+        return new MeshSpecification(nativeMeshSpec);
+    }
+
+    private MeshSpecification(long meshSpec) {
+        mNativeMeshSpec = meshSpec;
+        MeshSpecificationHolder.MESH_SPECIFICATION_REGISTRY.registerNativeAllocation(
+                this, meshSpec);
+    }
+
+    private static native long nativeGetFinalizer();
+
+    private static native long nativeMake(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader);
+
+    private static native long nativeMakeWithCS(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace);
+
+    private static native long nativeMakeWithAlpha(Attribute[] attributes, int vertexStride,
+            Varying[] varyings, String vertexShader, String fragmentShader, long colorSpace,
+            int alphaType);
+}
diff --git a/graphics/java/android/graphics/PathIterator.java b/graphics/java/android/graphics/PathIterator.java
index 33b9a47..bfda690 100644
--- a/graphics/java/android/graphics/PathIterator.java
+++ b/graphics/java/android/graphics/PathIterator.java
@@ -281,7 +281,7 @@
             return mConicWeight;
         }
 
-        public Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
+        Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
             mVerb = verb;
             mPoints = points;
             mConicWeight = conicWeight;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 3b7d0e1..9fb627f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1207,6 +1207,7 @@
      * It is safe to call this method twice or more on the same instance.
      * @hide
      */
+    @TestApi
     public void releaseNativeObjectForTest() {
         mCleaner.run();
     }
@@ -1294,6 +1295,13 @@
     /**
      * Deserialize the font mapping from the serialized byte buffer.
      *
+     * <p>Warning: the given {@code buffer} must outlive generated Typeface
+     * objects in {@code out}. In production code, this is guaranteed by
+     * storing the buffer in {@link #sSystemFontMapBuffer}.
+     * If you call this method in a test, please make sure to destroy the
+     * generated Typeface objects by calling
+     * {@link #releaseNativeObjectForTest()}.
+     *
      * @hide
      */
     @TestApi
diff --git a/graphics/java/android/view/PixelCopy.java b/graphics/java/android/view/PixelCopy.java
index 82ced43..0e198d5 100644
--- a/graphics/java/android/view/PixelCopy.java
+++ b/graphics/java/android/view/PixelCopy.java
@@ -382,9 +382,9 @@
             }
 
             /**
-             * Creates a PixelCopy request for the given {@link Window}
+             * Creates a PixelCopy Builder for the given {@link Window}
              * @param source The Window to copy from
-             * @return A {@link Builder} builder to set the optional params & execute the request
+             * @return A {@link Builder} builder to set the optional params & build the request
              */
             @SuppressLint("BuilderSetStyle")
             public static @NonNull Builder ofWindow(@NonNull Window source) {
@@ -394,7 +394,7 @@
             }
 
             /**
-             * Creates a PixelCopy request for the {@link Window} that the given {@link View} is
+             * Creates a PixelCopy Builder for the {@link Window} that the given {@link View} is
              * attached to.
              *
              * Note that this copy request is not cropped to the area the View occupies by default.
@@ -404,7 +404,7 @@
              *
              * @param source A View that {@link View#isAttachedToWindow() is attached} to a window
              *               that will be used to retrieve the window to copy from.
-             * @return A {@link Builder} builder to set the optional params & execute the request
+             * @return A {@link Builder} builder to set the optional params & build the request
              */
             @SuppressLint("BuilderSetStyle")
             public static @NonNull Builder ofWindow(@NonNull View source) {
@@ -427,10 +427,10 @@
             }
 
             /**
-             * Creates a PixelCopy request for the given {@link Surface}
+             * Creates a PixelCopy Builder for the given {@link Surface}
              *
              * @param source The Surface to copy from. Must be {@link Surface#isValid() valid}.
-             * @return A {@link Builder} builder to set the optional params & execute the request
+             * @return A {@link Builder} builder to set the optional params & build the request
              */
             @SuppressLint("BuilderSetStyle")
             public static @NonNull Builder ofSurface(@NonNull Surface source) {
@@ -441,12 +441,12 @@
             }
 
             /**
-             * Creates a PixelCopy request for the {@link Surface} belonging to the
+             * Creates a PixelCopy Builder for the {@link Surface} belonging to the
              * given {@link SurfaceView}
              *
              * @param source The SurfaceView to copy from. The backing surface must be
              *               {@link Surface#isValid() valid}
-             * @return A {@link Builder} builder to set the optional params & execute the request
+             * @return A {@link Builder} builder to set the optional params & build the request
              */
             @SuppressLint("BuilderSetStyle")
             public static @NonNull Builder ofSurface(@NonNull SurfaceView source) {
diff --git a/keystore/java/android/security/keystore/KeyProperties.java b/keystore/java/android/security/keystore/KeyProperties.java
index 6245598..8c42547 100644
--- a/keystore/java/android/security/keystore/KeyProperties.java
+++ b/keystore/java/android/security/keystore/KeyProperties.java
@@ -196,6 +196,7 @@
     @StringDef(prefix = { "KEY_" }, value = {
         KEY_ALGORITHM_RSA,
         KEY_ALGORITHM_EC,
+        KEY_ALGORITHM_XDH,
         KEY_ALGORITHM_AES,
         KEY_ALGORITHM_HMAC_SHA1,
         KEY_ALGORITHM_HMAC_SHA224,
@@ -211,6 +212,11 @@
     /** Elliptic Curve (EC) Cryptography key. */
     public static final String KEY_ALGORITHM_EC = "EC";
 
+    /** Curve 25519 based Agreement key.
+     * @hide
+     */
+    public static final String KEY_ALGORITHM_XDH = "XDH";
+
     /** Advanced Encryption Standard (AES) key. */
     public static final String KEY_ALGORITHM_AES = "AES";
 
@@ -246,7 +252,8 @@
 
         public static int toKeymasterAsymmetricKeyAlgorithm(
                 @NonNull @KeyAlgorithmEnum String algorithm) {
-            if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
+            if (KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)
+                    || KEY_ALGORITHM_XDH.equalsIgnoreCase(algorithm)) {
                 return KeymasterDefs.KM_ALGORITHM_EC;
             } else if (KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
                 return KeymasterDefs.KM_ALGORITHM_RSA;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
index 4e73bd9..4505eaf 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreECPublicKey.java
@@ -24,13 +24,9 @@
 import android.system.keystore2.KeyDescriptor;
 import android.system.keystore2.KeyMetadata;
 
-import java.security.AlgorithmParameters;
-import java.security.NoSuchAlgorithmException;
 import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECGenParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.ECPoint;
-import java.security.spec.InvalidParameterSpecException;
 
 /**
  * {@link ECPublicKey} backed by keystore.
@@ -62,34 +58,13 @@
         }
     }
 
-    private static String getEcCurveFromKeymaster(int ecCurve) {
-        switch (ecCurve) {
-            case android.hardware.security.keymint.EcCurve.P_224:
-                return "secp224r1";
-            case android.hardware.security.keymint.EcCurve.P_256:
-                return "secp256r1";
-            case android.hardware.security.keymint.EcCurve.P_384:
-                return "secp384r1";
-            case android.hardware.security.keymint.EcCurve.P_521:
-                return "secp521r1";
-        }
-        return "";
-    }
-
-    private ECParameterSpec getCurveSpec(String name)
-            throws NoSuchAlgorithmException, InvalidParameterSpecException {
-        AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
-        parameters.init(new ECGenParameterSpec(name));
-        return parameters.getParameterSpec(ECParameterSpec.class);
-    }
-
     @Override
     public AndroidKeyStorePrivateKey getPrivateKey() {
         ECParameterSpec params = mParams;
         for (Authorization a : getAuthorizations()) {
             try {
                 if (a.keyParameter.tag == KeymasterDefs.KM_TAG_EC_CURVE) {
-                    params = getCurveSpec(getEcCurveFromKeymaster(
+                    params = KeymasterUtils.getCurveSpec(KeymasterUtils.getEcCurveFromKeymaster(
                             a.keyParameter.value.getEcCurve()));
                     break;
                 }
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
index 4caa47f..7292cd3 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyAgreementSpi.java
@@ -32,7 +32,6 @@
 import java.security.PublicKey;
 import java.security.SecureRandom;
 import java.security.interfaces.ECKey;
-import java.security.interfaces.XECKey;
 import java.security.spec.AlgorithmParameterSpec;
 import java.util.ArrayList;
 import java.util.List;
@@ -134,10 +133,15 @@
             throw new InvalidKeyException("key == null");
         } else if (!(key instanceof PublicKey)) {
             throw new InvalidKeyException("Only public keys supported. Key: " + key);
-        } else if (!(mKey instanceof ECKey && key instanceof ECKey)
-                && !(mKey instanceof XECKey && key instanceof XECKey)) {
+        } else if (mKey instanceof ECKey && !(key instanceof ECKey)
+                /*&& !(mKey instanceof XECKey && key instanceof XECKey)*/) {
+        /** TODO This condition is temporary modified, because OpenSSL implementation does not
+         * implement OpenSSLX25519PublicKey from XECKey interface (b/214203951).
+         * This change has to revert once conscrypt implements OpenSSLX25519PublicKey from
+         * XECKey interface.
+         */
             throw new InvalidKeyException(
-                    "Public and Private key should be of the same type:");
+                    "Public and Private key should be of the same type.");
         } else if (mKey instanceof ECKey
                 && !((ECKey) key).getParams().getCurve()
                 .equals(((ECKey) mKey).getParams().getCurve())) {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index acc0005..afec830 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -52,6 +52,7 @@
 import android.system.keystore2.KeyMetadata;
 import android.system.keystore2.ResponseCode;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
@@ -856,6 +857,13 @@
                                 KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
                                 imei.getBytes(StandardCharsets.UTF_8)
                         ));
+                        final String secondImei = telephonyService.getImei(1);
+                        if (!TextUtils.isEmpty(secondImei)) {
+                            params.add(KeyStore2ParameterUtils.makeBytes(
+                                    KeymasterDefs.KM_TAG_ATTESTATION_ID_SECOND_IMEI,
+                                    secondImei.getBytes(StandardCharsets.UTF_8)
+                            ));
+                        }
                         break;
                     }
                     case AttestationUtils.ID_TYPE_MEID: {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 7a320ba..2d609e8 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.hardware.biometrics.BiometricManager;
+import android.hardware.security.keymint.EcCurve;
 import android.hardware.security.keymint.HardwareAuthenticatorType;
 import android.hardware.security.keymint.KeyParameter;
 import android.hardware.security.keymint.SecurityLevel;
@@ -67,6 +68,14 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
 import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.EdECKey;
+import java.security.interfaces.EdECPrivateKey;
+import java.security.interfaces.XECKey;
+import java.security.interfaces.XECPrivateKey;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.NamedParameterSpec;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -567,22 +576,14 @@
                         spec.getMaxUsageCount()
                 ));
             }
-            if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
-                if (key instanceof ECKey) {
-                    ECKey ecKey = (ECKey) key;
-                    importArgs.add(KeyStore2ParameterUtils.makeEnum(
-                            KeymasterDefs.KM_TAG_EC_CURVE,
-                            KeyProperties.EcCurve.toKeymasterCurve(ecKey.getParams())
-                    ));
-                }
+            if (KeymasterDefs.KM_ALGORITHM_EC
+                    == KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
+                            key.getAlgorithm())) {
+                importArgs.add(KeyStore2ParameterUtils.makeEnum(
+                        KeymasterDefs.KM_TAG_EC_CURVE,
+                        getKeymasterEcCurve(key)
+                ));
             }
-            /* TODO: check for Ed25519(EdDSA) or X25519(XDH) key algorithm and
-             *  add import args for KM_TAG_EC_CURVE as EcCurve.CURVE_25519.
-             *  Currently conscrypt does not support EdDSA key import and XDH keys are not an
-             *  instance of XECKey, hence these conditions are not added, once it is fully
-             *  implemented by conscrypt, we can add CURVE_25519 argument for EdDSA and XDH
-             *  algorithms.
-             */
         } catch (IllegalArgumentException | IllegalStateException e) {
             throw new KeyStoreException(e);
         }
@@ -608,6 +609,31 @@
         }
     }
 
+    private int getKeymasterEcCurve(PrivateKey key) {
+        if (key instanceof ECKey) {
+            ECParameterSpec param = ((ECPrivateKey) key).getParams();
+            int kmECCurve = KeymasterUtils.getKeymasterEcCurve(KeymasterUtils.getCurveName(param));
+            if (kmECCurve >= 0) {
+                return kmECCurve;
+            }
+        } else if (key instanceof XECKey) {
+            AlgorithmParameterSpec param = ((XECPrivateKey) key).getParams();
+            if (param.equals(NamedParameterSpec.X25519)) {
+                return EcCurve.CURVE_25519;
+            }
+        } else if (key.getAlgorithm().equals("XDH")) {
+            // TODO com.android.org.conscrypt.OpenSSLX25519PrivateKey does not implement XECKey,
+            //  this case is not required once it implements XECKey interface(b/214203951).
+            return EcCurve.CURVE_25519;
+        } else if (key instanceof EdECKey) {
+            AlgorithmParameterSpec param = ((EdECPrivateKey) key).getParams();
+            if (param.equals(NamedParameterSpec.ED25519)) {
+                return EcCurve.CURVE_25519;
+            }
+        }
+        throw new IllegalArgumentException("Unexpected Key " + key.getClass().getName());
+    }
+
     private static void assertCanReplace(String alias, @Domain int targetDomain,
             int targetNamespace, KeyDescriptor descriptor)
             throws KeyStoreException {
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
index 9f3df3d..6913834 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreXDHPublicKey.java
@@ -88,7 +88,7 @@
                 getUserKeyDescriptor(),
                 getKeyIdDescriptor().nspace,
                 getAuthorizations(),
-                "x25519",
+                "XDH",
                 getSecurityLevel());
     }
 
diff --git a/keystore/java/android/security/keystore2/KeymasterUtils.java b/keystore/java/android/security/keystore2/KeymasterUtils.java
index de4696c..614e368 100644
--- a/keystore/java/android/security/keystore2/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore2/KeymasterUtils.java
@@ -20,7 +20,12 @@
 import android.security.keymaster.KeymasterDefs;
 import android.security.keystore.KeyProperties;
 
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
 import java.security.ProviderException;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.InvalidParameterSpecException;
 
 /**
  * @hide
@@ -121,4 +126,65 @@
                 break;
         }
     }
+
+    static String getEcCurveFromKeymaster(int ecCurve) {
+        switch (ecCurve) {
+            case android.hardware.security.keymint.EcCurve.P_224:
+                return "secp224r1";
+            case android.hardware.security.keymint.EcCurve.P_256:
+                return "secp256r1";
+            case android.hardware.security.keymint.EcCurve.P_384:
+                return "secp384r1";
+            case android.hardware.security.keymint.EcCurve.P_521:
+                return "secp521r1";
+        }
+        return "";
+    }
+
+    static int getKeymasterEcCurve(String ecCurveName) {
+        if (ecCurveName.equals("secp224r1")) {
+            return android.hardware.security.keymint.EcCurve.P_224;
+        } else if (ecCurveName.equals("secp256r1")) {
+            return android.hardware.security.keymint.EcCurve.P_256;
+        } else if (ecCurveName.equals("secp384r1")) {
+            return android.hardware.security.keymint.EcCurve.P_384;
+        } else if (ecCurveName.equals("secp521r1")) {
+            return android.hardware.security.keymint.EcCurve.P_521;
+        }
+        return -1;
+    }
+
+    static ECParameterSpec getCurveSpec(String name)
+            throws NoSuchAlgorithmException, InvalidParameterSpecException {
+        AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC");
+        parameters.init(new ECGenParameterSpec(name));
+        return parameters.getParameterSpec(ECParameterSpec.class);
+    }
+
+    static String getCurveName(ECParameterSpec spec) {
+        if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp224r1")) {
+            return "secp224r1";
+        } else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp256r1")) {
+            return "secp256r1";
+        } else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp384r1")) {
+            return "secp384r1";
+        } else if (KeymasterUtils.isECParameterSpecOfCurve(spec, "secp521r1")) {
+            return "secp521r1";
+        }
+        return null;
+    }
+
+    private static boolean isECParameterSpecOfCurve(ECParameterSpec spec, String curveName) {
+        try {
+            ECParameterSpec curveSpec = KeymasterUtils.getCurveSpec(curveName);
+            if (curveSpec.getCurve().equals(spec.getCurve())
+                    && curveSpec.getOrder().equals(spec.getOrder())
+                    && curveSpec.getGenerator().equals(spec.getGenerator())) {
+                return true;
+            }
+        } catch (NoSuchAlgorithmException | InvalidParameterSpecException e) {
+            return false;
+        }
+        return false;
+    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index c06548a..6f9a4ff8 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -41,7 +41,6 @@
 import static androidx.window.extensions.embedding.SplitContainer.shouldFinishAssociatedContainerWhenStacked;
 import static androidx.window.extensions.embedding.SplitPresenter.RESULT_EXPAND_FAILED_NO_TF_INFO;
 import static androidx.window.extensions.embedding.SplitPresenter.getActivityIntentMinDimensionsPair;
-import static androidx.window.extensions.embedding.SplitPresenter.getNonEmbeddedActivityBounds;
 import static androidx.window.extensions.embedding.SplitPresenter.shouldShowSplit;
 
 import android.app.Activity;
@@ -464,7 +463,6 @@
             // parentInfo#isVisibleRequested is true.
             return;
         }
-        onTaskContainerInfoChanged(taskContainer, parentInfo.getConfiguration());
         if (isInPictureInPicture(parentInfo.getConfiguration())) {
             // No need to update presentation in PIP until the Task exit PIP.
             return;
@@ -614,12 +612,6 @@
         }
     }
 
-    @GuardedBy("mLock")
-    private void onTaskContainerInfoChanged(@NonNull TaskContainer taskContainer,
-            @NonNull Configuration config) {
-        taskContainer.setTaskBounds(config.windowConfiguration.getBounds());
-    }
-
     /** Returns whether the given {@link TaskContainer} may show in split. */
     // Suppress GuardedBy warning because lint asks to mark this method as
     // @GuardedBy(mPresenter.mController.mLock), which is mLock itself
@@ -973,10 +965,16 @@
     @VisibleForTesting
     @GuardedBy("mLock")
     void onActivityDestroyed(@NonNull Activity activity) {
+        if (!activity.isFinishing()) {
+            // onDestroyed is triggered without finishing. This happens when the activity is
+            // relaunched. In this case, we don't want to cleanup the record.
+            return;
+        }
         // Remove any pending appeared activity, as the server won't send finished activity to the
         // organizer.
+        final IBinder activityToken = activity.getActivityToken();
         for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
-            mTaskContainers.valueAt(i).onActivityDestroyed(activity);
+            mTaskContainers.valueAt(i).onActivityDestroyed(activityToken);
         }
         // We didn't trigger the callback if there were any pending appeared activities, so check
         // again after the pending is removed.
@@ -1178,16 +1176,33 @@
      * Returns a container that this activity is registered with. An activity can only belong to one
      * container, or no container at all.
      */
+    @GuardedBy("mLock")
     @Nullable
     TaskFragmentContainer getContainerWithActivity(@NonNull Activity activity) {
-        final IBinder activityToken = activity.getActivityToken();
+        return getContainerWithActivity(activity.getActivityToken());
+    }
+
+    @GuardedBy("mLock")
+    @Nullable
+    TaskFragmentContainer getContainerWithActivity(@NonNull IBinder activityToken) {
+        // Check pending appeared activity first because there can be a delay for the server
+        // update.
         for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
             final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
-            // Traverse from top to bottom in case an activity is added to top pending, and hasn't
-            // received update from server yet.
             for (int j = containers.size() - 1; j >= 0; j--) {
                 final TaskFragmentContainer container = containers.get(j);
-                if (container.hasActivity(activityToken)) {
+                if (container.hasPendingAppearedActivity(activityToken)) {
+                    return container;
+                }
+            }
+        }
+
+        // Check appeared activity if there is no such pending appeared activity.
+        for (int i = mTaskContainers.size() - 1; i >= 0; i--) {
+            final List<TaskFragmentContainer> containers = mTaskContainers.valueAt(i).mContainers;
+            for (int j = containers.size() - 1; j >= 0; j--) {
+                final TaskFragmentContainer container = containers.get(j);
+                if (container.hasAppearedActivity(activityToken)) {
                     return container;
                 }
             }
@@ -1235,13 +1250,6 @@
         final TaskContainer taskContainer = mTaskContainers.get(taskId);
         final TaskFragmentContainer container = new TaskFragmentContainer(pendingAppearedActivity,
                 pendingAppearedIntent, taskContainer, this);
-        if (!taskContainer.isTaskBoundsInitialized()) {
-            // Get the initial bounds before the TaskFragment has appeared.
-            final Rect taskBounds = getNonEmbeddedActivityBounds(activityInTask);
-            if (!taskContainer.setTaskBounds(taskBounds)) {
-                Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
-            }
-        }
         return container;
     }
 
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index f494b32..5395fb2 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -932,11 +932,7 @@
         if (taskContainer != null) {
             return taskContainer.getTaskProperties();
         }
-        // Use a copy of configuration because activity's configuration may be updated later,
-        // or we may get unexpected TaskContainer's configuration if Activity's configuration is
-        // updated. An example is Activity is going to be in split.
-        return new TaskProperties(activity.getDisplayId(),
-                new Configuration(activity.getResources().getConfiguration()));
+        return TaskProperties.getTaskPropertiesFromActivity(activity);
     }
 
     @NonNull
@@ -950,16 +946,4 @@
         // TODO(b/190433398): Supply correct insets.
         return new WindowMetrics(taskBounds, WindowInsets.CONSUMED);
     }
-
-    /** Obtains the bounds from a non-embedded Activity. */
-    @NonNull
-    static Rect getNonEmbeddedActivityBounds(@NonNull Activity activity) {
-        final WindowConfiguration windowConfiguration =
-                activity.getResources().getConfiguration().windowConfiguration;
-        if (!activity.isInMultiWindowMode()) {
-            // In fullscreen mode the max bounds should correspond to the task bounds.
-            return windowConfiguration.getMaxBounds();
-        }
-        return windowConfiguration.getBounds();
-    }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
index 231da05..03f4dc9 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -20,14 +20,17 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+import static android.app.WindowConfiguration.inMultiWindowMode;
 
 import android.app.Activity;
+import android.app.ActivityClient;
 import android.app.WindowConfiguration;
 import android.app.WindowConfiguration.WindowingMode;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.util.ArraySet;
+import android.util.Log;
 import android.window.TaskFragmentInfo;
 import android.window.TaskFragmentParentInfo;
 import android.window.WindowContainerTransaction;
@@ -41,14 +44,11 @@
 
 /** Represents TaskFragments and split pairs below a Task. */
 class TaskContainer {
+    private static final String TAG = TaskContainer.class.getSimpleName();
 
     /** The unique task id. */
     private final int mTaskId;
 
-    // TODO(b/240219484): consolidate to mConfiguration
-    /** Available window bounds of this Task. */
-    private final Rect mTaskBounds = new Rect();
-
     /** Active TaskFragments in this Task. */
     @NonNull
     final List<TaskFragmentContainer> mContainers = new ArrayList<>();
@@ -86,10 +86,10 @@
             throw new IllegalArgumentException("Invalid Task id");
         }
         mTaskId = taskId;
-        // Make a copy in case the activity's config is updated, and updates the TaskContainer's
-        // config unexpectedly.
-        mConfiguration = new Configuration(activityInTask.getResources().getConfiguration());
-        mDisplayId = activityInTask.getDisplayId();
+        final TaskProperties taskProperties = TaskProperties
+                .getTaskPropertiesFromActivity(activityInTask);
+        mConfiguration = taskProperties.getConfiguration();
+        mDisplayId = taskProperties.getDisplayId();
         // Note that it is always called when there's a new Activity is started, which implies
         // the host task is visible.
         mIsVisible = true;
@@ -108,25 +108,6 @@
     }
 
     @NonNull
-    Rect getTaskBounds() {
-        return mTaskBounds;
-    }
-
-    /** Returns {@code true} if the bounds is changed. */
-    boolean setTaskBounds(@NonNull Rect taskBounds) {
-        if (!taskBounds.isEmpty() && !mTaskBounds.equals(taskBounds)) {
-            mTaskBounds.set(taskBounds);
-            return true;
-        }
-        return false;
-    }
-
-    /** Whether the Task bounds has been initialized. */
-    boolean isTaskBoundsInitialized() {
-        return !mTaskBounds.isEmpty();
-    }
-
-    @NonNull
     Configuration getConfiguration() {
         // Make a copy in case the config is updated unexpectedly.
         return new Configuration(mConfiguration);
@@ -185,16 +166,16 @@
     }
 
     /** Called when the activity is destroyed. */
-    void onActivityDestroyed(@NonNull Activity activity) {
+    void onActivityDestroyed(@NonNull IBinder activityToken) {
         for (TaskFragmentContainer container : mContainers) {
-            container.onActivityDestroyed(activity);
+            container.onActivityDestroyed(activityToken);
         }
     }
 
     /** Removes the pending appeared activity from all TaskFragments in this Task. */
-    void cleanupPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
+    void cleanupPendingAppearedActivity(@NonNull IBinder activityToken) {
         for (TaskFragmentContainer container : mContainers) {
-            container.removePendingAppearedActivity(pendingAppearedActivity);
+            container.removePendingAppearedActivity(activityToken);
         }
     }
 
@@ -261,5 +242,45 @@
         Configuration getConfiguration() {
             return mConfiguration;
         }
+
+        /**
+         * Obtains the {@link TaskProperties} for the task that the provided {@link Activity} is
+         * associated with.
+         * <p>
+         * Note that for most case, caller should use
+         * {@link SplitPresenter#getTaskProperties(Activity)} instead. This method is used before
+         * the {@code activity} goes into split.
+         * </p><p>
+         * If the {@link Activity} is in fullscreen, override
+         * {@link WindowConfiguration#getBounds()} with {@link WindowConfiguration#getMaxBounds()}
+         * in case the {@link Activity} is letterboxed. Otherwise, get the Task
+         * {@link Configuration} from the server side or use {@link Activity}'s
+         * {@link Configuration} as a fallback if the Task {@link Configuration} cannot be obtained.
+         */
+        @NonNull
+        static TaskProperties getTaskPropertiesFromActivity(@NonNull Activity activity) {
+            final int displayId = activity.getDisplayId();
+            // Use a copy of configuration because activity's configuration may be updated later,
+            // or we may get unexpected TaskContainer's configuration if Activity's configuration is
+            // updated. An example is Activity is going to be in split.
+            final Configuration activityConfig = new Configuration(
+                    activity.getResources().getConfiguration());
+            final WindowConfiguration windowConfiguration = activityConfig.windowConfiguration;
+            final int windowingMode = windowConfiguration.getWindowingMode();
+            if (!inMultiWindowMode(windowingMode)) {
+                // Use the max bounds in fullscreen in case the Activity is letterboxed.
+                windowConfiguration.setBounds(windowConfiguration.getMaxBounds());
+                return new TaskProperties(displayId, activityConfig);
+            }
+            final Configuration taskConfig = ActivityClient.getInstance()
+                    .getTaskConfiguration(activity.getActivityToken());
+            if (taskConfig == null) {
+                Log.w(TAG, "Could not obtain task configuration for activity:" + activity);
+                // Still report activity config if task config cannot be obtained from the server
+                // side.
+                return new TaskProperties(displayId, activityConfig);
+            }
+            return new TaskProperties(displayId, taskConfig);
+        }
     }
 }
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
index af5d8c5..33220c4 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationAdapter.java
@@ -18,7 +18,9 @@
 
 import static android.graphics.Matrix.MTRANS_X;
 import static android.graphics.Matrix.MTRANS_Y;
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.Choreographer;
 import android.view.RemoteAnimationTarget;
@@ -49,6 +51,16 @@
     /** Area in absolute coordinate that the animation surface shouldn't go beyond. */
     @NonNull
     private final Rect mWholeAnimationBounds = new Rect();
+    /**
+     * Area in absolute coordinate that should represent all the content to show for this window.
+     * This should be the end bounds for opening window, and start bounds for closing window in case
+     * the window is resizing during the open/close transition.
+     */
+    @NonNull
+    private final Rect mContentBounds = new Rect();
+    /** Offset relative to the window parent surface for {@link #mContentBounds}. */
+    @NonNull
+    private final Point mContentRelOffset = new Point();
 
     @NonNull
     final Transformation mTransformation = new Transformation();
@@ -78,6 +90,21 @@
         mTarget = target;
         mLeash = leash;
         mWholeAnimationBounds.set(wholeAnimationBounds);
+        if (target.mode == MODE_CLOSING) {
+            // When it is closing, we want to show the content at the start position in case the
+            // window is resizing as well. For example, when the activities is changing from split
+            // to stack, the bottom TaskFragment will be resized to fullscreen when hiding.
+            final Rect startBounds = target.startBounds;
+            final Rect endBounds = target.screenSpaceBounds;
+            mContentBounds.set(startBounds);
+            mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
+            mContentRelOffset.offset(
+                    startBounds.left - endBounds.left,
+                    startBounds.top - endBounds.top);
+        } else {
+            mContentBounds.set(target.screenSpaceBounds);
+            mContentRelOffset.set(target.localBounds.left, target.localBounds.top);
+        }
     }
 
     /**
@@ -108,8 +135,7 @@
     /** To be overridden by subclasses to adjust the animation surface change. */
     void onAnimationUpdateInner(@NonNull SurfaceControl.Transaction t) {
         // Update the surface position and alpha.
-        mTransformation.getMatrix().postTranslate(
-                mTarget.localBounds.left, mTarget.localBounds.top);
+        mTransformation.getMatrix().postTranslate(mContentRelOffset.x, mContentRelOffset.y);
         t.setMatrix(mLeash, mTransformation.getMatrix(), mMatrix);
         t.setAlpha(mLeash, mTransformation.getAlpha());
 
@@ -117,9 +143,8 @@
         // positionX/Y are in local coordinate, so minus the local offset to get the slide amount.
         final int positionX = Math.round(mMatrix[MTRANS_X]);
         final int positionY = Math.round(mMatrix[MTRANS_Y]);
-        final Rect cropRect = new Rect(mTarget.screenSpaceBounds);
-        final Rect localBounds = mTarget.localBounds;
-        cropRect.offset(positionX - localBounds.left, positionY - localBounds.top);
+        final Rect cropRect = new Rect(mContentBounds);
+        cropRect.offset(positionX - mContentRelOffset.x, positionY - mContentRelOffset.y);
 
         // Store the current offset of the surface top left from (0,0) in absolute coordinate.
         final int offsetX = cropRect.left;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
index 0e13c59..322f854 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationRunner.java
@@ -17,6 +17,7 @@
 package androidx.window.extensions.embedding;
 
 import static android.os.Process.THREAD_PRIORITY_DISPLAY;
+import static android.view.RemoteAnimationTarget.MODE_CHANGING;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
 import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
@@ -254,7 +255,7 @@
             @NonNull RemoteAnimationTarget[] targets) {
         final List<TaskFragmentAnimationAdapter> adapters = new ArrayList<>();
         for (RemoteAnimationTarget target : targets) {
-            if (target.startBounds != null) {
+            if (target.mode == MODE_CHANGING) {
                 // This is the target with bounds change.
                 final Animation[] animations =
                         mAnimationSpec.createChangeBoundsChangeAnimations(target);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
index 13afa49..1f866c3 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentAnimationSpec.java
@@ -114,8 +114,8 @@
     @NonNull
     Animation createChangeBoundsCloseAnimation(@NonNull RemoteAnimationTarget target) {
         final Rect parentBounds = target.taskInfo.configuration.windowConfiguration.getBounds();
-        // TODO(b/258126915): we want to keep track of the closing start bounds
-        final Rect bounds = target.screenSpaceBounds;
+        // Use startBounds if the window is closing in case it may also resize.
+        final Rect bounds = target.startBounds;
         final int endTop;
         final int endLeft;
         if (parentBounds.top == bounds.top && parentBounds.bottom == bounds.bottom) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
index 71b8840..e31792a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskFragmentContainer.java
@@ -43,6 +43,9 @@
  * Client-side container for a stack of activities. Corresponds to an instance of TaskFragment
  * on the server side.
  */
+// Suppress GuardedBy warning because all the TaskFragmentContainers are stored in
+// SplitController.mTaskContainers which is guarded.
+@SuppressWarnings("GuardedBy")
 class TaskFragmentContainer {
     private static final int APPEAR_EMPTY_TIMEOUT_MS = 3000;
 
@@ -66,11 +69,11 @@
     TaskFragmentInfo mInfo;
 
     /**
-     * Activities that are being reparented or being started to this container, but haven't been
-     * added to {@link #mInfo} yet.
+     * Activity tokens that are being reparented or being started to this container, but haven't
+     * been added to {@link #mInfo} yet.
      */
     @VisibleForTesting
-    final ArrayList<Activity> mPendingAppearedActivities = new ArrayList<>();
+    final ArrayList<IBinder> mPendingAppearedActivities = new ArrayList<>();
 
     /**
      * When this container is created for an {@link Intent} to start within, we store that Intent
@@ -84,8 +87,11 @@
     private final List<TaskFragmentContainer> mContainersToFinishOnExit =
             new ArrayList<>();
 
-    /** Individual associated activities in different containers that should be finished on exit. */
-    private final List<Activity> mActivitiesToFinishOnExit = new ArrayList<>();
+    /**
+     * Individual associated activity tokens in different containers that should be finished on
+     * exit.
+     */
+    private final List<IBinder> mActivitiesToFinishOnExit = new ArrayList<>();
 
     /** Indicates whether the container was cleaned up after the last activity was removed. */
     private boolean mIsFinished;
@@ -158,8 +164,9 @@
         // in this intermediate state.
         // Place those on top of the list since they will be on the top after reported from the
         // server.
-        for (Activity activity : mPendingAppearedActivities) {
-            if (!activity.isFinishing()) {
+        for (IBinder token : mPendingAppearedActivities) {
+            final Activity activity = mController.getActivity(token);
+            if (activity != null && !activity.isFinishing()) {
                 allActivities.add(activity);
             }
         }
@@ -203,55 +210,58 @@
 
     /** Adds the activity that will be reparented to this container. */
     void addPendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
-        if (hasActivity(pendingAppearedActivity.getActivityToken())) {
+        final IBinder activityToken = pendingAppearedActivity.getActivityToken();
+        if (hasActivity(activityToken)) {
             return;
         }
-        // Remove the pending activity from other TaskFragments.
-        mTaskContainer.cleanupPendingAppearedActivity(pendingAppearedActivity);
-        mPendingAppearedActivities.add(pendingAppearedActivity);
-        updateActivityClientRecordTaskFragmentToken(pendingAppearedActivity);
+        // Remove the pending activity from other TaskFragments in case the activity is reparented
+        // again before the server update.
+        mTaskContainer.cleanupPendingAppearedActivity(activityToken);
+        mPendingAppearedActivities.add(activityToken);
+        updateActivityClientRecordTaskFragmentToken(activityToken);
     }
 
     /**
      * Updates the {@link ActivityThread.ActivityClientRecord#mTaskFragmentToken} for the
      * activity. This makes sure the token is up-to-date if the activity is relaunched later.
      */
-    private void updateActivityClientRecordTaskFragmentToken(@NonNull Activity activity) {
+    private void updateActivityClientRecordTaskFragmentToken(@NonNull IBinder activityToken) {
         final ActivityThread.ActivityClientRecord record = ActivityThread
-                .currentActivityThread().getActivityClient(activity.getActivityToken());
+                .currentActivityThread().getActivityClient(activityToken);
         if (record != null) {
             record.mTaskFragmentToken = mToken;
         }
     }
 
-    void removePendingAppearedActivity(@NonNull Activity pendingAppearedActivity) {
-        mPendingAppearedActivities.remove(pendingAppearedActivity);
+    void removePendingAppearedActivity(@NonNull IBinder activityToken) {
+        mPendingAppearedActivities.remove(activityToken);
     }
 
     void clearPendingAppearedActivities() {
-        final List<Activity> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
+        final List<IBinder> cleanupActivities = new ArrayList<>(mPendingAppearedActivities);
         // Clear mPendingAppearedActivities so that #getContainerWithActivity won't return the
         // current TaskFragment.
         mPendingAppearedActivities.clear();
         mPendingAppearedIntent = null;
 
         // For removed pending activities, we need to update the them to their previous containers.
-        for (Activity activity : cleanupActivities) {
+        for (IBinder activityToken : cleanupActivities) {
             final TaskFragmentContainer curContainer = mController.getContainerWithActivity(
-                    activity);
+                    activityToken);
             if (curContainer != null) {
-                curContainer.updateActivityClientRecordTaskFragmentToken(activity);
+                curContainer.updateActivityClientRecordTaskFragmentToken(activityToken);
             }
         }
     }
 
     /** Called when the activity is destroyed. */
-    void onActivityDestroyed(@NonNull Activity activity) {
-        removePendingAppearedActivity(activity);
+    void onActivityDestroyed(@NonNull IBinder activityToken) {
+        removePendingAppearedActivity(activityToken);
         if (mInfo != null) {
             // Remove the activity now because there can be a delay before the server callback.
-            mInfo.getActivities().remove(activity.getActivityToken());
+            mInfo.getActivities().remove(activityToken);
         }
+        mActivitiesToFinishOnExit.remove(activityToken);
     }
 
     @Nullable
@@ -275,16 +285,24 @@
         mPendingAppearedIntent = null;
     }
 
-    boolean hasActivity(@NonNull IBinder token) {
-        if (mInfo != null && mInfo.getActivities().contains(token)) {
-            return true;
-        }
-        for (Activity activity : mPendingAppearedActivities) {
-            if (activity.getActivityToken().equals(token)) {
-                return true;
-            }
-        }
-        return false;
+    boolean hasActivity(@NonNull IBinder activityToken) {
+        // Instead of using (hasAppearedActivity() || hasPendingAppearedActivity), we want to make
+        // sure the controller considers this container as the one containing the activity.
+        // This is needed when the activity is added as pending appeared activity to one
+        // TaskFragment while it is also an appeared activity in another.
+        return mController.getContainerWithActivity(activityToken) == this;
+    }
+
+    /** Whether this activity has appeared in the TaskFragment on the server side. */
+    boolean hasAppearedActivity(@NonNull IBinder activityToken) {
+        return mInfo != null && mInfo.getActivities().contains(activityToken);
+    }
+
+    /**
+     * Whether we are waiting for this activity to appear in the TaskFragment on the server side.
+     */
+    boolean hasPendingAppearedActivity(@NonNull IBinder activityToken) {
+        return mPendingAppearedActivities.contains(activityToken);
     }
 
     int getRunningActivityCount() {
@@ -342,8 +360,8 @@
         // Cleanup activities that were being re-parented
         List<IBinder> infoActivities = mInfo.getActivities();
         for (int i = mPendingAppearedActivities.size() - 1; i >= 0; --i) {
-            final Activity activity = mPendingAppearedActivities.get(i);
-            if (infoActivities.contains(activity.getActivityToken())) {
+            final IBinder activityToken = mPendingAppearedActivities.get(i);
+            if (infoActivities.contains(activityToken)) {
                 mPendingAppearedActivities.remove(i);
             }
         }
@@ -392,7 +410,7 @@
         if (mIsFinished) {
             return;
         }
-        mActivitiesToFinishOnExit.add(activityToFinish);
+        mActivitiesToFinishOnExit.add(activityToFinish.getActivityToken());
     }
 
     /**
@@ -402,7 +420,7 @@
         if (mIsFinished) {
             return;
         }
-        mActivitiesToFinishOnExit.remove(activityToRemove);
+        mActivitiesToFinishOnExit.remove(activityToRemove.getActivityToken());
     }
 
     /** Removes all dependencies that should be finished when this container is finished. */
@@ -470,8 +488,9 @@
         mContainersToFinishOnExit.clear();
 
         // Finish associated activities
-        for (Activity activity : mActivitiesToFinishOnExit) {
-            if (activity.isFinishing()
+        for (IBinder activityToken : mActivitiesToFinishOnExit) {
+            final Activity activity = mController.getActivity(activityToken);
+            if (activity == null || activity.isFinishing()
                     || controller.shouldRetainAssociatedActivity(this, activity)) {
                 continue;
             }
@@ -540,7 +559,8 @@
         }
         int maxMinWidth = mInfo.getMinimumWidth();
         int maxMinHeight = mInfo.getMinimumHeight();
-        for (Activity activity : mPendingAppearedActivities) {
+        for (IBinder activityToken : mPendingAppearedActivities) {
+            final Activity activity = mController.getActivity(activityToken);
             final Size minDimensions = SplitPresenter.getMinDimensions(activity);
             if (minDimensions == null) {
                 continue;
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
index 2192b5c..b70b320 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/layout/WindowLayoutComponentImpl.java
@@ -35,7 +35,6 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.util.ArrayMap;
-import android.window.WindowContext;
 import android.window.WindowProvider;
 
 import androidx.annotation.NonNull;
@@ -310,20 +309,21 @@
         }
         final int windowingMode;
         if (context instanceof Activity) {
-            windowingMode = ActivityClient.getInstance().getTaskWindowingMode(
+            final Configuration taskConfig = ActivityClient.getInstance().getTaskConfiguration(
                     context.getActivityToken());
+            if (taskConfig == null) {
+                // If we cannot determine the task configuration for any reason, it is likely that
+                // we won't be able to determine its position correctly as well. DisplayFeatures'
+                // bounds in this case can't be computed correctly, so we should skip.
+                return false;
+            }
+            windowingMode = taskConfig.windowConfiguration.getWindowingMode();
         } else {
             // TODO(b/242674941): use task windowing mode for window context that associates with
             //  activity.
             windowingMode = context.getResources().getConfiguration().windowConfiguration
                     .getWindowingMode();
         }
-        if (windowingMode == -1) {
-            // If we cannot determine the task windowing mode for any reason, it is likely that we
-            // won't be able to determine its position correctly as well. DisplayFeatures' bounds
-            // in this case can't be computed correctly, so we should skip.
-            return false;
-        }
         // It is recommended not to report any display features in multi-window mode, since it
         // won't be possible to synchronize the display feature positions with window movement.
         return !WindowConfiguration.inMultiWindowMode(windowingMode);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
index 92011af..bc03e4e 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/EmbeddingTestUtils.java
@@ -21,6 +21,7 @@
 import static androidx.window.extensions.embedding.SplitRule.FINISH_ALWAYS;
 import static androidx.window.extensions.embedding.SplitRule.FINISH_NEVER;
 
+import static org.junit.Assert.assertFalse;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 
@@ -45,6 +46,8 @@
 import java.util.Collections;
 import java.util.List;
 
+// Suppress GuardedBy warning on unit tests
+@SuppressWarnings("GuardedBy")
 public class EmbeddingTestUtils {
     static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
     static final int TASK_ID = 10;
@@ -191,6 +194,15 @@
         return new TaskContainer(TASK_ID, activity);
     }
 
+    static TaskContainer createTestTaskContainer(@NonNull SplitController controller) {
+        final TaskContainer taskContainer = createTestTaskContainer();
+        final int taskId = taskContainer.getTaskId();
+        // Should not call to create TaskContainer with the same task id twice.
+        assertFalse(controller.mTaskContainers.contains(taskId));
+        controller.mTaskContainers.put(taskId, taskContainer);
+        return taskContainer;
+    }
+
     static WindowLayoutInfo createWindowLayoutInfo() {
         final FoldingFeature foldingFeature = new FoldingFeature(
                 new Rect(
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 87d0278..221c764 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -242,6 +242,14 @@
 
         assertTrue(tf.hasActivity(mActivity.getActivityToken()));
 
+        // When the activity is not finishing, do not clear the record.
+        doReturn(false).when(mActivity).isFinishing();
+        mSplitController.onActivityDestroyed(mActivity);
+
+        assertTrue(tf.hasActivity(mActivity.getActivityToken()));
+
+        // Clear the record when the activity is finishing and destroyed.
+        doReturn(true).when(mActivity).isFinishing();
         mSplitController.onActivityDestroyed(mActivity);
 
         assertFalse(tf.hasActivity(mActivity.getActivityToken()));
@@ -261,7 +269,7 @@
 
         assertNotNull(tf);
         assertNotNull(taskContainer);
-        assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds());
+        assertEquals(TASK_BOUNDS, taskContainer.getConfiguration().windowConfiguration.getBounds());
     }
 
     @Test
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
index af9c6ba..95328ce 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -23,7 +23,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.Display.DEFAULT_DISPLAY;
 
-import static androidx.window.extensions.embedding.EmbeddingTestUtils.TASK_BOUNDS;
 import static androidx.window.extensions.embedding.EmbeddingTestUtils.createTestTaskContainer;
 
 import static org.junit.Assert.assertEquals;
@@ -68,28 +67,6 @@
     }
 
     @Test
-    public void testIsTaskBoundsInitialized() {
-        final TaskContainer taskContainer = createTestTaskContainer();
-
-        assertFalse(taskContainer.isTaskBoundsInitialized());
-
-        taskContainer.setTaskBounds(TASK_BOUNDS);
-
-        assertTrue(taskContainer.isTaskBoundsInitialized());
-    }
-
-    @Test
-    public void testSetTaskBounds() {
-        final TaskContainer taskContainer = createTestTaskContainer();
-
-        assertFalse(taskContainer.setTaskBounds(new Rect()));
-
-        assertTrue(taskContainer.setTaskBounds(TASK_BOUNDS));
-
-        assertFalse(taskContainer.setTaskBounds(TASK_BOUNDS));
-    }
-
-    @Test
     public void testGetWindowingModeForSplitTaskFragment() {
         final TaskContainer taskContainer = createTestTaskContainer();
         final Rect splitBounds = new Rect(0, 0, 500, 1000);
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
index d43c471..99f56b4 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskFragmentContainerTest.java
@@ -161,7 +161,8 @@
         final TaskFragmentContainer pendingActivityContainer = new TaskFragmentContainer(mActivity,
                 null /* pendingAppearedIntent */, taskContainer, mController);
 
-        assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains(mActivity));
+        assertTrue(pendingActivityContainer.mPendingAppearedActivities.contains(
+                mActivity.getActivityToken()));
 
         final TaskFragmentInfo info0 = createMockTaskFragmentInfo(pendingActivityContainer,
                 mActivity);
@@ -317,7 +318,7 @@
 
     @Test
     public void testOnActivityDestroyed() {
-        final TaskContainer taskContainer = createTestTaskContainer();
+        final TaskContainer taskContainer = createTestTaskContainer(mController);
         final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
                 mIntent, taskContainer, mController);
         container.addPendingAppearedActivity(mActivity);
@@ -328,7 +329,7 @@
 
         assertTrue(container.hasActivity(mActivity.getActivityToken()));
 
-        taskContainer.onActivityDestroyed(mActivity);
+        taskContainer.onActivityDestroyed(mActivity.getActivityToken());
 
         // It should not contain the destroyed Activity.
         assertFalse(container.hasActivity(mActivity.getActivityToken()));
@@ -398,6 +399,79 @@
         assertFalse(taskContainer.isInIntermediateState());
     }
 
+    @Test
+    public void testHasAppearedActivity() {
+        final TaskContainer taskContainer = createTestTaskContainer();
+        final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+        container.addPendingAppearedActivity(mActivity);
+
+        assertFalse(container.hasAppearedActivity(mActivity.getActivityToken()));
+
+        final List<IBinder> activities = new ArrayList<>();
+        activities.add(mActivity.getActivityToken());
+        doReturn(activities).when(mInfo).getActivities();
+        container.setInfo(mTransaction, mInfo);
+
+        assertTrue(container.hasAppearedActivity(mActivity.getActivityToken()));
+    }
+
+    @Test
+    public void testHasPendingAppearedActivity() {
+        final TaskContainer taskContainer = createTestTaskContainer();
+        final TaskFragmentContainer container = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+        container.addPendingAppearedActivity(mActivity);
+
+        assertTrue(container.hasPendingAppearedActivity(mActivity.getActivityToken()));
+
+        final List<IBinder> activities = new ArrayList<>();
+        activities.add(mActivity.getActivityToken());
+        doReturn(activities).when(mInfo).getActivities();
+        container.setInfo(mTransaction, mInfo);
+
+        assertFalse(container.hasPendingAppearedActivity(mActivity.getActivityToken()));
+    }
+
+    @Test
+    public void testHasActivity() {
+        final TaskContainer taskContainer = createTestTaskContainer(mController);
+        final TaskFragmentContainer container1 = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+        final TaskFragmentContainer container2 = new TaskFragmentContainer(null /* activity */,
+                mIntent, taskContainer, mController);
+
+        // Activity is pending appeared on container2.
+        container2.addPendingAppearedActivity(mActivity);
+
+        assertFalse(container1.hasActivity(mActivity.getActivityToken()));
+        assertTrue(container2.hasActivity(mActivity.getActivityToken()));
+
+        // Activity is pending appeared on container1 (removed from container2).
+        container1.addPendingAppearedActivity(mActivity);
+
+        assertTrue(container1.hasActivity(mActivity.getActivityToken()));
+        assertFalse(container2.hasActivity(mActivity.getActivityToken()));
+
+        final List<IBinder> activities = new ArrayList<>();
+        activities.add(mActivity.getActivityToken());
+        doReturn(activities).when(mInfo).getActivities();
+
+        // Although Activity is appeared on container2, we prioritize pending appeared record on
+        // container1.
+        container2.setInfo(mTransaction, mInfo);
+
+        assertTrue(container1.hasActivity(mActivity.getActivityToken()));
+        assertFalse(container2.hasActivity(mActivity.getActivityToken()));
+
+        // When the pending appeared record is removed from container1, we respect the appeared
+        // record in container2.
+        container1.removePendingAppearedActivity(mActivity.getActivityToken());
+
+        assertFalse(container1.hasActivity(mActivity.getActivityToken()));
+        assertTrue(container2.hasActivity(mActivity.getActivityToken()));
+    }
+
     /** Creates a mock activity in the organizer process. */
     private Activity createMockActivity() {
         final Activity activity = mock(Activity.class);
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 42da075..904ae86 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Laat los"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Program sal dalk nie met verdeelde skerm werk nie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Program steun nie verdeelde skerm nie."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Hierdie app kan net in 1 venster oopgemaak word."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Program sal dalk nie op \'n sekondêre skerm werk nie."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Program steun nie begin op sekondêre skerms nie."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Skermverdeler"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index ef53c95..51de2e5 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"መተግበሪያ ከተከፈለ ማያ ገጽ ጋር ላይሠራ ይችላል"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ይህ መተግበሪያ መከፈት የሚችለው በ1 መስኮት ብቻ ነው።"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"መተግበሪያ በሁለተኛ ማሳያ ላይ ላይሠራ ይችላል።"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"መተግበሪያ በሁለተኛ ማሳያዎች ላይ ማስጀመርን አይደግፍም።"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"የተከፈለ የማያ ገጽ ከፋይ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index f5ea409..635334d 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"إظهار"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"قد لا يعمل التطبيق بشكل سليم في وضع \"تقسيم الشاشة\"."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"التطبيق لا يتيح تقسيم الشاشة."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"لا يمكن فتح هذا التطبيق إلا في نافذة واحدة."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"قد لا يعمل التطبيق على شاشة عرض ثانوية."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"لا يمكن تشغيل التطبيق على شاشات عرض ثانوية."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"أداة تقسيم الشاشة"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index c4cfcf7..788fd5c 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"দেখুৱাওক"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"এপ্‌টোৱে বিভাজিত স্ক্ৰীনৰ সৈতে কাম নকৰিব পাৰে।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"এপ্‌টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই এপ্‌টো কেৱল ১ খন ৱিণ্ড’ত খুলিব পাৰি।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"গৌণ ডিছপ্লেত এপে সঠিকভাৱে কাম নকৰিব পাৰে।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"গৌণ ডিছপ্লেত এপ্ লঞ্চ কৰিব নোৱাৰি।"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"স্প্লিট স্ক্ৰীনৰ বিভাজক"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 84f706a..a56918d 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Güvənli məkandan çıxarın"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Tətbiq bölünmüş ekran ilə işləməyə bilər."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu tətbiq yalnız 1 pəncərədə açıla bilər."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Tətbiq ikinci ekranda işləməyə bilər."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Tətbiq ikinci ekranda başlamağı dəstəkləmir."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcısı"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 2eb1ac2..dcb03aa 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Uklonite iz tajne memorije"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi sa podeljenim ekranom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podeljeni ekran."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija može da se otvori samo u jednom prozoru."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionisati na sekundarnom ekranu."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Razdelnik podeljenog ekrana"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index b6ce785..f6b285a 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Паказаць"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Праграма можа не працаваць у рэжыме падзеленага экрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Праграма не падтрымлівае функцыю дзялення экрана."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Гэту праграму можна адкрыць толькі ў адным акне."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Праграма можа не працаваць на дадатковых экранах."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Праграма не падтрымлівае запуск на дадатковых экранах."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Раздзяляльнік падзеленага экрана"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index ce22914..044f2a7 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Отмяна на съхраняването"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Приложението може да не работи в режим на разделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложението не поддържа разделен екран."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Това приложение може да се отвори само в 1 прозорец."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Възможно е приложението да не работи на алтернативни дисплеи."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложението не поддържа използването на алтернативни дисплеи."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Разделител в режима за разделен екран"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 52ae816..1fb0292 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"আনস্ট্যাস করুন"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"অ্যাপটি স্প্লিট স্ক্রিনে কাজ নাও করতে পারে।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"অ্যাপ্লিকেশান বিভক্ত-স্ক্রিন সমর্থন করে না৷"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"এই অ্যাপটি শুধু ১টি উইন্ডোয় খোলা যেতে পারে।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"সেকেন্ডারি ডিসপ্লেতে অ্যাপটি কাজ নাও করতে পারে।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"সেকেন্ডারি ডিসপ্লেতে অ্যাপ লঞ্চ করা যাবে না।"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"বিভক্ত-স্ক্রিন বিভাজক"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index e7ff6b6..8e52d78 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vađenje iz stasha"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće raditi na podijeljenom ekranu."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava dijeljenje ekrana."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova aplikacija se može otvoriti samo u 1 prozoru."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće raditi na sekundarnom ekranu."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim ekranima."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog ekrana"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 43c8bad..6bc4f99 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Deixa d\'amagar"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"És possible que l\'aplicació no funcioni amb la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'aplicació no admet la pantalla dividida."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aquesta aplicació només pot obrir-se en 1 finestra."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"És possible que l\'aplicació no funcioni en una pantalla secundària."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'aplicació no es pot obrir en pantalles secundàries."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalles"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 0d68e46..b638b0e 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušit uložení"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikace v režimu rozdělené obrazovky nemusí fungovat."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tuto aplikaci lze otevřít jen na jednom okně."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikace na sekundárním displeji nemusí fungovat."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikace nepodporuje spuštění na sekundárních displejích."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Čára rozdělující obrazovku"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 28c0064..e0b7a8c 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Vis"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen fungerer muligvis ikke i opdelt skærm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen understøtter ikke opdelt skærm."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne app kan kun åbnes i 1 vindue."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer muligvis ikke på sekundære skærme."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke åbnes på sekundære skærme."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Adskiller til opdelt skærm"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 41af26d..caca8b4 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Aus Stash entfernen"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Die App funktioniert unter Umständen im Modus für geteilten Bildschirm nicht."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Diese App kann nur in einem einzigen Fenster geöffnet werden."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Die App funktioniert auf einem sekundären Display möglicherweise nicht."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Die App unterstützt den Start auf sekundären Displays nicht."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Bildschirmteiler"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index 3e08ee1..ffb4fb0 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Κατάργηση απόκρυψης"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Η εφαρμογή ενδέχεται να μην λειτουργεί με διαχωρισμό οθόνης."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Αυτή η εφαρμογή μπορεί να ανοιχθεί μόνο σε 1 παράθυρο."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Η εφαρμογή ίσως να μην λειτουργήσει σε δευτερεύουσα οθόνη."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Η εφαρμογή δεν υποστηρίζει την εκκίνηση σε δευτερεύουσες οθόνες."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Διαχωριστικό οθόνης"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index 231c2649..c71011d 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
index 431c7ec..05091fb 100644
--- a/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rCA/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in 1 window."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Split-screen divider"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index 231c2649..c71011d 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index 231c2649..c71011d 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"App may not work with split-screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App does not support split-screen."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"This app can only be opened in one window."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App may not work on a secondary display."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App does not support launch on secondary displays."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Split screen divider"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
index f3e60d2..2993fe7 100644
--- a/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rXC/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‎‏‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‏‎‎‎‎‎‎‎‏‏‏‎‎Unstash‎‏‎‎‏‎"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‎‏‎‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‎‏‎‏‏‏‏‏‏‏‏‏‏‎‎‎App may not work with split-screen.‎‏‎‎‏‎"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‎‎‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‎‏‎‏‎‎‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‎‏‎App does not support split-screen.‎‏‎‎‏‎"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎This app can only be opened in 1 window.‎‏‎‎‏‎"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‎‎‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‎‏‎‏‎‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎App may not work on a secondary display.‎‏‎‎‏‎"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‎‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‏‎App does not support launch on secondary displays.‎‏‎‎‏‎"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‏‎‏‎‏‏‏‏‏‎‎‏‎‏‏‏‎Split-screen divider‎‏‎‎‏‎"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index fe29baa..0eaca8b 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Dejar de almacenar de manera segura"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la app no funcione en el modo de pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La app no es compatible con la función de pantalla dividida."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app solo puede estar abierta en 1 ventana."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la app no funcione en una pantalla secundaria."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La app no puede iniciarse en pantallas secundarias."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index 8f20e16..9c8fed1 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"No esconder"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Es posible que la aplicación no funcione con la pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"La aplicación no admite la pantalla dividida."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación solo puede abrirse en una ventana."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Es posible que la aplicación no funcione en una pantalla secundaria."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"La aplicación no se puede abrir en pantallas secundarias."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Dividir la pantalla"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 698e5cc..e8cbe53 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Eemalda hoidlast"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Rakendus ei pruugi poolitatud ekraaniga töötada."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Rakendus ei toeta jagatud ekraani."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Selle rakenduse saab avada ainult ühes aknas."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Rakendus ei pruugi teisesel ekraanil töötada."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Rakendus ei toeta teisestel ekraanidel käivitamist."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Ekraanijagaja"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index 629c745..4417668 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ez gorde"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikazioak ez du onartzen pantaila zatitua"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Leiho bakar batean ireki daiteke aplikazioa."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Baliteke aplikazioak ez funtzionatzea bigarren mailako pantailetan."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikazioa ezin da abiarazi bigarren mailako pantailatan."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Pantaila-zatitzailea"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index b7920ef..7375faf 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"لغو مخفی‌سازی"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن است برنامه با «صفحهٔ دونیمه» کار نکند."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"برنامه از تقسیم صفحه پشتیبانی نمی‌کند."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"این برنامه فقط در ۱ پنجره می‌تواند باز شود."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن است برنامه در نمایشگر ثانویه کار نکند."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"برنامه از راه‌اندازی در نمایشگرهای ثانویه پشتیبانی نمی‌کند."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"تقسیم‌کننده صفحه"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index 18def67..7729d1c 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poista turvasäilytyksestä"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Sovellus ei ehkä toimi jaetulla näytöllä."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Sovellus ei tue jaetun näytön tilaa."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Tämän sovelluksen voi avata vain yhdessä ikkunassa."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Sovellus ei ehkä toimi toissijaisella näytöllä."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Sovellus ei tue käynnistämistä toissijaisilla näytöillä."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Näytön jakaja"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index 5146d1c..6348800 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Retirer de la réserve"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'application n\'est pas compatible avec l\'écran partagé."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette application ne peut être ouverte que dans une fenêtre."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index 1ee8f68..1842213 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Il est possible que l\'application ne fonctionne pas en mode Écran partagé."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Application incompatible avec l\'écran partagé."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Cette appli ne peut être ouverte que dans 1 fenêtre."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Il est possible que l\'application ne fonctionne pas sur un écran secondaire."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'application ne peut pas être lancée sur des écrans secondaires."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Séparateur d\'écran partagé"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index 6a8add8..2e05d4c 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Non esconder"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Pode que a aplicación non funcione coa pantalla dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A aplicación non é compatible coa función de pantalla dividida."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta aplicación só se pode abrir en 1 ventá."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É posible que a aplicación non funcione nunha pantalla secundaria."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A aplicación non se pode iniciar en pantallas secundarias."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor de pantalla dividida"</string>
diff --git a/libs/WindowManager/Shell/res/values-gu/strings.xml b/libs/WindowManager/Shell/res/values-gu/strings.xml
index de131995..e680298 100644
--- a/libs/WindowManager/Shell/res/values-gu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gu/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"બતાવો"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"વિભાજિત-સ્ક્રીન સાથે ઍપ કદાચ કામ ન કરે."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ઍપ્લિકેશન સ્ક્રીન-વિભાજનનું સમર્થન કરતી નથી."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"આ ઍપ માત્ર 1 વિન્ડોમાં ખોલી શકાય છે."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર કદાચ કામ ન કરે."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ઍપ્લિકેશન ગૌણ ડિસ્પ્લે પર લૉન્ચનું સમર્થન કરતી નથી."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"સ્પ્લિટ-સ્ક્રીન વિભાજક"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index df0ebb3..1a7cf3e 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -34,6 +34,8 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"दिखाएं"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ऐप्लिकेशन शायद स्प्लिट स्क्रीन मोड में काम न करे."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ऐप विभाजित स्‍क्रीन का समर्थन नहीं करता है."</string>
+    <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
+    <skip />
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"हो सकता है कि ऐप प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर काम न करे."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"प्राइमरी (मुख्य) डिस्प्ले के अलावा बाकी दूसरे डिस्प्ले पर ऐप लॉन्च नहीं किया जा सकता."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"विभाजित स्क्रीन विभाजक"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index 8d20c9d1..23a5970 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Poništite sakrivanje"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija možda neće funkcionirati s podijeljenim zaslonom."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podržava podijeljeni zaslon."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ova se aplikacija može otvoriti samo u jednom prozoru."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija možda neće funkcionirati na sekundarnom zaslonu."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podržava pokretanje na sekundarnim zaslonima."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Razdjelnik podijeljenog zaslona"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index ed4c354..1bbbdb7 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Félretevés megszüntetése"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Lehet, hogy az alkalmazás nem működik osztott képernyős nézetben."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Az alkalmazás nem támogatja az osztott képernyős nézetet."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ez az alkalmazás csak egy ablakban nyitható meg."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Előfordulhat, hogy az alkalmazás nem működik másodlagos kijelzőn."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Az alkalmazást nem lehet másodlagos kijelzőn elindítani."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Elválasztó az osztott nézetben"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 31ead01..6eef4af 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ցուցադրել"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Հավելվածը չի կարող աշխատել տրոհված էկրանի ռեժիմում։"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Հավելվածը չի աջակցում էկրանի տրոհումը:"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Այս հավելվածը հնարավոր է բացել միայն մեկ պատուհանում։"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Հավելվածը կարող է չաշխատել լրացուցիչ էկրանի վրա"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Հավելվածը չի աջակցում գործարկումը լրացուցիչ էկրանների վրա"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Տրոհված էկրանի բաժանիչ"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index e0e1801..61a9558 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Batalkan stash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikasi mungkin tidak berfungsi dengan layar terpisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App tidak mendukung layar terpisah."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplikasi ini hanya dapat dibuka di 1 jendela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikasi mungkin tidak berfungsi pada layar sekunder."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikasi tidak mendukung peluncuran pada layar sekunder."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Pembagi layar terpisah"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 4b0e812..0b873bc 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Taka úr geymslu"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Hugsanlega virkar forritið ekki með skjáskiptingu."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Forritið styður ekki að skjánum sé skipt."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aðeins er hægt að opna þetta forrit í 1 glugga."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Hugsanlegt er að forritið virki ekki á öðrum skjá."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Forrit styður ekki opnun á öðrum skjá."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Skjáskipting"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 4226a84..da4d0bb 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Annulla accantonamento"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"L\'app potrebbe non funzionare con lo schermo diviso."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"L\'app non supporta la modalità Schermo diviso."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Questa app può essere aperta soltanto in 1 finestra."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"L\'app potrebbe non funzionare su un display secondario."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"L\'app non supporta l\'avvio su display secondari."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Strumento per schermo diviso"</string>
diff --git a/libs/WindowManager/Shell/res/values-iw/strings.xml b/libs/WindowManager/Shell/res/values-iw/strings.xml
index 038a2232..e9a53dd 100644
--- a/libs/WindowManager/Shell/res/values-iw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-iw/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ביטול ההסתרה הזמנית"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ייתכן שהאפליקציה לא תפעל במסך מפוצל."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"האפליקציה אינה תומכת במסך מפוצל."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ניתן לפתוח את האפליקציה הזו רק בחלון אחד."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ייתכן שהאפליקציה לא תפעל במסך משני."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"האפליקציה אינה תומכת בהפעלה במסכים משניים."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"מחלק מסך מפוצל"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 315f074..2930cc3 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"表示"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"アプリは分割画面では動作しないことがあります。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"アプリで分割画面がサポートされていません。"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"このアプリはウィンドウが 1 つの場合のみ開くことができます。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"アプリはセカンダリ ディスプレイでは動作しないことがあります。"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"アプリはセカンダリ ディスプレイでの起動に対応していません。"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"分割画面の分割線"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 1ff6ff8..848be3f 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"გადანახვის გაუქმება"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"აპმა შეიძლება არ იმუშაოს გაყოფილი ეკრანის რეჟიმში."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ამ აპის გახსნა შესაძლებელია მხოლოდ 1 ფანჯარაში."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"აპმა შეიძლება არ იმუშაოს მეორეულ ეკრანზე."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"აპს არ გააჩნია მეორეული ეკრანის მხარდაჭერა."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index 933d0ca..8d08ccab 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Көрсету"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Қолданба экранды бөлу режимінде жұмыс істемеуі мүмкін."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Қодланба бөлінген экранды қолдамайды."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бұл қолданбаны тек 1 терезеден ашуға болады."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Қолданба қосымша дисплейде жұмыс істемеуі мүмкін."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Қолданба қосымша дисплейлерде іске қосуды қолдамайды."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Бөлінген экран бөлгіші"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index c1cb1dd..7c4ea57e 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ឈប់លាក់ជាបណ្ដោះអាសន្ន"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"កម្មវិធី​អាចនឹងមិន​ដំណើរការ​ជាមួយ​មុខងារបំបែកអេក្រង់​ទេ។"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"កម្មវិធីមិនគាំទ្រអេក្រង់បំបែកជាពីរទេ"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"កម្មវិធីនេះអាចបើកនៅក្នុងវិនដូតែ 1 ប៉ុណ្ណោះ។"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"កម្មវិធីនេះ​ប្រហែល​ជាមិនដំណើរការ​នៅលើ​អេក្រង់បន្ទាប់បន្សំទេ។"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"កម្មវិធី​នេះមិន​អាច​ចាប់ផ្តើម​នៅលើ​អេក្រង់បន្ទាប់បន្សំបានទេ។"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"កម្មវិធីចែកអេក្រង់បំបែក"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index c7fe59b..7290617 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ಅನ್‌ಸ್ಟ್ಯಾಶ್ ಮಾಡಿ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ವಿಭಜಿಸಿದ ಸ್ಕ್ರೀನ್‌ನಲ್ಲಿ ಆ್ಯಪ್ ಕೆಲಸ ಮಾಡದೇ ಇರಬಹುದು."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ಅಪ್ಲಿಕೇಶನ್ ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ಈ ಆ್ಯಪ್ ಅನ್ನು 1 ವಿಂಡೋದಲ್ಲಿ ಮಾತ್ರ ತೆರೆಯಬಹುದು."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್‌ ಕಾರ್ಯ ನಿರ್ವಹಿಸದೇ ಇರಬಹುದು."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ಸೆಕೆಂಡರಿ ಡಿಸ್‌ಪ್ಲೇಗಳಲ್ಲಿ ಪ್ರಾರಂಭಿಸುವಿಕೆಯನ್ನು ಅಪ್ಲಿಕೇಶನ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"ಸ್ಪ್ಲಿಟ್-ಪರದೆ ಡಿವೈಡರ್"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 17c51d9..59b405f 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"숨기기 취소"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"앱이 분할 화면에서 작동하지 않을 수 있습니다."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"앱이 화면 분할을 지원하지 않습니다."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"이 앱은 창 1개에서만 열 수 있습니다."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"앱이 보조 디스플레이에서 작동하지 않을 수도 있습니다."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"앱이 보조 디스플레이에서의 실행을 지원하지 않습니다."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"화면 분할기"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index 4329276..69ec8eb 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Сейфтен чыгаруу"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Колдонмодо экран бөлүнбөйт."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Бул колдонмону 1 терезеде гана ачууга болот."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Колдонмо кошумча экранда иштебей коюшу мүмкүн."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Колдонмону кошумча экрандарда иштетүүгө болбойт."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Экранды бөлгүч"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index e0a92b8..d5ea3cf 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ເອົາອອກຈາກບ່ອນເກັບສ່ວນຕົວ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ແອັບອາດໃຊ້ບໍ່ໄດ້ກັບການແບ່ງໜ້າຈໍ."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ແອັບບໍ່ຮອງຮັບໜ້າຈໍແບບແຍກກັນ."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ແອັບນີ້ສາມາດເປີດໄດ້ໃນ 1 ໜ້າຈໍເທົ່ານັ້ນ."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ແອັບອາດບໍ່ສາມາດໃຊ້ໄດ້ໃນໜ້າຈໍທີສອງ."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ແອັບບໍ່ຮອງຮັບການເປີດໃນໜ້າຈໍທີສອງ."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"ຕົວຂັ້ນການແບ່ງໜ້າຈໍ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 50565a7..922f5b5 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Nebeslėpti"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Programa gali neveikti naudojant išskaidyto ekrano režimą."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programoje nepalaikomas skaidytas ekranas."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šią programą galima atidaryti tik viename lange."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Programa gali neveikti antriniame ekrane."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programa nepalaiko paleisties antriniuose ekranuose."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Skaidyto ekrano daliklis"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 7126094..08ac928 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Rādīt"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Iespējams, lietotne nedarbosies ekrāna sadalīšanas režīmā."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Šo lietotni var atvērt tikai vienā logā."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Lietotne, iespējams, nedarbosies sekundārajā displejā."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Lietotnē netiek atbalstīta palaišana sekundārajos displejos."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Ekrāna sadalītājs"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index 41f549e..ae71ae9 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Прикажете"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликацијата може да не работи со поделен екран."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликацијата не поддржува поделен екран."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Апликацијава може да се отвори само во еден прозорец."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликацијата може да не функционира на друг екран."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликацијата не поддржува стартување на други екрани."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Разделник на поделен екран"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index b21e5b4..1f2ee77 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -34,6 +34,8 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"അൺസ്റ്റാഷ് ചെയ്യൽ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"സ്‌ക്രീൻ വിഭജന മോഡിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
+    <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
+    <skip />
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"രണ്ടാം ഡിസ്‌പ്ലേയിൽ ആപ്പ് പ്രവർത്തിച്ചേക്കില്ല."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"രണ്ടാം ഡിസ്‌പ്ലേകളിൽ സമാരംഭിക്കുന്നതിനെ ആപ്പ് അനുവദിക്കുന്നില്ല."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"സ്പ്ലിറ്റ്-സ്ക്രീൻ ഡിവൈഡർ"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index d713258..c1950a1 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Ил гаргах"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апп хуваагдсан дэлгэц дээр ажиллахгүй байж болзошгүй."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Энэ апп нь дэлгэц хуваах тохиргоог дэмждэггүй."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Энэ аппыг зөвхөн 1 цонхонд нээх боломжтой."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апп хоёрдогч дэлгэцэд ажиллахгүй."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Аппыг хоёрдогч дэлгэцэд эхлүүлэх боломжгүй."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"\"Дэлгэц хуваах\" хуваагч"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 1b53175..29821f6 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्टॅश करा"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"अ‍ॅप कदाचित स्प्लिट स्क्रीनसह काम करू शकत नाही."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अ‍ॅप स्क्रीन-विभाजनास समर्थन देत नाही."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"हे अ‍ॅप फक्त एका विंडोमध्ये उघडले जाऊ शकते."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"दुसऱ्या डिस्प्लेवर अ‍ॅप कदाचित चालणार नाही."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"दुसऱ्या डिस्प्लेवर अ‍ॅप लाँच होणार नाही."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रीन विभाजक"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index e648a7a..c3db19d 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Tunjukkan"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Apl tidak menyokong skrin pisah."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Apl ini hanya boleh dibuka dalam 1 tetingkap."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Apl mungkin tidak berfungsi pada paparan kedua."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Apl tidak menyokong pelancaran pada paparan kedua."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Pembahagi skrin pisah"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 96a6412..b2bb37d 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"မသိုဝှက်ရန်"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းဖြင့် အက်ပ်သည် အလုပ်မလုပ်ပါ။"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"အက်ပ်သည် မျက်နှာပြင်ခွဲပြရန် ပံ့ပိုးထားခြင်းမရှိပါ။"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ဤအက်ပ်ကို ဝင်းဒိုး ၁ ခုတွင်သာ ဖွင့်နိုင်သည်။"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ဤအက်ပ်အနေဖြင့် ဒုတိယဖန်သားပြင်ပေါ်တွင် အလုပ်လုပ်မည် မဟုတ်ပါ။"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ဤအက်ပ်အနေဖြင့် ဖွင့်ရန်စနစ်ကို ဒုတိယဖန်သားပြင်မှ အသုံးပြုရန် ပံ့ပိုးမထားပါ။"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index b6cea3f..90b9dfc 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Avslutt oppbevaring"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Det kan hende at appen ikke fungerer med delt skjerm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen støtter ikke delt skjerm."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denne appen kan bare åpnes i ett vindu."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen fungerer kanskje ikke på en sekundær skjerm."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan ikke kjøres på sekundære skjermer."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Skilleelement for delt skjerm"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index 4413a43..0f6b155 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -34,6 +34,8 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"अनस्ट्यास गर्नुहोस्"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"एप विभाजित स्क्रिनमा काम नगर्न सक्छ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"अनुप्रयोगले विभाजित-स्क्रिनलाई समर्थन गर्दैन।"</string>
+    <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
+    <skip />
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"यो एपले सहायक प्रदर्शनमा काम नगर्नसक्छ।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"अनुप्रयोगले सहायक प्रदर्शनहरूमा लञ्च सुविधालाई समर्थन गर्दैन।"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"विभाजित-स्क्रिन छुट्याउने"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 2e45143..f9f4ef4 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Niet meer verbergen"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"De app werkt mogelijk niet met gesplitst scherm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"App biedt geen ondersteuning voor gesplitst scherm."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Deze app kan slechts in 1 venster worden geopend."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"App werkt mogelijk niet op een secundair scherm."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"App kan niet op secundaire displays worden gestart."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Scheiding voor gesplitst scherm"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 7f0897f..5a76a6f 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ଦେଖାନ୍ତୁ"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ସ୍ପ୍ଲିଟ୍-ସ୍କ୍ରିନରେ ଆପ୍ କାମ କରିନପାରେ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ଆପ୍‍ ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନକୁ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ଏହି ଆପକୁ କେବଳ 1ଟି ୱିଣ୍ଡୋରେ ଖୋଲାଯାଇପାରିବ।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ କାମ ନକରିପାରେ।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ସେକେଣ୍ଡାରୀ ଡିସପ୍ଲେରେ ଆପ୍‍ ଲଞ୍ଚ ସପୋର୍ଟ କରେ ନାହିଁ।"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"ସ୍ପ୍ଲିଟ୍‍-ସ୍କ୍ରୀନ ବିଭାଜକ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index aa250d5..617c95e 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ਅਣਸਟੈਸ਼"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਨੂੰ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ਇਹ ਐਪ ਸਿਰਫ਼ 1 ਵਿੰਡੋ ਵਿੱਚ ਖੋਲ੍ਹੀ ਜਾ ਸਕਦੀ ਹੈ।"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇ \'ਤੇ ਕੰਮ ਨਾ ਕਰੇ।"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ਐਪ ਸੈਕੰਡਰੀ ਡਿਸਪਲੇਆਂ \'ਤੇ ਲਾਂਚ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਡਿਵਾਈਡਰ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 3c3d7aa..4a17ec7 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zabierz ze schowka"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacja może nie działać przy podzielonym ekranie."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacja nie obsługuje dzielonego ekranu."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ta aplikacja może być otwarta tylko w 1 oknie."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacja może nie działać na dodatkowym ekranie."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacja nie obsługuje uruchamiania na dodatkowych ekranach."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Linia dzielenia ekranu"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index cad59e0..69be68e 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index 26772dc..13e83ac 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Remover do armazenamento"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"A app pode não funcionar com o ecrã dividido."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"A app não é compatível com o ecrã dividido."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Esta app só pode ser aberta em 1 janela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"A app pode não funcionar num ecrã secundário."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"A app não é compatível com o início em ecrãs secundários."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor do ecrã dividido"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index cad59e0..69be68e 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Exibir"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"É possível que o app não funcione com a tela dividida."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"O app não é compatível com a divisão de tela."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Este app só pode ser aberto em uma única janela."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"É possível que o app não funcione em uma tela secundária."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"O app não é compatível com a inicialização em telas secundárias."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divisor de tela"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 607d997..c112a9d 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Anulează stocarea"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Este posibil ca aplicația să nu funcționeze cu ecranul împărțit."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplicația nu acceptă ecranul împărțit."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Aplicația poate fi deschisă într-o singură fereastră."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Este posibil ca aplicația să nu funcționeze pe un ecran secundar."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplicația nu acceptă lansare pe ecrane secundare."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Separator pentru ecranul împărțit"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index bed76e4..489adc0 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показать"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"В режиме разделения экрана приложение может работать нестабильно."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Приложение не поддерживает разделение экрана."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Это приложение можно открыть только в одном окне."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Приложение может не работать на дополнительном экране"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Приложение не поддерживает запуск на дополнительных экранах"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Разделитель экрана"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index 0ed3b8e..3237114 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"සඟවා තැබීම ඉවත් කරන්න"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"යෙදුම බෙදුම් තිරය සමග ක්‍රියා නොකළ හැකිය"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"යෙදුම බෙදුණු-තිරය සඳහා සහාය නොදක්වයි."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"මෙම යෙදුම විවෘත කළ හැක්කේ 1 කවුළුවක පමණයි."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"යෙදුම ද්විතියික සංදර්ශකයක ක්‍රියා නොකළ හැකිය."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"යෙදුම ද්විතීයික සංදර්ශක මත දියත් කිරීම සඳහා සහාය නොදක්වයි."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"බෙදුම්-තිර වෙන්කරණය"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index f20e940..a753021 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Zrušiť skrytie"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikácia nemusí fungovať s rozdelenou obrazovkou."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Táto aplikácia môže byť otvorená iba v jednom okne."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikácia nemusí fungovať na sekundárnej obrazovke."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikácia nepodporuje spúšťanie na sekundárnych obrazovkách."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Rozdeľovač obrazovky"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index e2063d8..b5d8733 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Razkrij"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacija morda ne deluje v načinu razdeljenega zaslona."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"To aplikacijo je mogoče odpreti samo v enem oknu."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacija morda ne bo delovala na sekundarnem zaslonu."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacija ne podpira zagona na sekundarnih zaslonih."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Razdelilnik zaslonov"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index 0c3947d..ebd644c 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Mos e fshih"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Aplikacioni mund të mos funksionojë me ekranin e ndarë."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ky aplikacion mund të hapet vetëm në 1 dritare."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Aplikacioni mund të mos funksionojë në një ekran dytësor."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Aplikacioni nuk mbështet nisjen në ekrane dytësore."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Ndarësi i ekranit të ndarë"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index 140d3db..d051ca3 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Уклоните из тајне меморије"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Апликација можда неће радити са подељеним екраном."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Апликација не подржава подељени екран."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ова апликација може да се отвори само у једном прозору."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Апликација можда неће функционисати на секундарном екрану."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Апликација не подржава покретање на секундарним екранима."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Разделник подељеног екрана"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 62220c4..cd46039 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Återställ stash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Appen kanske inte fungerar med delad skärm."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Appen har inte stöd för delad skärm."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Denna app kan bara vara öppen i ett fönster."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Appen kanske inte fungerar på en sekundär skärm."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Appen kan inte köras på en sekundär skärm."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Avdelare för delad skärm"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index 232b268..345fbf8 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Fichua"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Huenda programu isifanye kazi kwenye skrini inayogawanywa."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Programu hii inaweza kufunguliwa katika dirisha 1 pekee."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Huenda programu isifanye kazi kwenye dirisha lingine."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Programu hii haiwezi kufunguliwa kwenye madirisha mengine."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Kitenganishi cha skrini inayogawanywa"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index 90bf263..2039685 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -34,6 +34,8 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"திரைப் பிரிப்பு அம்சத்தில் ஆப்ஸ் செயல்படாமல் போகக்கூடும்."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"திரையைப் பிரிப்பதைப் ஆப்ஸ் ஆதரிக்கவில்லை."</string>
+    <!-- no translation found for dock_multi_instances_not_supported_text (5242868470666346929) -->
+    <skip />
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"இரண்டாம்நிலைத் திரையில் ஆப்ஸ் வேலை செய்யாமல் போகக்கூடும்."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"இரண்டாம்நிலைத் திரைகளில் பயன்பாட்டைத் தொடங்க முடியாது."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"திரையைப் பிரிக்கும் பிரிப்பான்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 7a2a8a8..0c0114a 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"ఆన్‌స్టాచ్"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"స్క్రీన్ విభజనతో యాప్‌ పని చేయకపోవచ్చు."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"యాప్‌లో స్క్రీన్ విభజనకు మద్దతు లేదు."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"ఈ యాప్‌ను 1 విండోలో మాత్రమే తెరవవచ్చు."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ప్రత్యామ్నాయ డిస్‌ప్లేలో యాప్ పని చేయకపోవచ్చు."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ప్రత్యామ్నాయ డిస్‌ప్లేల్లో ప్రారంభానికి యాప్ మద్దతు లేదు."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"విభజన స్క్రీన్ విభాగిని"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 76cbb1a..9f3a146 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"เอาออกจากที่เก็บส่วนตัว"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"แอปอาจใช้ไม่ได้กับโหมดแบ่งหน้าจอ"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"แอปไม่สนับสนุนการแยกหน้าจอ"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"แอปนี้เปิดได้ใน 1 หน้าต่างเท่านั้น"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"แอปอาจไม่ทำงานในจอแสดงผลรอง"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"แอปไม่รองรับการเรียกใช้ในจอแสดงผลรอง"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"เส้นแบ่งหน้าจอ"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index 103d072..c20a07f 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"I-unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Posibleng hindi gumana ang app sa split screen."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Hindi sinusuportahan ng app ang split-screen."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Sa 1 window lang puwedeng buksan ang app na ito."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Maaaring hindi gumana ang app sa pangalawang display."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Hindi sinusuportahan ng app ang paglulunsad sa mga pangalawang display."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Divider ng split-screen"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 0b82db7..aeb86da 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Depolama"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Uygulama bölünmüş ekranda çalışmayabilir."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uygulama bölünmüş ekranı desteklemiyor."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu uygulama yalnızca 1 pencerede açılabilir."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uygulama ikincil ekranda çalışmayabilir."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uygulama ikincil ekranlarda başlatılmayı desteklemiyor."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Bölünmüş ekran ayırıcı"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index 59b7673..b589ed8 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Показати"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Додаток може не працювати в режимі розділеного екрана."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Додаток не підтримує розділення екрана."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Цей додаток можна відкрити лише в одному вікні."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Додаток може не працювати на додатковому екрані."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Додаток не підтримує запуск на додаткових екранах."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Розділювач екрана"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 743c063..81672bf 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Unstash"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"ممکن ہے کہ ایپ اسپلٹ اسکرین کے ساتھ کام نہ کرے۔"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"یہ ایپ صرف 1 ونڈو میں کھولی جا سکتی ہے۔"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"ممکن ہے ایپ ثانوی ڈسپلے پر کام نہ کرے۔"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"ایپ ثانوی ڈسپلیز پر شروعات کا تعاون نہیں کرتی۔"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"سپلٹ اسکرین تقسیم کار"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 3b9324f..d0384e9 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Chiqarish"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Bu ilova ekranni ikkiga ajratish rejimini dastaklamaydi."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Bu ilova ekranni bo‘lish xususiyatini qo‘llab-quvvatlamaydi."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Bu ilovani faqat 1 ta oynada ochish mumkin."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Bu ilova qo‘shimcha ekranda ishlamasligi mumkin."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Bu ilova qo‘shimcha ekranlarda ishga tushmaydi."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Ekranni ikkiga bo‘lish chizig‘i"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 8583621..49986b5 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Hiện"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Ứng dụng có thể không hoạt động với tính năng chia đôi màn hình."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Ứng dụng này chỉ có thể mở 1 cửa sổ."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Ứng dụng có thể không hoạt động trên màn hình phụ."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Ứng dụng không hỗ trợ khởi chạy trên màn hình phụ."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Bộ chia chia đôi màn hình"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index d20626d..acdb252 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消隐藏"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"应用可能无法在分屏模式下正常运行。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"应用不支持分屏。"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此应用只能在 1 个窗口中打开。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"应用可能无法在辅显示屏上正常运行。"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"应用不支持在辅显示屏上启动。"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"分屏分隔线"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f53dc7d..b1a957e5 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消保護"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"應用程式不支援分割畫面。"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"此應用程式只可在 1 個視窗中開啟"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示屏上運作。"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示屏上啟動。"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 4b33ab6..bb3dba1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"取消暫時隱藏"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"應用程式可能無法在分割畫面中運作。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"這個應用程式不支援分割畫面。"</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"這個應用程式只能在 1 個視窗中開啟。"</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"應用程式可能無法在次要顯示器上運作。"</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"應用程式無法在次要顯示器上啟動。"</string>
     <string name="accessibility_divider" msgid="703810061635792791">"分割畫面分隔線"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index cd128b6..51a23ff 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -34,6 +34,7 @@
     <string name="accessibility_action_pip_unstash" msgid="7467499339610437646">"Susa isiteshi"</string>
     <string name="dock_forced_resizable" msgid="1749750436092293116">"Izinhlelo zokusebenza kungenzeka zingasebenzi ngesikrini esihlukanisiwe."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="7408396418008948957">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
+    <string name="dock_multi_instances_not_supported_text" msgid="5242868470666346929">"Le-app ingavulwa kuphela ewindini eli-1."</string>
     <string name="forced_resizable_secondary_display" msgid="1768046938673582671">"Uhlelo lokusebenza kungenzeka lungasebenzi kusibonisi sesibili."</string>
     <string name="activity_launch_on_secondary_display_failed_text" msgid="4226485344988071769">"Uhlelo lokusebenza alusekeli ukuqalisa kuzibonisi zesibili."</string>
     <string name="accessibility_divider" msgid="703810061635792791">"Isihlukanisi sokuhlukanisa isikrini"</string>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
index a0dde6a..2ec9e8b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/Interpolators.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.animation;
 
+import android.graphics.Path;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
@@ -53,6 +54,11 @@
     public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
 
     /**
+     * The default emphasized interpolator. Used for hero / emphasized movement of content.
+     */
+    public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
+
+    /**
      * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
      * is disappearing e.g. when moving off screen.
      */
@@ -81,4 +87,14 @@
 
     public static final PathInterpolator DIM_INTERPOLATOR =
             new PathInterpolator(.23f, .87f, .52f, -0.11f);
+
+    // Create the default emphasized interpolator
+    private static PathInterpolator createEmphasizedInterpolator() {
+        Path path = new Path();
+        // Doing the same as fast_out_extra_slow_in
+        path.moveTo(0f, 0f);
+        path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+        path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+        return new PathInterpolator(path);
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java
new file mode 100644
index 0000000..36cf29a
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationBackground.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.back;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import android.annotation.NonNull;
+import android.graphics.Color;
+import android.view.SurfaceControl;
+
+import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
+
+/**
+ * Controls background surface for the back animations
+ */
+public class BackAnimationBackground {
+    private static final int BACKGROUND_LAYER = -1;
+    private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
+    private SurfaceControl mBackgroundSurface;
+
+    public BackAnimationBackground(RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+        mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
+    }
+
+    void ensureBackground(int color, @NonNull SurfaceControl.Transaction transaction) {
+        if (mBackgroundSurface != null) {
+            return;
+        }
+
+        final float[] colorComponents = new float[] { Color.red(color) / 255.f,
+                Color.green(color) / 255.f, Color.blue(color) / 255.f };
+
+        final SurfaceControl.Builder colorLayerBuilder = new SurfaceControl.Builder()
+                .setName("back-animation-background")
+                .setCallsite("BackAnimationBackground")
+                .setColorLayer();
+
+        mRootTaskDisplayAreaOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, colorLayerBuilder);
+        mBackgroundSurface = colorLayerBuilder.build();
+        transaction.setColor(mBackgroundSurface, colorComponents)
+                .setLayer(mBackgroundSurface, BACKGROUND_LAYER)
+                .show(mBackgroundSurface);
+    }
+
+    void removeBackground(@NonNull SurfaceControl.Transaction transaction) {
+        if (mBackgroundSurface == null) {
+            return;
+        }
+
+        if (mBackgroundSurface.isValid()) {
+            transaction.remove(mBackgroundSurface);
+        }
+        mBackgroundSurface = null;
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index f811940..57a0fd5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -47,6 +47,7 @@
 import android.view.RemoteAnimationTarget;
 import android.window.BackAnimationAdapter;
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 import android.window.BackNavigationInfo;
 import android.window.IBackAnimationFinishedCallback;
 import android.window.IBackAnimationRunner;
@@ -138,14 +139,18 @@
         }
     };
 
+    private final BackAnimationBackground mAnimationBackground;
+
     public BackAnimationController(
             @NonNull ShellInit shellInit,
             @NonNull ShellController shellController,
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler backgroundHandler,
-            Context context) {
+            Context context,
+            @NonNull BackAnimationBackground backAnimationBackground) {
         this(shellInit, shellController, shellExecutor, backgroundHandler,
-                ActivityTaskManager.getService(), context, context.getContentResolver());
+                ActivityTaskManager.getService(), context, context.getContentResolver(),
+                backAnimationBackground);
     }
 
     @VisibleForTesting
@@ -155,7 +160,8 @@
             @NonNull @ShellMainThread ShellExecutor shellExecutor,
             @NonNull @ShellBackgroundThread Handler bgHandler,
             @NonNull IActivityTaskManager activityTaskManager,
-            Context context, ContentResolver contentResolver) {
+            Context context, ContentResolver contentResolver,
+            @NonNull BackAnimationBackground backAnimationBackground) {
         mShellController = shellController;
         mShellExecutor = shellExecutor;
         mActivityTaskManager = activityTaskManager;
@@ -163,6 +169,7 @@
         mContentResolver = contentResolver;
         mBgHandler = bgHandler;
         shellInit.addInitCallback(this::onInit, this);
+        mAnimationBackground = backAnimationBackground;
     }
 
     @VisibleForTesting
@@ -184,10 +191,14 @@
             return;
         }
 
-        final CrossTaskBackAnimation crossTaskAnimation = new CrossTaskBackAnimation(mContext);
+        final CrossTaskBackAnimation crossTaskAnimation =
+                new CrossTaskBackAnimation(mContext, mAnimationBackground);
         mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_TASK,
-                new BackAnimationRunner(crossTaskAnimation.mCallback, crossTaskAnimation.mRunner));
-        // TODO (238474994): register cross activity animation when it's completed.
+                crossTaskAnimation.mBackAnimationRunner);
+        final CrossActivityAnimation crossActivityAnimation =
+                new CrossActivityAnimation(mContext, mAnimationBackground);
+        mAnimationDefinition.set(BackNavigationInfo.TYPE_CROSS_ACTIVITY,
+                crossActivityAnimation.mBackAnimationRunner);
         // TODO (236760237): register dialog close animation when it's completed.
     }
 
@@ -275,7 +286,8 @@
         @Override
         public void clearBackToLauncherCallback() {
             executeRemoteCallWithTaskPermission(mController, "clearBackToLauncherCallback",
-                    (controller) -> controller.clearBackToLauncherCallback());
+                    (controller) -> controller.unregisterAnimation(
+                            BackNavigationInfo.TYPE_RETURN_TO_HOME));
         }
 
         @Override
@@ -289,8 +301,8 @@
         mAnimationDefinition.set(type, runner);
     }
 
-    private void clearBackToLauncherCallback() {
-        mAnimationDefinition.remove(BackNavigationInfo.TYPE_RETURN_TO_HOME);
+    void unregisterAnimation(@BackNavigationInfo.BackTargetType int type) {
+        mAnimationDefinition.remove(type);
     }
 
     /**
@@ -374,7 +386,7 @@
             return;
         }
 
-        final BackEvent backEvent = mTouchTracker.createProgressEvent();
+        final BackMotionEvent backEvent = mTouchTracker.createProgressEvent();
         dispatchOnBackProgressed(mActiveCallback, backEvent);
     }
 
@@ -404,7 +416,7 @@
     }
 
     private void dispatchOnBackStarted(IOnBackInvokedCallback callback,
-            BackEvent backEvent) {
+            BackMotionEvent backEvent) {
         if (callback == null) {
             return;
         }
@@ -442,7 +454,7 @@
     }
 
     private void dispatchOnBackProgressed(IOnBackInvokedCallback callback,
-            BackEvent backEvent) {
+            BackMotionEvent backEvent) {
         if (callback == null) {
             return;
         }
@@ -455,6 +467,11 @@
         }
     }
 
+    private boolean shouldDispatchAnimation(IOnBackInvokedCallback callback) {
+        // TODO(b/258698745): Only dispatch to animation callbacks.
+        return mEnableAnimations.get();
+    }
+
     /**
      * Sets to true when the back gesture has passed the triggering threshold, false otherwise.
      */
@@ -629,7 +646,7 @@
                     if (!mBackGestureStarted) {
                         // if the down -> up gesture happened before animation start, we have to
                         // trigger the uninterruptible transition to finish the back animation.
-                        final BackEvent backFinish = mTouchTracker.createProgressEvent();
+                        final BackMotionEvent backFinish = mTouchTracker.createProgressEvent();
                         dispatchOnBackProgressed(mActiveCallback, backFinish);
                         startPostCommitAnimation();
                     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
new file mode 100644
index 0000000..e36e16c
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossActivityAnimation.java
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.back;
+
+import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.NonNull;
+import android.content.Context;
+import android.graphics.Matrix;
+import android.graphics.PointF;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.RemoteException;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.animation.AccelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+import android.window.BackEvent;
+import android.window.BackMotionEvent;
+import android.window.BackProgressAnimator;
+import android.window.IOnBackInvokedCallback;
+
+import com.android.internal.policy.ScreenDecorationsUtils;
+import com.android.internal.protolog.common.ProtoLog;
+import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.annotations.ShellMainThread;
+
+/** Class that defines cross-activity animation. */
+@ShellMainThread
+class CrossActivityAnimation {
+    /**
+     * Minimum scale of the entering/closing window.
+     */
+    private static final float MIN_WINDOW_SCALE = 0.9f;
+
+    /**
+     * Minimum alpha of the closing/entering window.
+     */
+    private static final float CLOSING_MIN_WINDOW_ALPHA = 0.5f;
+
+    /**
+     * Progress value to fly out closing window and fly in entering window.
+     */
+    private static final float SWITCH_ENTERING_WINDOW_PROGRESS = 0.5f;
+
+    /** Max window translation in the Y axis. */
+    private static final int WINDOW_MAX_DELTA_Y = 160;
+
+    /** Duration of fade in/out entering window. */
+    private static final int FADE_IN_DURATION = 100;
+    /** Duration of post animation after gesture committed. */
+    private static final int POST_ANIMATION_DURATION = 350;
+    private static final Interpolator INTERPOLATOR = Interpolators.EMPHASIZED;
+
+    private final Rect mStartTaskRect = new Rect();
+    private final float mCornerRadius;
+
+    // The closing window properties.
+    private final RectF mClosingRect = new RectF();
+
+    // The entering window properties.
+    private final Rect mEnteringStartRect = new Rect();
+    private final RectF mEnteringRect = new RectF();
+
+    private float mCurrentAlpha = 1.0f;
+
+    private float mEnteringMargin = 0;
+    private ValueAnimator mEnteringAnimator;
+    private boolean mEnteringWindowShow = false;
+
+    private final PointF mInitialTouchPos = new PointF();
+
+    private final Matrix mTransformMatrix = new Matrix();
+
+    private final float[] mTmpFloat9 = new float[9];
+
+    private RemoteAnimationTarget mEnteringTarget;
+    private RemoteAnimationTarget mClosingTarget;
+    private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
+    private boolean mBackInProgress = false;
+
+    private PointF mTouchPos = new PointF();
+    private IRemoteAnimationFinishedCallback mFinishCallback;
+
+    private final BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+    final BackAnimationRunner mBackAnimationRunner;
+
+    private final BackAnimationBackground mBackground;
+
+    CrossActivityAnimation(Context context, BackAnimationBackground background) {
+        mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
+        mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
+        mBackground = background;
+    }
+
+    private static float mapRange(float value, float min, float max) {
+        return min + (value * (max - min));
+    }
+
+    private float getInterpolatedProgress(float backProgress) {
+        return INTERPOLATOR.getInterpolation(backProgress);
+    }
+
+    private void startBackAnimation() {
+        if (mEnteringTarget == null || mClosingTarget == null) {
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Entering target or closing target is null.");
+            return;
+        }
+        mTransaction.setAnimationTransaction();
+
+        // Offset start rectangle to align task bounds.
+        mStartTaskRect.set(mClosingTarget.windowConfiguration.getBounds());
+        mStartTaskRect.offsetTo(0, 0);
+
+        // Draw background with task background color.
+        mBackground.ensureBackground(
+                mEnteringTarget.taskInfo.taskDescription.getBackgroundColor(), mTransaction);
+    }
+
+    private void applyTransform(SurfaceControl leash, RectF targetRect, float targetAlpha) {
+        final float scale = targetRect.width() / mStartTaskRect.width();
+        mTransformMatrix.reset();
+        mTransformMatrix.setScale(scale, scale);
+        mTransformMatrix.postTranslate(targetRect.left, targetRect.top);
+        mTransaction.setAlpha(leash, targetAlpha)
+                .setMatrix(leash, mTransformMatrix, mTmpFloat9)
+                .setWindowCrop(leash, mStartTaskRect)
+                .setCornerRadius(leash, mCornerRadius);
+    }
+
+    private void finishAnimation() {
+        if (mEnteringTarget != null) {
+            mEnteringTarget.leash.release();
+            mEnteringTarget = null;
+        }
+        if (mClosingTarget != null) {
+            mClosingTarget.leash.release();
+            mClosingTarget = null;
+        }
+        if (mBackground != null) {
+            mBackground.removeBackground(mTransaction);
+        }
+
+        mTransaction.apply();
+        mBackInProgress = false;
+        mTransformMatrix.reset();
+        mInitialTouchPos.set(0, 0);
+        mEnteringWindowShow = false;
+        mEnteringMargin = 0;
+
+        if (mFinishCallback != null) {
+            try {
+                mFinishCallback.onAnimationFinished();
+            } catch (RemoteException e) {
+                e.printStackTrace();
+            }
+            mFinishCallback = null;
+        }
+    }
+
+    private void onGestureProgress(@NonNull BackEvent backEvent) {
+        if (!mBackInProgress) {
+            mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
+            mBackInProgress = true;
+        }
+        mTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
+
+        if (mEnteringTarget == null || mClosingTarget == null) {
+            return;
+        }
+
+        final float progress = getInterpolatedProgress(backEvent.getProgress());
+        final float touchY = mTouchPos.y;
+
+        final int width = mStartTaskRect.width();
+        final int height = mStartTaskRect.height();
+
+        final float closingScale = mapRange(progress, 1, MIN_WINDOW_SCALE);
+
+        final float closingWidth = closingScale * width;
+        final float closingHeight = (float) height / width * closingWidth;
+
+        // Move the window along the X axis.
+        final float closingLeft = mStartTaskRect.left + (width - closingWidth) / 2;
+
+        // Move the window along the Y axis.
+        final float deltaYRatio = (touchY - mInitialTouchPos.y) / height;
+        final float deltaY = (float) Math.sin(deltaYRatio * Math.PI * 0.5f) * WINDOW_MAX_DELTA_Y;
+        final float closingTop = (height - closingHeight) * 0.5f + deltaY;
+        mClosingRect.set(
+                closingLeft, closingTop, closingLeft + closingWidth, closingTop + closingHeight);
+        mEnteringRect.set(mClosingRect);
+
+        // Switch closing/entering targets while reach to the threshold progress.
+        if (showEnteringWindow(progress > SWITCH_ENTERING_WINDOW_PROGRESS)) {
+            return;
+        }
+
+        // Present windows and update the alpha.
+        mCurrentAlpha = Math.max(mapRange(progress, 1.0f, 0), CLOSING_MIN_WINDOW_ALPHA);
+        mClosingRect.offset(mEnteringMargin, 0);
+        mEnteringRect.offset(mEnteringMargin - width, 0);
+
+        applyTransform(
+                mClosingTarget.leash, mClosingRect, mEnteringWindowShow ? 0.01f : mCurrentAlpha);
+        applyTransform(
+                mEnteringTarget.leash, mEnteringRect, mEnteringWindowShow ? mCurrentAlpha : 0.01f);
+        mTransaction.apply();
+    }
+
+    private boolean showEnteringWindow(boolean show) {
+        if (mEnteringAnimator == null) {
+            mEnteringAnimator = ValueAnimator.ofFloat(1f, 0f).setDuration(FADE_IN_DURATION);
+            mEnteringAnimator.setInterpolator(new AccelerateInterpolator());
+            mEnteringAnimator.addUpdateListener(animation -> {
+                float progress = animation.getAnimatedFraction();
+                final int width = mStartTaskRect.width();
+                mEnteringMargin = width * progress;
+                // We don't animate to 0 or the surface would become invisible and lose focus.
+                final float alpha = progress >= 0.5f ? 0.01f
+                        : mapRange(progress * 2, mCurrentAlpha, 0.01f);
+                mClosingRect.offset(mEnteringMargin, 0);
+                mEnteringRect.offset(mEnteringMargin - width, 0);
+
+                applyTransform(mClosingTarget.leash, mClosingRect, alpha);
+                applyTransform(mEnteringTarget.leash, mEnteringRect, mCurrentAlpha);
+                mTransaction.apply();
+            });
+        }
+
+        if (mEnteringAnimator.isRunning()) {
+            return true;
+        }
+
+        if (mEnteringWindowShow == show) {
+            return false;
+        }
+
+        mEnteringWindowShow = show;
+        if (show) {
+            mEnteringAnimator.start();
+        } else {
+            mEnteringAnimator.reverse();
+        }
+        return true;
+    }
+
+    private void onGestureCommitted() {
+        if (mEnteringTarget == null || mClosingTarget == null) {
+            finishAnimation();
+            return;
+        }
+
+        // End the fade in animation.
+        if (mEnteringAnimator.isRunning()) {
+            mEnteringAnimator.cancel();
+        }
+
+        // We enter phase 2 of the animation, the starting coordinates for phase 2 are the current
+        // coordinate of the gesture driven phase.
+        mEnteringRect.round(mEnteringStartRect);
+        mTransaction.hide(mClosingTarget.leash);
+
+        ValueAnimator valueAnimator =
+                ValueAnimator.ofFloat(1f, 0f).setDuration(POST_ANIMATION_DURATION);
+        valueAnimator.setInterpolator(new DecelerateInterpolator());
+        valueAnimator.addUpdateListener(animation -> {
+            float progress = animation.getAnimatedFraction();
+            updatePostCommitEnteringAnimation(progress);
+            mTransaction.apply();
+        });
+
+        valueAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                finishAnimation();
+            }
+        });
+        valueAnimator.start();
+    }
+
+    private void updatePostCommitEnteringAnimation(float progress) {
+        float left = mapRange(progress, mEnteringStartRect.left, mStartTaskRect.left);
+        float top = mapRange(progress, mEnteringStartRect.top, mStartTaskRect.top);
+        float width = mapRange(progress, mEnteringStartRect.width(), mStartTaskRect.width());
+        float height = mapRange(progress, mEnteringStartRect.height(), mStartTaskRect.height());
+        float alpha = mapRange(progress, mCurrentAlpha, 1.0f);
+
+        mEnteringRect.set(left, top, left + width, top + height);
+        applyTransform(mEnteringTarget.leash, mEnteringRect, alpha);
+    }
+
+    private final class Callback extends IOnBackInvokedCallback.Default {
+        @Override
+        public void onBackStarted(BackMotionEvent backEvent) {
+            mProgressAnimator.onBackStarted(backEvent,
+                    CrossActivityAnimation.this::onGestureProgress);
+        }
+
+        @Override
+        public void onBackProgressed(@NonNull BackMotionEvent backEvent) {
+            mProgressAnimator.onBackProgressed(backEvent);
+        }
+
+        @Override
+        public void onBackCancelled() {
+            // End the fade in animation.
+            if (mEnteringAnimator.isRunning()) {
+                mEnteringAnimator.cancel();
+            }
+            // TODO (b259608500): Let BackProgressAnimator could play cancel animation.
+            mProgressAnimator.reset();
+            finishAnimation();
+        }
+
+        @Override
+        public void onBackInvoked() {
+            mProgressAnimator.reset();
+            onGestureCommitted();
+        }
+    }
+
+    private final class Runner extends IRemoteAnimationRunner.Default {
+        @Override
+        public void onAnimationStart(
+                int transit,
+                RemoteAnimationTarget[] apps,
+                RemoteAnimationTarget[] wallpapers,
+                RemoteAnimationTarget[] nonApps,
+                IRemoteAnimationFinishedCallback finishedCallback) {
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to activity animation.");
+            for (RemoteAnimationTarget a : apps) {
+                if (a.mode == MODE_CLOSING) {
+                    mClosingTarget = a;
+                }
+                if (a.mode == MODE_OPENING) {
+                    mEnteringTarget = a;
+                }
+            }
+
+            startBackAnimation();
+            mFinishCallback = finishedCallback;
+        }
+
+        @Override
+        public void onAnimationCancelled(boolean isKeyguardOccluded) {
+            finishAnimation();
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 2074b6a..676e259 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -39,6 +39,7 @@
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 import android.window.BackProgressAnimator;
 import android.window.IOnBackInvokedCallback;
 
@@ -61,7 +62,7 @@
  */
 @ShellMainThread
 class CrossTaskBackAnimation {
-    private static final float[] BACKGROUNDCOLOR = {0.263f, 0.263f, 0.227f};
+    private static final int BACKGROUNDCOLOR = 0x43433A;
 
     /**
      * Minimum scale of the entering window.
@@ -106,7 +107,6 @@
 
     private RemoteAnimationTarget mEnteringTarget;
     private RemoteAnimationTarget mClosingTarget;
-    private SurfaceControl mBackgroundSurface;
     private SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
 
     private boolean mBackInProgress = false;
@@ -115,56 +115,15 @@
     private float mProgress = 0;
     private PointF mTouchPos = new PointF();
     private IRemoteAnimationFinishedCallback mFinishCallback;
-
     private BackProgressAnimator mProgressAnimator = new BackProgressAnimator();
+    final BackAnimationRunner mBackAnimationRunner;
 
-    final IOnBackInvokedCallback mCallback = new IOnBackInvokedCallback.Default() {
-        @Override
-        public void onBackStarted(BackEvent backEvent) {
-            mProgressAnimator.onBackStarted(backEvent,
-                    CrossTaskBackAnimation.this::onGestureProgress);
-        }
+    private final BackAnimationBackground mBackground;
 
-        @Override
-        public void onBackProgressed(@NonNull BackEvent backEvent) {
-            mProgressAnimator.onBackProgressed(backEvent);
-        }
-
-        @Override
-        public void onBackCancelled() {
-            mProgressAnimator.reset();
-            finishAnimation();
-        }
-
-        @Override
-        public void onBackInvoked() {
-            mProgressAnimator.reset();
-            onGestureCommitted();
-        }
-    };
-
-    final IRemoteAnimationRunner mRunner = new IRemoteAnimationRunner.Default() {
-        @Override
-        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
-                RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
-                IRemoteAnimationFinishedCallback finishedCallback) {
-            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to task animation.");
-            for (RemoteAnimationTarget a : apps) {
-                if (a.mode == MODE_CLOSING) {
-                    mClosingTarget = a;
-                }
-                if (a.mode == MODE_OPENING) {
-                    mEnteringTarget = a;
-                }
-            }
-
-            startBackAnimation();
-            mFinishCallback = finishedCallback;
-        }
-    };
-
-    CrossTaskBackAnimation(Context context) {
+    CrossTaskBackAnimation(Context context, BackAnimationBackground background) {
         mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
+        mBackAnimationRunner = new BackAnimationRunner(new Callback(), new Runner());
+        mBackground = background;
     }
 
     private float getInterpolatedProgress(float backProgress) {
@@ -182,14 +141,7 @@
         mStartTaskRect.offsetTo(0, 0);
 
         // Draw background.
-        mBackgroundSurface = new SurfaceControl.Builder()
-                .setName("Background of Back Navigation")
-                .setColorLayer()
-                .setHidden(false)
-                .build();
-        mTransaction.setColor(mBackgroundSurface, BACKGROUNDCOLOR)
-                .setLayer(mBackgroundSurface, -1);
-        mTransaction.apply();
+        mBackground.ensureBackground(BACKGROUNDCOLOR, mTransaction);
     }
 
     private void updateGestureBackProgress(float progress, BackEvent event) {
@@ -300,11 +252,11 @@
             mClosingTarget = null;
         }
 
-        if (mBackgroundSurface != null) {
-            mBackgroundSurface.release();
-            mBackgroundSurface = null;
+        if (mBackground != null) {
+            mBackground.removeBackground(mTransaction);
         }
 
+        mTransaction.apply();
         mBackInProgress = false;
         mTransformMatrix.reset();
         mClosingCurrentRect.setEmpty();
@@ -362,4 +314,49 @@
     private static float mapRange(float value, float min, float max) {
         return min + (value * (max - min));
     }
+
+    private final class Callback extends IOnBackInvokedCallback.Default  {
+        @Override
+        public void onBackStarted(BackMotionEvent backEvent) {
+            mProgressAnimator.onBackStarted(backEvent,
+                    CrossTaskBackAnimation.this::onGestureProgress);
+        }
+
+        @Override
+        public void onBackProgressed(@NonNull BackMotionEvent backEvent) {
+            mProgressAnimator.onBackProgressed(backEvent);
+        }
+
+        @Override
+        public void onBackCancelled() {
+            mProgressAnimator.reset();
+            finishAnimation();
+        }
+
+        @Override
+        public void onBackInvoked() {
+            mProgressAnimator.reset();
+            onGestureCommitted();
+        }
+    };
+
+    private final class Runner extends IRemoteAnimationRunner.Default {
+        @Override
+        public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+                RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+                IRemoteAnimationFinishedCallback finishedCallback) {
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Start back to task animation.");
+            for (RemoteAnimationTarget a : apps) {
+                if (a.mode == MODE_CLOSING) {
+                    mClosingTarget = a;
+                }
+                if (a.mode == MODE_OPENING) {
+                    mEnteringTarget = a;
+                }
+            }
+
+            startBackAnimation();
+            mFinishCallback = finishedCallback;
+        }
+    };
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
index ccfac65..695ef4e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/TouchTracker.java
@@ -19,6 +19,7 @@
 import android.os.SystemProperties;
 import android.view.RemoteAnimationTarget;
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 
 /**
  * Helper class to record the touch location for gesture and generate back events.
@@ -82,11 +83,11 @@
         mSwipeEdge = BackEvent.EDGE_LEFT;
     }
 
-    BackEvent createStartEvent(RemoteAnimationTarget target) {
-        return new BackEvent(mInitTouchX, mInitTouchY, 0, mSwipeEdge, target);
+    BackMotionEvent createStartEvent(RemoteAnimationTarget target) {
+        return new BackMotionEvent(mInitTouchX, mInitTouchY, 0, mSwipeEdge, target);
     }
 
-    BackEvent createProgressEvent() {
+    BackMotionEvent createProgressEvent() {
         float progressThreshold = PROGRESS_THRESHOLD >= 0
                 ? PROGRESS_THRESHOLD : mProgressThreshold;
         progressThreshold = progressThreshold == 0 ? 1 : progressThreshold;
@@ -109,8 +110,8 @@
         return createProgressEvent(progress);
     }
 
-    BackEvent createProgressEvent(float progress) {
-        return new BackEvent(mLatestTouchX, mLatestTouchY, progress, mSwipeEdge, null);
+    BackMotionEvent createProgressEvent(float progress) {
+        return new BackMotionEvent(mLatestTouchX, mLatestTouchY, progress, mSwipeEdge, null);
     }
 
     public void setProgressThreshold(float progressThreshold) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 1fd91de..9674b69 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -475,8 +475,13 @@
 
     @VisibleForTesting
     public void onStatusBarStateChanged(boolean isShade) {
+        boolean didChange = mIsStatusBarShade != isShade;
+        if (DEBUG_BUBBLE_CONTROLLER) {
+            Log.d(TAG, "onStatusBarStateChanged isShade=" + isShade + " didChange=" + didChange);
+        }
         mIsStatusBarShade = isShade;
-        if (!mIsStatusBarShade) {
+        if (!mIsStatusBarShade && didChange) {
+            // Only collapse stack on change
             collapseStack();
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index f621351..04d62f6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1955,6 +1955,7 @@
         if (wasExpanded) {
             stopMonitoringSwipeUpGesture();
             animateCollapse();
+            showManageMenu(false);
             logBubbleEvent(mExpandedBubble, FrameworkStatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
         } else {
             animateExpansion();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index e8b0f02..214b304 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -219,7 +219,11 @@
                 insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
         // Only insets the divider bar with task bar when it's expanded so that the rounded corners
         // will be drawn against task bar.
-        if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
+        // But there is no need to do it when IME showing because there are no rounded corners at
+        // the bottom. This also avoids the problem of task bar height not changing when IME
+        // floating.
+        if (!insetsState.getSourceOrDefaultVisibility(InsetsState.ITYPE_IME)
+                && taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
             mTempRect.inset(taskBarInsetsSource.calculateVisibleInsets(mTempRect));
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index ae49616..45b234a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -122,6 +122,7 @@
     private int mDensity;
 
     private final boolean mDimNonImeSide;
+    private ValueAnimator mDividerFlingAnimator;
 
     public SplitLayout(String windowName, Context context, Configuration configuration,
             SplitLayoutHandler splitLayoutHandler,
@@ -395,6 +396,10 @@
         mSplitWindowManager.release(t);
         mDisplayImeController.removePositionProcessor(mImePositionProcessor);
         mImePositionProcessor.reset();
+        if (mDividerFlingAnimator != null) {
+            mDividerFlingAnimator.cancel();
+        }
+        resetDividerPosition();
     }
 
     public void release() {
@@ -577,13 +582,18 @@
                     CUJ_SPLIT_SCREEN_RESIZE);
             return;
         }
-        ValueAnimator animator = ValueAnimator
+
+        if (mDividerFlingAnimator != null) {
+            mDividerFlingAnimator.cancel();
+        }
+
+        mDividerFlingAnimator = ValueAnimator
                 .ofInt(from, to)
                 .setDuration(duration);
-        animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        animator.addUpdateListener(
+        mDividerFlingAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+        mDividerFlingAnimator.addUpdateListener(
                 animation -> updateDivideBounds((int) animation.getAnimatedValue()));
-        animator.addListener(new AnimatorListenerAdapter() {
+        mDividerFlingAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (flingFinishedCallback != null) {
@@ -591,14 +601,15 @@
                 }
                 InteractionJankMonitorUtils.endTracing(
                         CUJ_SPLIT_SCREEN_RESIZE);
+                mDividerFlingAnimator = null;
             }
 
             @Override
             public void onAnimationCancel(Animator animation) {
-                setDividePosition(to, true /* applyLayoutChange */);
+                mDividerFlingAnimator = null;
             }
         });
-        animator.start();
+        mDividerFlingAnimator.start();
     }
 
     /** Switch both surface position with animation. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 962be9d..4ea8a5d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -38,6 +38,7 @@
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
 import com.android.wm.shell.back.BackAnimation;
+import com.android.wm.shell.back.BackAnimationBackground;
 import com.android.wm.shell.back.BackAnimationController;
 import com.android.wm.shell.bubbles.BubbleController;
 import com.android.wm.shell.bubbles.Bubbles;
@@ -93,13 +94,13 @@
 import com.android.wm.shell.unfold.UnfoldTransitionHandler;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
-import java.util.Optional;
-
 import dagger.BindsOptionalOf;
 import dagger.Lazy;
 import dagger.Module;
 import dagger.Provides;
 
+import java.util.Optional;
+
 /**
  * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only
  * accessible from components within the WM subcomponent (can be explicitly exposed to the
@@ -255,21 +256,30 @@
 
     @WMSingleton
     @Provides
+    static BackAnimationBackground provideBackAnimationBackground(
+            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
+        return new BackAnimationBackground(rootTaskDisplayAreaOrganizer);
+    }
+
+    @WMSingleton
+    @Provides
     static Optional<BackAnimationController> provideBackAnimationController(
             Context context,
             ShellInit shellInit,
             ShellController shellController,
             @ShellMainThread ShellExecutor shellExecutor,
-            @ShellBackgroundThread Handler backgroundHandler
+            @ShellBackgroundThread Handler backgroundHandler,
+            BackAnimationBackground backAnimationBackground
     ) {
         if (BackAnimationController.IS_ENABLED) {
             return Optional.of(
                     new BackAnimationController(shellInit, shellController, shellExecutor,
-                            backgroundHandler, context));
+                            backgroundHandler, context, backAnimationBackground));
         }
         return Optional.empty();
     }
 
+
     //
     // Bubbles (optional feature)
     //
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 90b35a5..44bcdb2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -82,7 +82,7 @@
         mTasks.put(taskInfo.taskId, state);
         if (!Transitions.ENABLE_SHELL_TRANSITIONS) {
             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
-            mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
+            mWindowDecorationViewModel.onTaskOpening(taskInfo, leash, t, t);
             t.apply();
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
index 168f6d7..60e5ff2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserver.java
@@ -90,7 +90,7 @@
                 // This logic relies on 2 assumptions: 1 is that child tasks will be visited before
                 // parents (due to how z-order works). 2 is that no non-tasks are interleaved
                 // between tasks (hierarchically).
-                taskParents.add(change.getContainer());
+                taskParents.add(change.getParent());
             }
             if (taskParents.contains(change.getContainer())) {
                 continue;
@@ -120,7 +120,7 @@
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        mWindowDecorViewModel.createWindowDecoration(
+        mWindowDecorViewModel.onTaskOpening(
                 change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
@@ -128,31 +128,23 @@
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        mWindowDecorViewModel.setupWindowDecorationForTransition(
-                change.getTaskInfo(), startT, finishT);
+        mWindowDecorViewModel.onTaskClosing(change.getTaskInfo(), startT, finishT);
     }
 
     private void onChangeTransitionReady(
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        mWindowDecorViewModel.setupWindowDecorationForTransition(
-                change.getTaskInfo(), startT, finishT);
+        mWindowDecorViewModel.onTaskChanging(
+                change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
     private void onToFrontTransitionReady(
             TransitionInfo.Change change,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
-        boolean exists = mWindowDecorViewModel.setupWindowDecorationForTransition(
-                change.getTaskInfo(),
-                startT,
-                finishT);
-        if (!exists) {
-            // Window caption does not exist, create it
-            mWindowDecorViewModel.createWindowDecoration(
-                    change.getTaskInfo(), change.getLeash(), startT, finishT);
-        }
+        mWindowDecorViewModel.onTaskChanging(
+                change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
     @Override
@@ -188,4 +180,4 @@
             mWindowDecorViewModel.destroyWindowDecoration(taskInfo.get(i));
         }
     }
-}
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
index 75a4091..6623f5c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/fullscreen/FullscreenTaskListener.java
@@ -103,7 +103,7 @@
         if (mWindowDecorViewModelOptional.isPresent()) {
             SurfaceControl.Transaction t = new SurfaceControl.Transaction();
             createdWindowDecor = mWindowDecorViewModelOptional.get()
-                    .createWindowDecoration(taskInfo, leash, t, t);
+                    .onTaskOpening(taskInfo, leash, t, t);
             t.apply();
         }
         if (!createdWindowDecor) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
index 17d7f5d..5376ae3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipBoundsState.java
@@ -97,6 +97,8 @@
     private int mShelfHeight;
     /** Whether the user has resized the PIP manually. */
     private boolean mHasUserResizedPip;
+    /** Whether the user has moved the PIP manually. */
+    private boolean mHasUserMovedPip;
     /**
      * Areas defined by currently visible apps that they prefer to keep clear from overlays such as
      * the PiP. Restricted areas may only move the PiP a limited amount from its anchor position.
@@ -279,6 +281,7 @@
         if (changed) {
             clearReentryState();
             setHasUserResizedPip(false);
+            setHasUserMovedPip(false);
         }
     }
 
@@ -442,6 +445,16 @@
         mHasUserResizedPip = hasUserResizedPip;
     }
 
+    /** Returns whether the user has moved the PIP. */
+    public boolean hasUserMovedPip() {
+        return mHasUserMovedPip;
+    }
+
+    /** Set whether the user has moved the PIP. */
+    public void setHasUserMovedPip(boolean hasUserMovedPip) {
+        mHasUserMovedPip = hasUserMovedPip;
+    }
+
     /**
      * Registers a callback when the minimal size of PIP that is set by the app changes.
      */
@@ -577,6 +590,8 @@
         pw.println(innerPrefix + "mImeHeight=" + mImeHeight);
         pw.println(innerPrefix + "mIsShelfShowing=" + mIsShelfShowing);
         pw.println(innerPrefix + "mShelfHeight=" + mShelfHeight);
+        pw.println(innerPrefix + "mHasUserMovedPip=" + mHasUserMovedPip);
+        pw.println(innerPrefix + "mHasUserResizedPip=" + mHasUserResizedPip);
         if (mPipReentryState == null) {
             pw.println(innerPrefix + "mPipReentryState=null");
         } else {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index f170e77..8ba2583 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -63,6 +63,7 @@
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.util.Log;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -179,8 +180,10 @@
                 // This is necessary in case there was a resize animation ongoing when exit PIP
                 // started, in which case the first resize will be skipped to let the exit
                 // operation handle the final resize out of PIP mode. See b/185306679.
-                finishResize(tx, destinationBounds, direction, animationType);
-                sendOnPipTransitionFinished(direction);
+                finishResizeDelayedIfNeeded(() -> {
+                    finishResize(tx, destinationBounds, direction, animationType);
+                    sendOnPipTransitionFinished(direction);
+                });
             }
         }
 
@@ -196,6 +199,39 @@
         }
     };
 
+    /**
+     * Finishes resizing the PiP, delaying the operation if it has to be synced with the PiP menu.
+     *
+     * This is done to avoid a race condition between the last transaction applied in
+     * onPipAnimationUpdate and the finishResize in onPipAnimationEnd. The transaction in
+     * onPipAnimationUpdate is applied directly from WmShell, while onPipAnimationEnd creates a
+     * WindowContainerTransaction in finishResize, which is to be applied by WmCore later. Normally,
+     * the WCT should be the last transaction to finish the animation. However, it  may happen that
+     * it gets applied *before* the transaction created by the last onPipAnimationUpdate. This
+     * happens only when the PiP surface transaction has to be synced with the PiP menu due to the
+     * necessity for a delay when syncing the PiP surface animation with the PiP menu surface
+     * animation and redrawing the PiP menu contents. As a result, the PiP surface gets scaled after
+     * the new bounds are applied by WmCore, which makes the PiP surface have unexpected bounds.
+     *
+     * To avoid this, we delay the finishResize operation until
+     * the next frame. This aligns the last onAnimationUpdate transaction with the WCT application.
+     */
+    private void finishResizeDelayedIfNeeded(Runnable finishResizeRunnable) {
+        if (!shouldSyncPipTransactionWithMenu()) {
+            finishResizeRunnable.run();
+            return;
+        }
+
+        // Delay the finishResize to the next frame
+        Choreographer.getInstance().postCallback(Choreographer.CALLBACK_COMMIT, () -> {
+            mMainExecutor.execute(finishResizeRunnable);
+        }, null);
+    }
+
+    private boolean shouldSyncPipTransactionWithMenu() {
+        return mPipMenuController.isMenuVisible();
+    }
+
     @VisibleForTesting
     final PipTransitionController.PipTransitionCallback mPipTransitionCallback =
             new PipTransitionController.PipTransitionCallback() {
@@ -221,7 +257,7 @@
                 @Override
                 public boolean handlePipTransaction(SurfaceControl leash,
                         SurfaceControl.Transaction tx, Rect destinationBounds) {
-                    if (mPipMenuController.isMenuVisible()) {
+                    if (shouldSyncPipTransactionWithMenu()) {
                         mPipMenuController.movePipMenu(leash, tx, destinationBounds);
                         return true;
                     }
@@ -1223,7 +1259,7 @@
         mSurfaceTransactionHelper
                 .crop(tx, mLeash, toBounds)
                 .round(tx, mLeash, mPipTransitionState.isInPip());
-        if (mPipMenuController.isMenuVisible()) {
+        if (shouldSyncPipTransactionWithMenu()) {
             mPipMenuController.resizePipMenu(mLeash, tx, toBounds);
         } else {
             tx.apply();
@@ -1265,7 +1301,7 @@
         mSurfaceTransactionHelper
                 .scale(tx, mLeash, startBounds, toBounds, degrees)
                 .round(tx, mLeash, startBounds, toBounds);
-        if (mPipMenuController.isMenuVisible()) {
+        if (shouldSyncPipTransactionWithMenu()) {
             mPipMenuController.movePipMenu(mLeash, tx, toBounds);
         } else {
             tx.apply();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
index 84071e0..690505e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipKeepClearAlgorithm.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Rect;
+import android.os.SystemProperties;
 import android.util.ArraySet;
 import android.view.Gravity;
 
@@ -34,6 +35,10 @@
  */
 public class PhonePipKeepClearAlgorithm implements PipKeepClearAlgorithm {
 
+    private boolean mKeepClearAreaGravityEnabled =
+            SystemProperties.getBoolean(
+                    "persist.wm.debug.enable_pip_keep_clear_algorithm_gravity", false);
+
     protected int mKeepClearAreasPadding;
 
     public PhonePipKeepClearAlgorithm(Context context) {
@@ -53,31 +58,36 @@
         Rect startingBounds = pipBoundsState.getBounds().isEmpty()
                 ? pipBoundsAlgorithm.getEntryDestinationBoundsIgnoringKeepClearAreas()
                 : pipBoundsState.getBounds();
-        float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
-        int verticalGravity = Gravity.BOTTOM;
-        int horizontalGravity;
-        if (snapFraction >= 0.5f && snapFraction < 2.5f) {
-            horizontalGravity = Gravity.RIGHT;
-        } else {
-            horizontalGravity = Gravity.LEFT;
-        }
-        // push the bounds based on the gravity
         Rect insets = new Rect();
         pipBoundsAlgorithm.getInsetBounds(insets);
         if (pipBoundsState.isImeShowing()) {
             insets.bottom -= pipBoundsState.getImeHeight();
         }
-        Rect pushedBounds = new Rect(startingBounds);
-        if (verticalGravity == Gravity.BOTTOM) {
-            pushedBounds.offsetTo(pushedBounds.left,
-                    insets.bottom - pushedBounds.height());
+        Rect pipBounds = new Rect(startingBounds);
+
+        // move PiP towards corner if user hasn't moved it manually or the flag is on
+        if (mKeepClearAreaGravityEnabled
+                || (!pipBoundsState.hasUserMovedPip() && !pipBoundsState.hasUserResizedPip())) {
+            float snapFraction = pipBoundsAlgorithm.getSnapFraction(startingBounds);
+            int verticalGravity = Gravity.BOTTOM;
+            int horizontalGravity;
+            if (snapFraction >= 0.5f && snapFraction < 2.5f) {
+                horizontalGravity = Gravity.RIGHT;
+            } else {
+                horizontalGravity = Gravity.LEFT;
+            }
+            if (verticalGravity == Gravity.BOTTOM) {
+                pipBounds.offsetTo(pipBounds.left,
+                        insets.bottom - pipBounds.height());
+            }
+            if (horizontalGravity == Gravity.RIGHT) {
+                pipBounds.offsetTo(insets.right - pipBounds.width(), pipBounds.top);
+            } else {
+                pipBounds.offsetTo(insets.left, pipBounds.top);
+            }
         }
-        if (horizontalGravity == Gravity.RIGHT) {
-            pushedBounds.offsetTo(insets.right - pushedBounds.width(), pushedBounds.top);
-        } else {
-            pushedBounds.offsetTo(insets.left, pushedBounds.top);
-        }
-        return findUnoccludedPosition(pushedBounds, pipBoundsState.getRestrictedKeepClearAreas(),
+
+        return findUnoccludedPosition(pipBounds, pipBoundsState.getRestrictedKeepClearAreas(),
                 pipBoundsState.getUnrestrictedKeepClearAreas(), insets);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index d28a9f3..efe938f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -612,12 +612,21 @@
                 new DisplayInsetsController.OnInsetsChangedListener() {
                     @Override
                     public void insetsChanged(InsetsState insetsState) {
+                        DisplayLayout pendingLayout =
+                                mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId());
+                        if (mIsInFixedRotation
+                                || pendingLayout.rotation()
+                                != mPipBoundsState.getDisplayLayout().rotation()) {
+                            // bail out if there is a pending rotation or fixed rotation change
+                            return;
+                        }
                         int oldMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
                         onDisplayChanged(
                                 mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()),
                                 false /* saveRestoreSnapFraction */);
                         int newMaxMovementBound = mPipBoundsState.getMovementBounds().bottom;
                         if (!mEnablePipKeepClearAlgorithm) {
+                            // offset PiP to adjust for bottom inset change
                             int pipTop = mPipBoundsState.getBounds().top;
                             int diff = newMaxMovementBound - oldMaxMovementBound;
                             if (diff < 0 && pipTop > newMaxMovementBound) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index a9a97be..83bc7c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -875,6 +875,8 @@
             }
 
             if (touchState.isDragging()) {
+                mPipBoundsState.setHasUserMovedPip(true);
+
                 // Move the pinned stack freely
                 final PointF lastDelta = touchState.getLastTouchDelta();
                 float lastX = mStartPosition.x + mDelta.x;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index f9172ba..7908f35 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -342,6 +342,16 @@
     }
 
     /**
+     * Returns the top running leaf task.
+     */
+    @Nullable
+    public ActivityManager.RunningTaskInfo getTopRunningTask() {
+        List<ActivityManager.RunningTaskInfo> tasks = mActivityTaskManager.getTasks(1,
+                false /* filterOnlyVisibleRecents */);
+        return tasks.isEmpty() ? null : tasks.get(0);
+    }
+
+    /**
      * Find the background task that match the given component.
      */
     @Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index a79ac45..b20125d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -315,10 +315,6 @@
         return mStageCoordinator;
     }
 
-    public ActivityManager.RunningTaskInfo getFocusingTaskInfo() {
-        return mStageCoordinator.getFocusingTaskInfo();
-    }
-
     public boolean isValidToEnterSplitScreen(@NonNull ActivityManager.RunningTaskInfo taskInfo) {
         return mStageCoordinator.isValidToEnterSplitScreen(taskInfo);
     }
@@ -628,9 +624,10 @@
         if (!isSplitScreenVisible()) {
             // Split screen is not yet activated, check if the current top running task is valid to
             // split together.
-            final ActivityManager.RunningTaskInfo taskInfo = getFocusingTaskInfo();
-            if (taskInfo != null && isValidToEnterSplitScreen(taskInfo)) {
-                return Objects.equals(taskInfo.baseIntent.getComponent(), launchingActivity);
+            final ActivityManager.RunningTaskInfo topRunningTask = mRecentTasksOptional
+                    .map(recentTasks -> recentTasks.getTopRunningTask()).orElse(null);
+            if (topRunningTask != null && isValidToEnterSplitScreen(topRunningTask)) {
+                return Objects.equals(topRunningTask.baseIntent.getComponent(), launchingActivity);
             }
             return false;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index acb71a8..eb7b0d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -150,7 +150,7 @@
  */
 public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
         DisplayController.OnDisplaysChangedListener, Transitions.TransitionHandler,
-        ShellTaskOrganizer.TaskListener, ShellTaskOrganizer.FocusListener {
+        ShellTaskOrganizer.TaskListener {
 
     private static final String TAG = StageCoordinator.class.getSimpleName();
 
@@ -186,8 +186,6 @@
     private final Rect mTempRect1 = new Rect();
     private final Rect mTempRect2 = new Rect();
 
-    private ActivityManager.RunningTaskInfo mFocusingTaskInfo;
-
     /**
      * A single-top root task which the split divider attached to.
      */
@@ -304,7 +302,6 @@
         mDisplayController.addDisplayWindowListener(this);
         mDisplayLayout = new DisplayLayout(displayController.getDisplayLayout(displayId));
         transitions.addHandler(this);
-        mTaskOrganizer.addFocusListener(this);
         mSplitUnsupportedToast = Toast.makeText(mContext,
                 R.string.dock_non_resizeble_failed_to_dock_text, Toast.LENGTH_SHORT);
     }
@@ -455,8 +452,9 @@
     }
 
     /** Launches an activity into split by legacy transition. */
-    void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
-            @SplitPosition int position, @Nullable Bundle options) {
+    void startIntentLegacy(PendingIntent intent, Intent fillInIntent, @SplitPosition int position,
+            @Nullable Bundle options) {
+        final boolean isEnteringSplit = !isSplitActive();
         final WindowContainerTransaction evictWct = new WindowContainerTransaction();
         prepareEvictChildTasks(position, evictWct);
 
@@ -466,22 +464,29 @@
                     RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                     IRemoteAnimationFinishedCallback finishedCallback,
                     SurfaceControl.Transaction t) {
-                if (apps == null || apps.length == 0) {
-                    if (mMainStage.getChildCount() == 0 || mSideStage.getChildCount() == 0) {
-                        mMainExecutor.execute(() ->
-                                exitSplitScreen(mMainStage.getChildCount() == 0
-                                        ? mSideStage : mMainStage, EXIT_REASON_UNKNOWN));
-                        mSplitUnsupportedToast.show();
+                if (isEnteringSplit) {
+                    boolean openingToSide = false;
+                    if (apps != null) {
+                        for (int i = 0; i < apps.length; ++i) {
+                            if (apps[i].mode == MODE_OPENING
+                                    && mSideStage.containsTask(apps[i].taskId)) {
+                                openingToSide = true;
+                                break;
+                            }
+                        }
                     }
-
-                    // Do nothing when the animation was cancelled.
-                    t.apply();
-                    return;
+                    if (!openingToSide) {
+                        mMainExecutor.execute(() -> exitSplitScreen(
+                                mSideStage.getChildCount() == 0 ? mMainStage : mSideStage,
+                                EXIT_REASON_UNKNOWN));
+                    }
                 }
 
-                for (int i = 0; i < apps.length; ++i) {
-                    if (apps[i].mode == MODE_OPENING) {
-                        t.show(apps[i].leash);
+                if (apps != null) {
+                    for (int i = 0; i < apps.length; ++i) {
+                        if (apps[i].mode == MODE_OPENING) {
+                            t.show(apps[i].leash);
+                        }
                     }
                 }
                 t.apply();
@@ -503,7 +508,7 @@
 
         // If split still not active, apply windows bounds first to avoid surface reset to
         // wrong pos by SurfaceAnimator from wms.
-        if (!mMainStage.isActive() && mLogger.isEnterRequestedByDrag()) {
+        if (isEnteringSplit && mLogger.isEnterRequestedByDrag()) {
             updateWindowBounds(mSplitLayout, wct);
         }
 
@@ -669,6 +674,12 @@
         mSplitLayout.init();
         mSplitLayout.setDivideRatio(splitRatio);
 
+        // Apply surface bounds before animation start.
+        SurfaceControl.Transaction startT = mTransactionPool.acquire();
+        updateSurfaceBounds(mSplitLayout, startT, false /* applyResizingOffset */);
+        startT.apply();
+        mTransactionPool.release(startT);
+
         // Set false to avoid record new bounds with old task still on top;
         mShouldUpdateRecents = false;
         mIsDividerRemoteAnimating = true;
@@ -742,7 +753,6 @@
         mSyncQueue.queue(wct);
         mSyncQueue.runInSync(t -> {
             setDividerVisibility(true, t);
-            updateSurfaceBounds(mSplitLayout, t, false /* applyResizingOffset */);
         });
 
         setEnterInstanceId(instanceId);
@@ -1035,7 +1045,7 @@
         mIsDividerRemoteAnimating = false;
 
         mSplitLayout.getInvisibleBounds(mTempRect1);
-        if (childrenToTop == null) {
+        if (childrenToTop == null || childrenToTop.getTopVisibleChildTaskId() == INVALID_TASK_ID) {
             mSideStage.removeAllTasks(wct, false /* toTop */);
             mMainStage.deactivate(wct, false /* toTop */);
             wct.reorder(mRootTaskInfo.token, false /* onTop */);
@@ -1294,13 +1304,6 @@
         }
     }
 
-    private void onStageChildTaskEnterPip() {
-        // When the exit split-screen is caused by one of the task enters auto pip,
-        // we want both tasks to be put to bottom instead of top, otherwise it will end up
-        // a fullscreen plus a pinned task instead of pinned only at the end of the transition.
-        exitSplitScreen(null, EXIT_REASON_CHILD_TASK_ENTER_PIP);
-    }
-
     private void updateRecentTasksSplitPair() {
         if (!mShouldUpdateRecents) {
             return;
@@ -1617,15 +1620,6 @@
                 && ArrayUtils.contains(CONTROLLED_WINDOWING_MODES, taskInfo.getWindowingMode());
     }
 
-    ActivityManager.RunningTaskInfo getFocusingTaskInfo() {
-        return mFocusingTaskInfo;
-    }
-
-    @Override
-    public void onFocusTaskChanged(ActivityManager.RunningTaskInfo taskInfo) {
-        mFocusingTaskInfo = taskInfo;
-    }
-
     @Override
     public void onSnappedToDismiss(boolean bottomOrRight, int reason) {
         final boolean mainStageToTop =
@@ -2063,7 +2057,6 @@
             // Update divider state after animation so that it is still around and positioned
             // properly for the animation itself.
             mSplitLayout.release();
-            mSplitLayout.resetDividerPosition();
             mTopStageAfterFoldDismiss = STAGE_TYPE_UNDEFINED;
         }
     }
@@ -2340,11 +2333,6 @@
         }
 
         @Override
-        public void onChildTaskEnterPip() {
-            StageCoordinator.this.onStageChildTaskEnterPip();
-        }
-
-        @Override
         public void onRootTaskVanished() {
             reset();
             StageCoordinator.this.onRootTaskVanished();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index bcf900b..358f712 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 
@@ -74,8 +73,6 @@
 
         void onChildTaskStatusChanged(int taskId, boolean present, boolean visible);
 
-        void onChildTaskEnterPip();
-
         void onRootTaskVanished();
 
         void onNoLongerSupportMultiWindow();
@@ -257,9 +254,6 @@
                 // Status is managed/synchronized by the transition lifecycle.
                 return;
             }
-            if (taskInfo.getWindowingMode() == WINDOWING_MODE_PINNED) {
-                mCallbacks.onChildTaskEnterPip();
-            }
             sendStatusChanged();
         } else {
             throw new IllegalArgumentException(this + "\n Unknown task: " + taskInfo
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
index 8bba4404..20da877 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimation.java
@@ -50,13 +50,17 @@
     private final float mIconStartAlpha;
     private final float mBrandingStartAlpha;
     private final TransactionPool mTransactionPool;
+    // TODO(b/261167708): Clean enter animation code after moving Letterbox code to Shell
+    private final float mRoundedCornerRadius;
 
     private Runnable mFinishCallback;
 
     SplashScreenExitAnimation(Context context, SplashScreenView view, SurfaceControl leash,
-            Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish) {
+            Rect frame, int mainWindowShiftLength, TransactionPool pool, Runnable handleFinish,
+            float roundedCornerRadius) {
         mSplashScreenView = view;
         mFirstWindowSurface = leash;
+        mRoundedCornerRadius = roundedCornerRadius;
         if (frame != null) {
             mFirstWindowFrame.set(frame);
         }
@@ -97,7 +101,7 @@
         SplashScreenExitAnimationUtils.startAnimations(mSplashScreenView, mFirstWindowSurface,
                 mMainWindowShiftLength, mTransactionPool, mFirstWindowFrame, mAnimationDuration,
                 mIconFadeOutDuration, mIconStartAlpha, mBrandingStartAlpha, mAppRevealDelay,
-                mAppRevealDuration, this);
+                mAppRevealDuration, this, mRoundedCornerRadius);
     }
 
     private void reset() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
index 3098e55..a7e4385 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashScreenExitAnimationUtils.java
@@ -63,6 +63,24 @@
 
     /**
      * Creates and starts the animator to fade out the icon, reveal the app, and shift up main
+     * window with rounded corner radius.
+     */
+    static void startAnimations(ViewGroup splashScreenView,
+            SurfaceControl firstWindowSurface, int mainWindowShiftLength,
+            TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
+            int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
+            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener,
+            float roundedCornerRadius) {
+        ValueAnimator animator =
+                createAnimator(splashScreenView, firstWindowSurface, mainWindowShiftLength,
+                        transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
+                        iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
+                        animatorListener, roundedCornerRadius);
+        animator.start();
+    }
+
+    /**
+     * Creates and starts the animator to fade out the icon, reveal the app, and shift up main
      * window.
      * @hide
      */
@@ -71,12 +89,10 @@
             TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
             int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
             int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener) {
-        ValueAnimator animator =
-                createAnimator(splashScreenView, firstWindowSurface, mainWindowShiftLength,
-                        transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
-                        iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
-                        animatorListener);
-        animator.start();
+        startAnimations(splashScreenView, firstWindowSurface, mainWindowShiftLength,
+                transactionPool, firstWindowFrame, animationDuration, iconFadeOutDuration,
+                iconStartAlpha, brandingStartAlpha, appRevealDelay, appRevealDuration,
+                animatorListener, 0f /* roundedCornerRadius */);
     }
 
     /**
@@ -87,7 +103,8 @@
             SurfaceControl firstWindowSurface, int mMainWindowShiftLength,
             TransactionPool transactionPool, Rect firstWindowFrame, int animationDuration,
             int iconFadeOutDuration, float iconStartAlpha, float brandingStartAlpha,
-            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener) {
+            int appRevealDelay, int appRevealDuration, Animator.AnimatorListener animatorListener,
+            float roundedCornerRadius) {
         // reveal app
         final float transparentRatio = 0.8f;
         final int globalHeight = splashScreenView.getHeight();
@@ -124,7 +141,7 @@
 
             shiftUpAnimation = new ShiftUpAnimation(0, -mMainWindowShiftLength, occludeHoleView,
                     firstWindowSurface, splashScreenView, transactionPool, firstWindowFrame,
-                    mMainWindowShiftLength);
+                    mMainWindowShiftLength, roundedCornerRadius);
         }
 
         ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
@@ -289,8 +306,8 @@
         public ShiftUpAnimation(float fromYDelta, float toYDelta, View occludeHoleView,
                                 SurfaceControl firstWindowSurface, ViewGroup splashScreenView,
                                 TransactionPool transactionPool, Rect firstWindowFrame,
-                                int mainWindowShiftLength) {
-            mFromYDelta = fromYDelta;
+                                int mainWindowShiftLength, float roundedCornerRadius) {
+            mFromYDelta = fromYDelta - roundedCornerRadius;
             mToYDelta = toYDelta;
             mOccludeHoleView = occludeHoleView;
             mApplier = new SyncRtSurfaceTransactionApplier(occludeHoleView);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 6ce981e..ebb957b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -16,8 +16,10 @@
 
 package com.android.wm.shell.startingsurface;
 
+import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.os.Process.THREAD_PRIORITY_TOP_APP_BOOST;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
+import static android.view.Display.DEFAULT_DISPLAY;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SOLID_COLOR_SPLASH_SCREEN;
 import static android.window.StartingWindowInfo.STARTING_WINDOW_TYPE_SPLASH_SCREEN;
@@ -29,6 +31,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -48,9 +51,11 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
+import android.hardware.display.DisplayManager;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -58,7 +63,9 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.ContextThemeWrapper;
+import android.view.Display;
 import android.view.SurfaceControl;
+import android.view.WindowManager;
 import android.window.SplashScreenView;
 import android.window.StartingWindowInfo;
 import android.window.StartingWindowInfo.StartingWindowType;
@@ -134,6 +141,144 @@
     }
 
     /**
+     * Help method to create a layout parameters for a window.
+     */
+    static Context createContext(Context initContext, StartingWindowInfo windowInfo,
+            int theme, @StartingWindowInfo.StartingWindowType int suggestType,
+            DisplayManager displayManager) {
+        final ActivityManager.RunningTaskInfo taskInfo = windowInfo.taskInfo;
+        final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+                ? windowInfo.targetActivityInfo
+                : taskInfo.topActivityInfo;
+        if (activityInfo == null || activityInfo.packageName == null) {
+            return null;
+        }
+
+        final int displayId = taskInfo.displayId;
+        final int taskId = taskInfo.taskId;
+
+        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                "addSplashScreen for package: %s with theme: %s for task: %d, suggestType: %d",
+                activityInfo.packageName, Integer.toHexString(theme), taskId, suggestType);
+        final Display display = displayManager.getDisplay(displayId);
+        if (display == null) {
+            // Can't show splash screen on requested display, so skip showing at all.
+            return null;
+        }
+        Context context = displayId == DEFAULT_DISPLAY
+                ? initContext : initContext.createDisplayContext(display);
+        if (context == null) {
+            return null;
+        }
+        if (theme != context.getThemeResId()) {
+            try {
+                context = context.createPackageContextAsUser(activityInfo.packageName,
+                        CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
+                context.setTheme(theme);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "Failed creating package context with package name "
+                        + activityInfo.packageName + " for user " + taskInfo.userId, e);
+                return null;
+            }
+        }
+
+        final Configuration taskConfig = taskInfo.getConfiguration();
+        if (taskConfig.diffPublicOnly(context.getResources().getConfiguration()) != 0) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                    "addSplashScreen: creating context based on task Configuration %s",
+                    taskConfig);
+            final Context overrideContext = context.createConfigurationContext(taskConfig);
+            overrideContext.setTheme(theme);
+            final TypedArray typedArray = overrideContext.obtainStyledAttributes(
+                    com.android.internal.R.styleable.Window);
+            final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
+            try {
+                if (resId != 0 && overrideContext.getDrawable(resId) != null) {
+                    // We want to use the windowBackground for the override context if it is
+                    // available, otherwise we use the default one to make sure a themed starting
+                    // window is displayed for the app.
+                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
+                            "addSplashScreen: apply overrideConfig %s",
+                            taskConfig);
+                    context = overrideContext;
+                }
+            } catch (Resources.NotFoundException e) {
+                Slog.w(TAG, "failed creating starting window for overrideConfig at taskId: "
+                        + taskId, e);
+                return null;
+            }
+            typedArray.recycle();
+        }
+        return context;
+    }
+
+    /**
+     * Creates the window layout parameters for splashscreen window.
+     */
+    static WindowManager.LayoutParams createLayoutParameters(Context context,
+            StartingWindowInfo windowInfo,
+            @StartingWindowInfo.StartingWindowType int suggestType,
+            CharSequence title, int pixelFormat, IBinder appToken) {
+        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
+        params.setFitInsetsSides(0);
+        params.setFitInsetsTypes(0);
+        params.format = pixelFormat;
+        int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
+                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
+                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+        final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
+        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
+            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+        }
+        if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
+            if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
+                windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+            }
+        } else {
+            windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
+        }
+        params.layoutInDisplayCutoutMode = a.getInt(
+                R.styleable.Window_windowLayoutInDisplayCutoutMode,
+                params.layoutInDisplayCutoutMode);
+        params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
+        a.recycle();
+
+        final ActivityManager.RunningTaskInfo taskInfo = windowInfo.taskInfo;
+        final ActivityInfo activityInfo = windowInfo.targetActivityInfo != null
+                ? windowInfo.targetActivityInfo
+                : taskInfo.topActivityInfo;
+        final int displayId = taskInfo.displayId;
+        // Assumes it's safe to show starting windows of launched apps while
+        // the keyguard is being hidden. This is okay because starting windows never show
+        // secret information.
+        // TODO(b/113840485): Occluded may not only happen on default display
+        if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
+            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
+        }
+
+        // Force the window flags: this is a fake window, so it is not really
+        // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
+        // flag because we do know that the next window will take input
+        // focus, so we want to get the IME window up on top of us right away.
+        // Touches will only pass through to the host activity window and will be blocked from
+        // passing to any other windows.
+        windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+        params.flags = windowFlags;
+        params.token = appToken;
+        params.packageName = activityInfo.packageName;
+        params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
+
+        if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
+            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+        }
+
+        params.setTitle("Splash Screen " + title);
+        return params;
+    }
+    /**
      * Create a SplashScreenView object.
      *
      * In order to speed up the splash screen view to show on first frame, preparing the
@@ -248,6 +393,26 @@
         return null;
     }
 
+    /**
+     * Creates a SplashScreenView without read animatable icon and branding image.
+     */
+    SplashScreenView makeSimpleSplashScreenContentView(Context context,
+            StartingWindowInfo info, int themeBGColor) {
+        updateDensity();
+        mTmpAttrs.reset();
+        final ActivityInfo ai = info.targetActivityInfo != null
+                ? info.targetActivityInfo
+                : info.taskInfo.topActivityInfo;
+
+        final SplashViewBuilder builder = new SplashViewBuilder(context, ai);
+        final SplashScreenView view = builder
+                .setWindowBGColor(themeBGColor)
+                .chooseStyle(STARTING_WINDOW_TYPE_SPLASH_SCREEN)
+                .build();
+        view.setNotCopyable();
+        return view;
+    }
+
     private SplashScreenView makeSplashScreenContentView(Context context, StartingWindowInfo info,
             @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) {
         updateDensity();
@@ -263,7 +428,8 @@
         final int themeBGColor = legacyDrawable != null
                 ? getBGColorFromCache(ai, () -> estimateWindowBGColor(legacyDrawable))
                 : getBGColorFromCache(ai, () -> peekWindowBGColor(context, mTmpAttrs));
-        return new StartingWindowViewBuilder(context, ai)
+
+        return new SplashViewBuilder(context, ai)
                 .setWindowBGColor(themeBGColor)
                 .overlayDrawable(legacyDrawable)
                 .chooseStyle(suggestType)
@@ -322,6 +488,14 @@
         private Drawable mSplashScreenIcon = null;
         private Drawable mBrandingImage = null;
         private int mIconBgColor = Color.TRANSPARENT;
+
+        void reset() {
+            mWindowBgResId = 0;
+            mWindowBgColor = Color.TRANSPARENT;
+            mSplashScreenIcon = null;
+            mBrandingImage = null;
+            mIconBgColor = Color.TRANSPARENT;
+        }
     }
 
     /**
@@ -351,7 +525,7 @@
         return appReadyDuration;
     }
 
-    private class StartingWindowViewBuilder {
+    private class SplashViewBuilder {
         private final Context mContext;
         private final ActivityInfo mActivityInfo;
 
@@ -364,27 +538,28 @@
         /** @see #setAllowHandleSolidColor(boolean) **/
         private boolean mAllowHandleSolidColor;
 
-        StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
+        SplashViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
             mContext = context;
             mActivityInfo = aInfo;
         }
 
-        StartingWindowViewBuilder setWindowBGColor(@ColorInt int background) {
+        SplashViewBuilder setWindowBGColor(@ColorInt int background) {
             mThemeColor = background;
             return this;
         }
 
-        StartingWindowViewBuilder overlayDrawable(Drawable overlay) {
+        SplashViewBuilder overlayDrawable(Drawable overlay) {
             mOverlayDrawable = overlay;
             return this;
         }
 
-        StartingWindowViewBuilder chooseStyle(int suggestType) {
+        SplashViewBuilder chooseStyle(int suggestType) {
             mSuggestType = suggestType;
             return this;
         }
 
-        StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+        // Set up the UI thread for the View.
+        SplashViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
             mUiThreadInitTask = uiThreadInitTask;
             return this;
         }
@@ -395,7 +570,7 @@
          * android.window.SplashScreen.OnExitAnimationListener#onSplashScreenExit(SplashScreenView)}
          * callback, effectively copying the {@link SplashScreenView} into the client process.
          */
-        StartingWindowViewBuilder setAllowHandleSolidColor(boolean allowHandleSolidColor) {
+        SplashViewBuilder setAllowHandleSolidColor(boolean allowHandleSolidColor) {
             mAllowHandleSolidColor = allowHandleSolidColor;
             return this;
         }
@@ -993,10 +1168,11 @@
      * Create and play the default exit animation for splash screen view.
      */
     void applyExitAnimation(SplashScreenView view, SurfaceControl leash,
-            Rect frame, Runnable finishCallback, long createTime) {
+            Rect frame, Runnable finishCallback, long createTime, float roundedCornerRadius) {
         final Runnable playAnimation = () -> {
             final SplashScreenExitAnimation animation = new SplashScreenExitAnimation(mContext,
-                    view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback);
+                    view, leash, frame, mMainWindowShiftLength, mTransactionPool, finishCallback,
+                    roundedCornerRadius);
             animation.startAnimations();
         };
         if (view.getIconView() == null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 7f6bfd2..e419462 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -62,7 +62,7 @@
      */
     static Drawable[] makeIconDrawable(@ColorInt int backgroundColor, @ColorInt int themeColor,
             @NonNull Drawable foregroundDrawable, int srcIconSize, int iconSize,
-            boolean loadInDetail, Handler splashscreenWorkerHandler) {
+            boolean loadInDetail, Handler preDrawHandler) {
         Drawable foreground;
         Drawable background = null;
         boolean drawBackground =
@@ -74,13 +74,13 @@
             // If the icon is Adaptive, we already use the icon background.
             drawBackground = false;
             foreground = new ImmobileIconDrawable(foregroundDrawable,
-                    srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
+                    srcIconSize, iconSize, loadInDetail, preDrawHandler);
         } else {
             // Adaptive icon don't handle transparency so we draw the background of the adaptive
             // icon with the same color as the window background color instead of using two layers
             foreground = new ImmobileIconDrawable(
                     new AdaptiveForegroundDrawable(foregroundDrawable),
-                    srcIconSize, iconSize, loadInDetail, splashscreenWorkerHandler);
+                    srcIconSize, iconSize, loadInDetail, preDrawHandler);
         }
 
         if (drawBackground) {
@@ -91,9 +91,9 @@
     }
 
     static Drawable[] makeLegacyIconDrawable(@NonNull Drawable iconDrawable, int srcIconSize,
-            int iconSize, boolean loadInDetail, Handler splashscreenWorkerHandler) {
+            int iconSize, boolean loadInDetail, Handler preDrawHandler) {
         return new Drawable[]{new ImmobileIconDrawable(iconDrawable, srcIconSize, iconSize,
-                loadInDetail, splashscreenWorkerHandler)};
+                loadInDetail, preDrawHandler)};
     }
 
     /**
@@ -107,14 +107,14 @@
         private Bitmap mIconBitmap;
 
         ImmobileIconDrawable(Drawable drawable, int srcIconSize, int iconSize, boolean loadInDetail,
-                Handler splashscreenWorkerHandler) {
+                Handler preDrawHandler) {
             // This icon has lower density, don't scale it.
             if (loadInDetail) {
-                splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, iconSize));
+                preDrawHandler.post(() -> preDrawIcon(drawable, iconSize));
             } else {
                 final float scale = (float) iconSize / srcIconSize;
                 mMatrix.setScale(scale, scale);
-                splashscreenWorkerHandler.post(() -> preDrawIcon(drawable, srcIconSize));
+                preDrawHandler.post(() -> preDrawIcon(drawable, srcIconSize));
             }
         }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index ff6f2b0..4f07bfe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -16,7 +16,6 @@
 
 package com.android.wm.shell.startingsurface;
 
-import static android.content.Context.CONTEXT_RESTRICTED;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.Choreographer.CALLBACK_INSETS_ANIMATION;
 import static android.view.Display.DEFAULT_DISPLAY;
@@ -32,8 +31,6 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
@@ -198,118 +195,21 @@
         if (activityInfo == null || activityInfo.packageName == null) {
             return;
         }
-
-        final int displayId = taskInfo.displayId;
-        final int taskId = taskInfo.taskId;
-
         // replace with the default theme if the application didn't set
         final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo);
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                "addSplashScreen for package: %s with theme: %s for task: %d, suggestType: %d",
-                activityInfo.packageName, Integer.toHexString(theme), taskId, suggestType);
-        final Display display = getDisplay(displayId);
-        if (display == null) {
-            // Can't show splash screen on requested display, so skip showing at all.
-            return;
-        }
-        Context context = displayId == DEFAULT_DISPLAY
-                ? mContext : mContext.createDisplayContext(display);
+        final Context context = SplashscreenContentDrawer.createContext(mContext, windowInfo, theme,
+                suggestType, mDisplayManager);
         if (context == null) {
             return;
         }
-        if (theme != context.getThemeResId()) {
-            try {
-                context = context.createPackageContextAsUser(activityInfo.packageName,
-                        CONTEXT_RESTRICTED, UserHandle.of(taskInfo.userId));
-                context.setTheme(theme);
-            } catch (PackageManager.NameNotFoundException e) {
-                Slog.w(TAG, "Failed creating package context with package name "
-                        + activityInfo.packageName + " for user " + taskInfo.userId, e);
-                return;
-            }
-        }
+        final WindowManager.LayoutParams params = SplashscreenContentDrawer.createLayoutParameters(
+                context, windowInfo, suggestType, activityInfo.packageName,
+                suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
+                        ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT, appToken);
 
-        final Configuration taskConfig = taskInfo.getConfiguration();
-        if (taskConfig.diffPublicOnly(context.getResources().getConfiguration()) != 0) {
-            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                    "addSplashScreen: creating context based on task Configuration %s",
-                    taskConfig);
-            final Context overrideContext = context.createConfigurationContext(taskConfig);
-            overrideContext.setTheme(theme);
-            final TypedArray typedArray = overrideContext.obtainStyledAttributes(
-                    com.android.internal.R.styleable.Window);
-            final int resId = typedArray.getResourceId(R.styleable.Window_windowBackground, 0);
-            try {
-                if (resId != 0 && overrideContext.getDrawable(resId) != null) {
-                    // We want to use the windowBackground for the override context if it is
-                    // available, otherwise we use the default one to make sure a themed starting
-                    // window is displayed for the app.
-                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                            "addSplashScreen: apply overrideConfig %s",
-                            taskConfig);
-                    context = overrideContext;
-                }
-            } catch (Resources.NotFoundException e) {
-                Slog.w(TAG, "failed creating starting window for overrideConfig at taskId: "
-                        + taskId, e);
-                return;
-            }
-            typedArray.recycle();
-        }
-
-        final WindowManager.LayoutParams params = new WindowManager.LayoutParams(
-                WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
-        params.setFitInsetsSides(0);
-        params.setFitInsetsTypes(0);
-        params.format = suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN
-                ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT;
-        int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
-                | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
-                | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
-        final TypedArray a = context.obtainStyledAttributes(R.styleable.Window);
-        if (a.getBoolean(R.styleable.Window_windowShowWallpaper, false)) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-        }
-        if (suggestType == STARTING_WINDOW_TYPE_LEGACY_SPLASH_SCREEN) {
-            if (a.getBoolean(R.styleable.Window_windowDrawsSystemBarBackgrounds, false)) {
-                windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-            }
-        } else {
-            windowFlags |= WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-        }
-        params.layoutInDisplayCutoutMode = a.getInt(
-                R.styleable.Window_windowLayoutInDisplayCutoutMode,
-                params.layoutInDisplayCutoutMode);
-        params.windowAnimations = a.getResourceId(R.styleable.Window_windowAnimationStyle, 0);
-        a.recycle();
-
-        // Assumes it's safe to show starting windows of launched apps while
-        // the keyguard is being hidden. This is okay because starting windows never show
-        // secret information.
-        // TODO(b/113840485): Occluded may not only happen on default display
-        if (displayId == DEFAULT_DISPLAY && windowInfo.isKeyguardOccluded) {
-            windowFlags |= WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
-        }
-
-        // Force the window flags: this is a fake window, so it is not really
-        // touchable or focusable by the user.  We also add in the ALT_FOCUSABLE_IM
-        // flag because we do know that the next window will take input
-        // focus, so we want to get the IME window up on top of us right away.
-        // Touches will only pass through to the host activity window and will be blocked from
-        // passing to any other windows.
-        windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
-                | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-        params.flags = windowFlags;
-        params.token = appToken;
-        params.packageName = activityInfo.packageName;
-        params.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS;
-
-        if (!context.getResources().getCompatibilityInfo().supportsScreen()) {
-            params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-        }
-
-        params.setTitle("Splash Screen " + activityInfo.packageName);
+        final int displayId = taskInfo.displayId;
+        final int taskId = taskInfo.taskId;
+        final Display display = getDisplay(displayId);
 
         // TODO(b/173975965) tracking performance
         // Prepare the splash screen content view on splash screen worker thread in parallel, so the
@@ -646,7 +546,7 @@
                             mSplashscreenContentDrawer.applyExitAnimation(record.mContentView,
                                     removalInfo.windowAnimationLeash, removalInfo.mainFrame,
                                     () -> removeWindowInner(record.mDecorView, true),
-                                    record.mCreateTime);
+                                    record.mCreateTime, removalInfo.roundedCornerRadius);
                         } else {
                             // the SplashScreenView has been copied to client, hide the view to skip
                             // default exit animation
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 3929e83..9d6711f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -18,50 +18,16 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.graphics.Color.WHITE;
-import static android.graphics.Color.alpha;
 import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-import static android.view.WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES;
-import static android.view.WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
-import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_USE_BLAST;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 
-import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getNavigationBarRect;
-
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.TaskDescription;
-import android.app.ActivityThread;
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.GraphicBuffer;
-import android.graphics.Matrix;
 import android.graphics.Paint;
-import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
-import android.hardware.HardwareBuffer;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -73,20 +39,14 @@
 import android.view.InsetsSourceControl;
 import android.view.InsetsState;
 import android.view.SurfaceControl;
-import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowInsets;
-import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.window.ClientWindowFrames;
+import android.window.SnapshotDrawerUtils;
 import android.window.StartingWindowInfo;
 import android.window.TaskSnapshot;
 
-import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.DecorView;
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.internal.view.BaseIWindow;
 import com.android.wm.shell.common.ShellExecutor;
@@ -100,27 +60,8 @@
  * @hide
  */
 public class TaskSnapshotWindow {
-    /**
-     * When creating the starting window, we use the exact same layout flags such that we end up
-     * with a window with the exact same dimensions etc. However, these flags are not used in layout
-     * and might cause other side effects so we exclude them.
-     */
-    static final int FLAG_INHERIT_EXCLUDES = FLAG_NOT_FOCUSABLE
-            | FLAG_NOT_TOUCHABLE
-            | FLAG_NOT_TOUCH_MODAL
-            | FLAG_ALT_FOCUSABLE_IM
-            | FLAG_NOT_FOCUSABLE
-            | FLAG_HARDWARE_ACCELERATED
-            | FLAG_IGNORE_CHEEK_PRESSES
-            | FLAG_LOCAL_FOCUS_MODE
-            | FLAG_SLIPPERY
-            | FLAG_WATCH_OUTSIDE_TOUCH
-            | FLAG_SPLIT_TOUCH
-            | FLAG_SCALED
-            | FLAG_SECURE;
-
     private static final String TAG = StartingWindowController.TAG;
-    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=%s";
+    private static final String TITLE_FORMAT = "SnapshotStartingWindow for taskId=";
 
     private static final long DELAY_REMOVAL_TIME_GENERAL = 100;
     /**
@@ -133,25 +74,12 @@
     private final Window mWindow;
     private final Runnable mClearWindowHandler;
     private final ShellExecutor mSplashScreenExecutor;
-    private final SurfaceControl mSurfaceControl;
     private final IWindowSession mSession;
-    private final Rect mTaskBounds;
-    private final Rect mFrame = new Rect();
-    private final Rect mSystemBarInsets = new Rect();
-    private TaskSnapshot mSnapshot;
-    private final RectF mTmpSnapshotSize = new RectF();
-    private final RectF mTmpDstFrame = new RectF();
-    private final CharSequence mTitle;
     private boolean mHasDrawn;
-    private boolean mSizeMismatch;
     private final Paint mBackgroundPaint = new Paint();
     private final int mActivityType;
-    private final int mStatusBarColor;
-    private final SystemBarBackgroundPainter mSystemBarBackgroundPainter;
     private final int mOrientationOnCreation;
-    private final SurfaceControl.Transaction mTransaction;
-    private final Matrix mSnapshotMatrix = new Matrix();
-    private final float[] mTmpFloat9 = new float[9];
+
     private final Runnable mScheduledRunnable = this::removeImmediately;
     private final boolean mHasImeSurface;
 
@@ -163,42 +91,15 @@
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
                 "create taskSnapshot surface for task: %d", taskId);
 
-        final WindowManager.LayoutParams attrs = info.topOpaqueWindowLayoutParams;
-        final WindowManager.LayoutParams mainWindowParams = info.mainWindowLayoutParams;
         final InsetsState topWindowInsetsState = info.topOpaqueWindowInsetsState;
-        if (attrs == null || mainWindowParams == null || topWindowInsetsState == null) {
-            Slog.w(TAG, "unable to create taskSnapshot surface for task: " + taskId);
+
+        final WindowManager.LayoutParams layoutParams = SnapshotDrawerUtils.createLayoutParameters(
+                info, TITLE_FORMAT + taskId, TYPE_APPLICATION_STARTING,
+                snapshot.getHardwareBuffer().getFormat(), appToken);
+        if (layoutParams == null) {
+            Slog.e(TAG, "TaskSnapshotWindow no layoutParams");
             return null;
         }
-        final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
-
-        final int appearance = attrs.insetsFlags.appearance;
-        final int windowFlags = attrs.flags;
-        final int windowPrivateFlags = attrs.privateFlags;
-
-        layoutParams.packageName = mainWindowParams.packageName;
-        layoutParams.windowAnimations = mainWindowParams.windowAnimations;
-        layoutParams.dimAmount = mainWindowParams.dimAmount;
-        layoutParams.type = TYPE_APPLICATION_STARTING;
-        layoutParams.format = snapshot.getHardwareBuffer().getFormat();
-        layoutParams.flags = (windowFlags & ~FLAG_INHERIT_EXCLUDES)
-                | FLAG_NOT_FOCUSABLE
-                | FLAG_NOT_TOUCHABLE;
-        // Setting as trusted overlay to let touches pass through. This is safe because this
-        // window is controlled by the system.
-        layoutParams.privateFlags = (windowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS)
-                | PRIVATE_FLAG_TRUSTED_OVERLAY | PRIVATE_FLAG_USE_BLAST;
-        layoutParams.token = appToken;
-        layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
-        layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
-        layoutParams.insetsFlags.appearance = appearance;
-        layoutParams.insetsFlags.behavior = attrs.insetsFlags.behavior;
-        layoutParams.layoutInDisplayCutoutMode = attrs.layoutInDisplayCutoutMode;
-        layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
-        layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
-        layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
-
-        layoutParams.setTitle(String.format(TITLE_FORMAT, taskId));
 
         final Point taskSize = snapshot.getTaskSize();
         final Rect taskBounds = new Rect(0, 0, taskSize.x, taskSize.y);
@@ -222,9 +123,8 @@
         }
 
         final TaskSnapshotWindow snapshotSurface = new TaskSnapshotWindow(
-                surfaceControl, snapshot, layoutParams.getTitle(), taskDescription, appearance,
-                windowFlags, windowPrivateFlags, taskBounds, orientation, activityType,
-                info.requestedVisibleTypes, clearWindowHandler, splashScreenExecutor);
+                snapshot, taskDescription, orientation, activityType,
+                clearWindowHandler, splashScreenExecutor);
         final Window window = snapshotSurface.mWindow;
 
         final InsetsState tmpInsetsState = new InsetsState();
@@ -255,33 +155,25 @@
             snapshotSurface.clearWindowSynced();
         }
 
-        final Rect systemBarInsets = getSystemBarInsets(tmpFrames.frame, topWindowInsetsState);
-        snapshotSurface.setFrames(tmpFrames.frame, systemBarInsets);
-        snapshotSurface.drawSnapshot();
+        SnapshotDrawerUtils.drawSnapshotOnSurface(info, layoutParams, surfaceControl, snapshot,
+                taskBounds, tmpFrames.frame, topWindowInsetsState, true /* releaseAfterDraw */);
+        snapshotSurface.mHasDrawn = true;
+        snapshotSurface.reportDrawn();
+
         return snapshotSurface;
     }
 
-    public TaskSnapshotWindow(SurfaceControl surfaceControl,
-            TaskSnapshot snapshot, CharSequence title, TaskDescription taskDescription,
-            int appearance, int windowFlags, int windowPrivateFlags, Rect taskBounds,
-            int currentOrientation, int activityType, @InsetsType int requestedVisibleTypes,
-            Runnable clearWindowHandler, ShellExecutor splashScreenExecutor) {
+    public TaskSnapshotWindow(TaskSnapshot snapshot, TaskDescription taskDescription,
+            int currentOrientation, int activityType, Runnable clearWindowHandler,
+            ShellExecutor splashScreenExecutor) {
         mSplashScreenExecutor = splashScreenExecutor;
         mSession = WindowManagerGlobal.getWindowSession();
         mWindow = new Window();
         mWindow.setSession(mSession);
-        mSurfaceControl = surfaceControl;
-        mSnapshot = snapshot;
-        mTitle = title;
         int backgroundColor = taskDescription.getBackgroundColor();
         mBackgroundPaint.setColor(backgroundColor != 0 ? backgroundColor : WHITE);
-        mTaskBounds = taskBounds;
-        mSystemBarBackgroundPainter = new SystemBarBackgroundPainter(windowFlags,
-                windowPrivateFlags, appearance, taskDescription, 1f, requestedVisibleTypes);
-        mStatusBarColor = taskDescription.getStatusBarColor();
         mOrientationOnCreation = currentOrientation;
         mActivityType = activityType;
-        mTransaction = new SurfaceControl.Transaction();
         mClearWindowHandler = clearWindowHandler;
         mHasImeSurface = snapshot.hasImeSurface();
     }
@@ -294,23 +186,6 @@
 	return mHasImeSurface;
     }
 
-    /**
-     * Ask system bar background painter to draw status bar background.
-     * @hide
-     */
-    public void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame) {
-        mSystemBarBackgroundPainter.drawStatusBarBackground(c, alreadyDrawnFrame,
-                mSystemBarBackgroundPainter.getStatusBarColorViewHeight());
-    }
-
-    /**
-     * Ask system bar background painter to draw navigation bar background.
-     * @hide
-     */
-    public void drawNavigationBarBackground(Canvas c) {
-        mSystemBarBackgroundPainter.drawNavigationBarBackground(c);
-    }
-
     void scheduleRemove(boolean deferRemoveForIme) {
         // Show the latest content as soon as possible for unlocking to home.
         if (mActivityType == ACTIVITY_TYPE_HOME) {
@@ -338,178 +213,6 @@
     }
 
     /**
-     * Set frame size.
-     * @hide
-     */
-    public void setFrames(Rect frame, Rect systemBarInsets) {
-        mFrame.set(frame);
-        mSystemBarInsets.set(systemBarInsets);
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        mSizeMismatch = (mFrame.width() != snapshot.getWidth()
-                || mFrame.height() != snapshot.getHeight());
-        mSystemBarBackgroundPainter.setInsets(systemBarInsets);
-    }
-
-    static Rect getSystemBarInsets(Rect frame, InsetsState state) {
-        return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
-                false /* ignoreVisibility */).toRect();
-    }
-
-    private void drawSnapshot() {
-        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_STARTING_WINDOW,
-                "Drawing snapshot surface sizeMismatch=%b", mSizeMismatch);
-        if (mSizeMismatch) {
-            // The dimensions of the buffer and the window don't match, so attaching the buffer
-            // will fail. Better create a child window with the exact dimensions and fill the parent
-            // window with the background color!
-            drawSizeMismatchSnapshot();
-        } else {
-            drawSizeMatchSnapshot();
-        }
-        mHasDrawn = true;
-        reportDrawn();
-
-        // In case window manager leaks us, make sure we don't retain the snapshot.
-        if (mSnapshot.getHardwareBuffer() != null) {
-            mSnapshot.getHardwareBuffer().close();
-        }
-        mSnapshot = null;
-        mSurfaceControl.release();
-    }
-
-    private void drawSizeMatchSnapshot() {
-        mTransaction.setBuffer(mSurfaceControl, mSnapshot.getHardwareBuffer())
-                .setColorSpace(mSurfaceControl, mSnapshot.getColorSpace())
-                .apply();
-    }
-
-    private void drawSizeMismatchSnapshot() {
-        final HardwareBuffer buffer = mSnapshot.getHardwareBuffer();
-        final SurfaceSession session = new SurfaceSession();
-
-        // We consider nearly matched dimensions as there can be rounding errors and the user won't
-        // notice very minute differences from scaling one dimension more than the other
-        final boolean aspectRatioMismatch = Math.abs(
-                ((float) buffer.getWidth() / buffer.getHeight())
-                - ((float) mFrame.width() / mFrame.height())) > 0.01f;
-
-        // Keep a reference to it such that it doesn't get destroyed when finalized.
-        SurfaceControl childSurfaceControl = new SurfaceControl.Builder(session)
-                .setName(mTitle + " - task-snapshot-surface")
-                .setBLASTLayer()
-                .setFormat(buffer.getFormat())
-                .setParent(mSurfaceControl)
-                .setCallsite("TaskSnapshotWindow.drawSizeMismatchSnapshot")
-                .build();
-
-        final Rect frame;
-        // We can just show the surface here as it will still be hidden as the parent is
-        // still hidden.
-        mTransaction.show(childSurfaceControl);
-        if (aspectRatioMismatch) {
-            // Clip off ugly navigation bar.
-            final Rect crop = calculateSnapshotCrop();
-            frame = calculateSnapshotFrame(crop);
-            mTransaction.setWindowCrop(childSurfaceControl, crop);
-            mTransaction.setPosition(childSurfaceControl, frame.left, frame.top);
-            mTmpSnapshotSize.set(crop);
-            mTmpDstFrame.set(frame);
-        } else {
-            frame = null;
-            mTmpSnapshotSize.set(0, 0, buffer.getWidth(), buffer.getHeight());
-            mTmpDstFrame.set(mFrame);
-            mTmpDstFrame.offsetTo(0, 0);
-        }
-
-        // Scale the mismatch dimensions to fill the task bounds
-        mSnapshotMatrix.setRectToRect(mTmpSnapshotSize, mTmpDstFrame, Matrix.ScaleToFit.FILL);
-        mTransaction.setMatrix(childSurfaceControl, mSnapshotMatrix, mTmpFloat9);
-        mTransaction.setColorSpace(childSurfaceControl, mSnapshot.getColorSpace());
-        mTransaction.setBuffer(childSurfaceControl, mSnapshot.getHardwareBuffer());
-
-        if (aspectRatioMismatch) {
-            GraphicBuffer background = GraphicBuffer.create(mFrame.width(), mFrame.height(),
-                    PixelFormat.RGBA_8888,
-                    GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_HW_COMPOSER
-                            | GraphicBuffer.USAGE_SW_WRITE_RARELY);
-            // TODO: Support this on HardwareBuffer
-            final Canvas c = background.lockCanvas();
-            drawBackgroundAndBars(c, frame);
-            background.unlockCanvasAndPost(c);
-            mTransaction.setBuffer(mSurfaceControl,
-                    HardwareBuffer.createFromGraphicBuffer(background));
-        }
-        mTransaction.apply();
-        childSurfaceControl.release();
-    }
-
-    /**
-     * Calculates the snapshot crop in snapshot coordinate space.
-     *
-     * @return crop rect in snapshot coordinate space.
-     */
-    public Rect calculateSnapshotCrop() {
-        final Rect rect = new Rect();
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        rect.set(0, 0, snapshot.getWidth(), snapshot.getHeight());
-        final Rect insets = mSnapshot.getContentInsets();
-
-        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
-        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
-
-        // Let's remove all system decorations except the status bar, but only if the task is at the
-        // very top of the screen.
-        final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
-        rect.inset((int) (insets.left * scaleX),
-                isTop ? 0 : (int) (insets.top * scaleY),
-                (int) (insets.right * scaleX),
-                (int) (insets.bottom * scaleY));
-        return rect;
-    }
-
-    /**
-     * Calculates the snapshot frame in window coordinate space from crop.
-     *
-     * @param crop rect that is in snapshot coordinate space.
-     */
-    public Rect calculateSnapshotFrame(Rect crop) {
-        final HardwareBuffer snapshot = mSnapshot.getHardwareBuffer();
-        final float scaleX = (float) snapshot.getWidth() / mSnapshot.getTaskSize().x;
-        final float scaleY = (float) snapshot.getHeight() / mSnapshot.getTaskSize().y;
-
-        // Rescale the frame from snapshot to window coordinate space
-        final Rect frame = new Rect(0, 0,
-                (int) (crop.width() / scaleX + 0.5f),
-                (int) (crop.height() / scaleY + 0.5f)
-        );
-
-        // However, we also need to make space for the navigation bar on the left side.
-        frame.offset(mSystemBarInsets.left, 0);
-        return frame;
-    }
-
-    /**
-     * Draw status bar and navigation bar background.
-     * @hide
-     */
-    public void drawBackgroundAndBars(Canvas c, Rect frame) {
-        final int statusBarHeight = mSystemBarBackgroundPainter.getStatusBarColorViewHeight();
-        final boolean fillHorizontally = c.getWidth() > frame.right;
-        final boolean fillVertically = c.getHeight() > frame.bottom;
-        if (fillHorizontally) {
-            c.drawRect(frame.right, alpha(mStatusBarColor) == 0xFF ? statusBarHeight : 0,
-                    c.getWidth(), fillVertically
-                            ? frame.bottom
-                            : c.getHeight(),
-                    mBackgroundPaint);
-        }
-        if (fillVertically) {
-            c.drawRect(0, frame.bottom, c.getWidth(), c.getHeight(), mBackgroundPaint);
-        }
-        mSystemBarBackgroundPainter.drawDecors(c, frame);
-    }
-
-    /**
      * Clear window from drawer, must be post on main executor.
      */
     private void clearWindowSynced() {
@@ -557,92 +260,4 @@
             });
         }
     }
-
-    /**
-     * Helper class to draw the background of the system bars in regions the task snapshot isn't
-     * filling the window.
-     */
-    static class SystemBarBackgroundPainter {
-        private final Paint mStatusBarPaint = new Paint();
-        private final Paint mNavigationBarPaint = new Paint();
-        private final int mStatusBarColor;
-        private final int mNavigationBarColor;
-        private final int mWindowFlags;
-        private final int mWindowPrivateFlags;
-        private final float mScale;
-        private final @InsetsType int mRequestedVisibleTypes;
-        private final Rect mSystemBarInsets = new Rect();
-
-        SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
-                TaskDescription taskDescription, float scale,
-                @InsetsType int requestedVisibleTypes) {
-            mWindowFlags = windowFlags;
-            mWindowPrivateFlags = windowPrivateFlags;
-            mScale = scale;
-            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
-            final int semiTransparent = context.getColor(
-                    R.color.system_bar_background_semi_transparent);
-            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
-                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
-                    APPEARANCE_LIGHT_STATUS_BARS,
-                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
-            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
-                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
-                    taskDescription.getNavigationBarColor(), appearance,
-                    APPEARANCE_LIGHT_NAVIGATION_BARS,
-                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
-                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
-            mStatusBarPaint.setColor(mStatusBarColor);
-            mNavigationBarPaint.setColor(mNavigationBarColor);
-            mRequestedVisibleTypes = requestedVisibleTypes;
-        }
-
-        void setInsets(Rect systemBarInsets) {
-            mSystemBarInsets.set(systemBarInsets);
-        }
-
-        int getStatusBarColorViewHeight() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags, forceBarBackground)) {
-                return (int) (mSystemBarInsets.top * mScale);
-            } else {
-                return 0;
-            }
-        }
-
-        private boolean isNavigationBarColorViewVisible() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags, forceBarBackground);
-        }
-
-        void drawDecors(Canvas c, @Nullable Rect alreadyDrawnFrame) {
-            drawStatusBarBackground(c, alreadyDrawnFrame, getStatusBarColorViewHeight());
-            drawNavigationBarBackground(c);
-        }
-
-        void drawStatusBarBackground(Canvas c, @Nullable Rect alreadyDrawnFrame,
-                int statusBarHeight) {
-            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0
-                    && (alreadyDrawnFrame == null || c.getWidth() > alreadyDrawnFrame.right)) {
-                final int rightInset = (int) (mSystemBarInsets.right * mScale);
-                final int left = alreadyDrawnFrame != null ? alreadyDrawnFrame.right : 0;
-                c.drawRect(left, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-            }
-        }
-
-        @VisibleForTesting
-        void drawNavigationBarBackground(Canvas c) {
-            final Rect navigationBarRect = new Rect();
-            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
-                    mScale);
-            final boolean visible = isNavigationBarColorViewVisible();
-            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
-                c.drawRect(navigationBarRect, mNavigationBarPaint);
-            }
-        }
-    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 4e1fa29..485b400 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -77,10 +77,10 @@
                 if (mRemote.asBinder() != null) {
                     mRemote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
                 }
+                if (sct != null) {
+                    finishTransaction.merge(sct);
+                }
                 mMainExecutor.execute(() -> {
-                    if (sct != null) {
-                        finishTransaction.merge(sct);
-                    }
                     finishCallback.onTransitionFinished(wct, null /* wctCB */);
                 });
             }
@@ -90,7 +90,13 @@
             if (mRemote.asBinder() != null) {
                 mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
             }
-            mRemote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
+            // If the remote is actually in the same process, then make a copy of parameters since
+            // remote impls assume that they have to clean-up native references.
+            final SurfaceControl.Transaction remoteStartT = RemoteTransitionHandler.copyIfLocal(
+                    startTransaction, mRemote.getRemoteTransition());
+            final TransitionInfo remoteInfo =
+                    remoteStartT == startTransaction ? info : info.localRemoteCopy();
+            mRemote.getRemoteTransition().startAnimation(transition, remoteInfo, remoteStartT, cb);
             // assume that remote will apply the start transaction.
             startTransaction.clear();
         } catch (RemoteException e) {
@@ -124,7 +130,13 @@
             }
         };
         try {
-            mRemote.getRemoteTransition().mergeAnimation(transition, info, t, mergeTarget, cb);
+            // If the remote is actually in the same process, then make a copy of parameters since
+            // remote impls assume that they have to clean-up native references.
+            final SurfaceControl.Transaction remoteT =
+                    RemoteTransitionHandler.copyIfLocal(t, mRemote.getRemoteTransition());
+            final TransitionInfo remoteInfo = remoteT == t ? info : info.localRemoteCopy();
+            mRemote.getRemoteTransition().mergeAnimation(
+                    transition, remoteInfo, remoteT, mergeTarget, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error merging remote transition.", e);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index 9469529..b4e0584 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.IBinder;
+import android.os.Parcel;
 import android.os.RemoteException;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -120,10 +121,10 @@
             public void onTransitionFinished(WindowContainerTransaction wct,
                     SurfaceControl.Transaction sct) {
                 unhandleDeath(remote.asBinder(), finishCallback);
+                if (sct != null) {
+                    finishTransaction.merge(sct);
+                }
                 mMainExecutor.execute(() -> {
-                    if (sct != null) {
-                        finishTransaction.merge(sct);
-                    }
                     mRequestedRemotes.remove(transition);
                     finishCallback.onTransitionFinished(wct, null /* wctCB */);
                 });
@@ -131,8 +132,14 @@
         };
         Transitions.setRunningRemoteTransitionDelegate(remote.getAppThread());
         try {
+            // If the remote is actually in the same process, then make a copy of parameters since
+            // remote impls assume that they have to clean-up native references.
+            final SurfaceControl.Transaction remoteStartT =
+                    copyIfLocal(startTransaction, remote.getRemoteTransition());
+            final TransitionInfo remoteInfo =
+                    remoteStartT == startTransaction ? info : info.localRemoteCopy();
             handleDeath(remote.asBinder(), finishCallback);
-            remote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
+            remote.getRemoteTransition().startAnimation(transition, remoteInfo, remoteStartT, cb);
             // assume that remote will apply the start transaction.
             startTransaction.clear();
         } catch (RemoteException e) {
@@ -145,6 +152,28 @@
         return true;
     }
 
+    static SurfaceControl.Transaction copyIfLocal(SurfaceControl.Transaction t,
+            IRemoteTransition remote) {
+        // We care more about parceling than local (though they should be the same); so, use
+        // queryLocalInterface since that's what Binder uses to decide if it needs to parcel.
+        if (remote.asBinder().queryLocalInterface(IRemoteTransition.DESCRIPTOR) == null) {
+            // No local interface, so binder itself will parcel and thus we don't need to.
+            return t;
+        }
+        // Binder won't be parceling; however, the remotes assume they have their own native
+        // objects (and don't know if caller is local or not), so we need to make a COPY here so
+        // that the remote can clean it up without clearing the original transaction.
+        // Since there's no direct `copy` for Transaction, we have to parcel/unparcel instead.
+        final Parcel p = Parcel.obtain();
+        try {
+            t.writeToParcel(p, 0);
+            p.setDataPosition(0);
+            return SurfaceControl.Transaction.CREATOR.createFromParcel(p);
+        } finally {
+            p.recycle();
+        }
+    }
+
     @Override
     public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
             @NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@@ -175,7 +204,11 @@
             }
         };
         try {
-            remote.mergeAnimation(transition, info, t, mergeTarget, cb);
+            // If the remote is actually in the same process, then make a copy of parameters since
+            // remote impls assume that they have to clean-up native references.
+            final SurfaceControl.Transaction remoteT = copyIfLocal(t, remote);
+            final TransitionInfo remoteInfo = remoteT == t ? info : info.localRemoteCopy();
+            remote.mergeAnimation(transition, remoteInfo, remoteT, mergeTarget, cb);
         } catch (RemoteException e) {
             Log.e(Transitions.TAG, "Error attempting to merge remote transition.", e);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
index e338221..6af81f1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/TransitionAnimationHelper.java
@@ -322,6 +322,7 @@
                         .setPixelFormat(PixelFormat.RGBA_8888)
                         .setChildrenOnly(true)
                         .setAllowProtected(true)
+                        .setCaptureSecureLayers(true)
                         .build();
         final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
                 ScreenCapture.captureLayers(captureArgs);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 56d51bd..c6935c0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -503,6 +503,7 @@
             // Treat this as an abort since we are bypassing any merge logic and effectively
             // finishing immediately.
             onAbort(transitionToken);
+            releaseSurfaces(info);
             return;
         }
 
@@ -607,6 +608,15 @@
         onFinish(transition, wct, wctCB, false /* abort */);
     }
 
+    /**
+     * Releases an info's animation-surfaces. These don't need to persist and we need to release
+     * them asap so that SF can free memory sooner.
+     */
+    private void releaseSurfaces(@Nullable TransitionInfo info) {
+        if (info == null) return;
+        info.releaseAnimSurfaces();
+    }
+
     private void onFinish(IBinder transition,
             @Nullable WindowContainerTransaction wct,
             @Nullable WindowContainerTransactionCallback wctCB,
@@ -645,6 +655,11 @@
         }
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS,
                 "Transition animation finished (abort=%b), notifying core %s", abort, transition);
+        if (active.mStartT != null) {
+            // Applied by now, so close immediately. Do not set to null yet, though, since nullness
+            // is used later to disambiguate malformed transitions.
+            active.mStartT.close();
+        }
         // Merge all relevant transactions together
         SurfaceControl.Transaction fullFinish = active.mFinishT;
         for (int iA = activeIdx + 1; iA < mActiveTransitions.size(); ++iA) {
@@ -664,12 +679,14 @@
             fullFinish.apply();
         }
         // Now perform all the finishes.
+        releaseSurfaces(active.mInfo);
         mActiveTransitions.remove(activeIdx);
         mOrganizer.finishTransition(transition, wct, wctCB);
         while (activeIdx < mActiveTransitions.size()) {
             if (!mActiveTransitions.get(activeIdx).mMerged) break;
             ActiveTransition merged = mActiveTransitions.remove(activeIdx);
             mOrganizer.finishTransition(merged.mToken, null /* wct */, null /* wctCB */);
+            releaseSurfaces(merged.mInfo);
         }
         // sift through aborted transitions
         while (mActiveTransitions.size() > activeIdx
@@ -682,8 +699,9 @@
             }
             mOrganizer.finishTransition(aborted.mToken, null /* wct */, null /* wctCB */);
             for (int i = 0; i < mObservers.size(); ++i) {
-                mObservers.get(i).onTransitionFinished(active.mToken, true);
+                mObservers.get(i).onTransitionFinished(aborted.mToken, true);
             }
+            releaseSurfaces(aborted.mInfo);
         }
         if (mActiveTransitions.size() <= activeIdx) {
             ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "All active transition animations "
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
index 8369569..e7036c7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModel.java
@@ -55,6 +55,8 @@
 import com.android.wm.shell.freeform.FreeformTaskTransitionStarter;
 import com.android.wm.shell.transition.Transitions;
 
+import java.util.function.Supplier;
+
 /**
  * View model for the window decoration with a caption and shadows. Works with
  * {@link CaptionWindowDecoration}.
@@ -62,6 +64,8 @@
 
 public class CaptionWindowDecorViewModel implements WindowDecorViewModel {
     private static final String TAG = "CaptionViewModel";
+    private final CaptionWindowDecoration.Factory mCaptionWindowDecorFactory;
+    private final Supplier<InputManager> mInputManagerSupplier;
     private final ActivityTaskManager mActivityTaskManager;
     private final ShellTaskOrganizer mTaskOrganizer;
     private final Context mContext;
@@ -71,12 +75,13 @@
     private final SyncTransactionQueue mSyncQueue;
     private FreeformTaskTransitionStarter mTransitionStarter;
     private DesktopModeController mDesktopModeController;
-    private EventReceiver mEventReceiver;
-    private InputMonitor mInputMonitor;
     private boolean mTransitionDragActive;
 
+    private SparseArray<EventReceiver> mEventReceiversByDisplay = new SparseArray<>();
+
     private final SparseArray<CaptionWindowDecoration> mWindowDecorByTaskId = new SparseArray<>();
     private final DragStartListenerImpl mDragStartListener = new DragStartListenerImpl();
+    private EventReceiverFactory mEventReceiverFactory = new EventReceiverFactory();
 
     public CaptionWindowDecorViewModel(
             Context context,
@@ -86,6 +91,29 @@
             DisplayController displayController,
             SyncTransactionQueue syncQueue,
             DesktopModeController desktopModeController) {
+        this(
+                context,
+                mainHandler,
+                mainChoreographer,
+                taskOrganizer,
+                displayController,
+                syncQueue,
+                desktopModeController,
+                new CaptionWindowDecoration.Factory(),
+                InputManager::getInstance);
+    }
+
+    public CaptionWindowDecorViewModel(
+            Context context,
+            Handler mainHandler,
+            Choreographer mainChoreographer,
+            ShellTaskOrganizer taskOrganizer,
+            DisplayController displayController,
+            SyncTransactionQueue syncQueue,
+            DesktopModeController desktopModeController,
+            CaptionWindowDecoration.Factory captionWindowDecorFactory,
+            Supplier<InputManager> inputManagerSupplier) {
+
         mContext = context;
         mMainHandler = mainHandler;
         mMainChoreographer = mainChoreographer;
@@ -94,7 +122,13 @@
         mDisplayController = displayController;
         mSyncQueue = syncQueue;
         mDesktopModeController = desktopModeController;
-        mTransitionDragActive = false;
+
+        mCaptionWindowDecorFactory = captionWindowDecorFactory;
+        mInputManagerSupplier = inputManagerSupplier;
+    }
+
+    void setEventReceiverFactory(EventReceiverFactory eventReceiverFactory) {
+        mEventReceiverFactory = eventReceiverFactory;
     }
 
     @Override
@@ -103,73 +137,76 @@
     }
 
     @Override
-    public boolean createWindowDecoration(
+    public boolean onTaskOpening(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
         if (!shouldShowWindowDecor(taskInfo)) return false;
-        CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId);
-        if (oldDecoration != null) {
-            // close the old decoration if it exists to avoid two window decorations being added
-            oldDecoration.close();
-        }
-        final CaptionWindowDecoration windowDecoration = new CaptionWindowDecoration(
-                mContext,
-                mDisplayController,
-                mTaskOrganizer,
-                taskInfo,
-                taskSurface,
-                mMainHandler,
-                mMainChoreographer,
-                mSyncQueue);
-        mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
-
-        TaskPositioner taskPositioner = new TaskPositioner(mTaskOrganizer, windowDecoration,
-                mDragStartListener);
-        CaptionTouchEventListener touchEventListener =
-                new CaptionTouchEventListener(taskInfo, taskPositioner,
-                        windowDecoration.getDragDetector());
-        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
-        windowDecoration.setDragResizeCallback(taskPositioner);
-        setupWindowDecorationForTransition(taskInfo, startT, finishT);
-        if (mInputMonitor == null) {
-            mInputMonitor = InputManager.getInstance().monitorGestureInput(
-                    "caption-touch", mContext.getDisplayId());
-            mEventReceiver = new EventReceiver(
-                    mInputMonitor.getInputChannel(), Looper.myLooper());
-        }
+        createWindowDecoration(taskInfo, taskSurface, startT, finishT);
         return true;
     }
 
     @Override
     public void onTaskInfoChanged(RunningTaskInfo taskInfo) {
         final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+
         if (decoration == null) return;
 
+        int oldDisplayId = decoration.mDisplay.getDisplayId();
+        if (taskInfo.displayId != oldDisplayId) {
+            removeTaskFromEventReceiver(oldDisplayId);
+            incrementEventReceiverTasks(taskInfo.displayId);
+        }
+
         decoration.relayout(taskInfo);
     }
 
     @Override
-    public boolean setupWindowDecorationForTransition(
+    public void onTaskChanging(
+            RunningTaskInfo taskInfo,
+            SurfaceControl taskSurface,
+            SurfaceControl.Transaction startT,
+            SurfaceControl.Transaction finishT) {
+        final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+
+        if (!shouldShowWindowDecor(taskInfo)) {
+            if (decoration != null) {
+                destroyWindowDecoration(taskInfo);
+            }
+            return;
+        }
+
+        if (decoration == null) {
+            createWindowDecoration(taskInfo, taskSurface, startT, finishT);
+        } else {
+            decoration.relayout(taskInfo, startT, finishT);
+        }
+    }
+
+    @Override
+    public void onTaskClosing(
             RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT) {
         final CaptionWindowDecoration decoration = mWindowDecorByTaskId.get(taskInfo.taskId);
-        if (decoration == null) return false;
+        if (decoration == null) return;
 
         decoration.relayout(taskInfo, startT, finishT);
-        return true;
     }
 
     @Override
-    public boolean destroyWindowDecoration(RunningTaskInfo taskInfo) {
+    public void destroyWindowDecoration(RunningTaskInfo taskInfo) {
         final CaptionWindowDecoration decoration =
                 mWindowDecorByTaskId.removeReturnOld(taskInfo.taskId);
-        if (decoration == null) return false;
+        if (decoration == null) return;
 
         decoration.close();
-        return true;
+        int displayId = taskInfo.displayId;
+        if (mEventReceiversByDisplay.contains(displayId)) {
+            EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
+            removeTaskFromEventReceiver(displayId);
+        }
     }
 
     private class CaptionTouchEventListener implements
@@ -217,6 +254,7 @@
                 decoration.setButtonVisibility();
             }
         }
+
         private void injectBackKey() {
             sendBackEvent(KeyEvent.ACTION_DOWN);
             sendBackEvent(KeyEvent.ACTION_UP);
@@ -266,7 +304,7 @@
          */
         private void handleEventForMove(MotionEvent e) {
             RunningTaskInfo taskInfo = mTaskOrganizer.getRunningTaskInfo(mTaskId);
-            int windowingMode =  mDesktopModeController
+            int windowingMode = mDesktopModeController
                     .getDisplayAreaWindowingMode(taskInfo.displayId);
             if (windowingMode == WINDOWING_MODE_FULLSCREEN) {
                 return;
@@ -302,9 +340,13 @@
     }
 
     // InputEventReceiver to listen for touch input outside of caption bounds
-    private class EventReceiver extends InputEventReceiver {
-        EventReceiver(InputChannel channel, Looper looper) {
+    class EventReceiver extends InputEventReceiver {
+        private InputMonitor mInputMonitor;
+        private int mTasksOnDisplay;
+        EventReceiver(InputMonitor inputMonitor, InputChannel channel, Looper looper) {
             super(channel, looper);
+            mInputMonitor = inputMonitor;
+            mTasksOnDisplay = 1;
         }
 
         @Override
@@ -312,24 +354,78 @@
             boolean handled = false;
             if (event instanceof MotionEvent) {
                 handled = true;
-                CaptionWindowDecorViewModel.this.handleReceivedMotionEvent((MotionEvent) event);
+                CaptionWindowDecorViewModel.this
+                        .handleReceivedMotionEvent((MotionEvent) event, mInputMonitor);
             }
             finishInputEvent(event, handled);
         }
+
+        @Override
+        public void dispose() {
+            if (mInputMonitor != null) {
+                mInputMonitor.dispose();
+                mInputMonitor = null;
+            }
+            super.dispose();
+        }
+
+        private void incrementTaskNumber() {
+            mTasksOnDisplay++;
+        }
+
+        private void decrementTaskNumber() {
+            mTasksOnDisplay--;
+        }
+
+        private int getTasksOnDisplay() {
+            return mTasksOnDisplay;
+        }
+    }
+
+    /**
+     * Check if an EventReceiver exists on a particular display.
+     * If it does, increment its task count. Otherwise, create one for that display.
+     * @param displayId the display to check against
+     */
+    private void incrementEventReceiverTasks(int displayId) {
+        if (mEventReceiversByDisplay.contains(displayId)) {
+            EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
+            eventReceiver.incrementTaskNumber();
+        } else {
+            createInputChannel(displayId);
+        }
+    }
+
+    // If all tasks on this display are gone, we don't need to monitor its input.
+    private void removeTaskFromEventReceiver(int displayId) {
+        if (!mEventReceiversByDisplay.contains(displayId)) return;
+        EventReceiver eventReceiver = mEventReceiversByDisplay.get(displayId);
+        if (eventReceiver == null) return;
+        eventReceiver.decrementTaskNumber();
+        if (eventReceiver.getTasksOnDisplay() == 0) {
+            disposeInputChannel(displayId);
+        }
+    }
+
+    class EventReceiverFactory {
+        EventReceiver create(InputMonitor inputMonitor, InputChannel channel, Looper looper) {
+            return new EventReceiver(inputMonitor, channel, looper);
+        }
     }
 
     /**
      * Handle MotionEvents relevant to focused task's caption that don't directly touch it
+     *
      * @param ev the {@link MotionEvent} received by {@link EventReceiver}
      */
-    private void handleReceivedMotionEvent(MotionEvent ev) {
+    private void handleReceivedMotionEvent(MotionEvent ev, InputMonitor inputMonitor) {
         if (!DesktopModeStatus.isActive(mContext)) {
             handleCaptionThroughStatusBar(ev);
         }
         handleEventOutsideFocusedCaption(ev);
         // Prevent status bar from reacting to a caption drag.
         if (mTransitionDragActive && !DesktopModeStatus.isActive(mContext)) {
-            mInputMonitor.pilferPointers();
+            inputMonitor.pilferPointers();
         }
     }
 
@@ -348,6 +444,7 @@
         }
     }
 
+
     /**
      * Perform caption actions if not able to through normal means.
      * Turn on desktop mode if handle is dragged below status bar.
@@ -401,6 +498,21 @@
         return focusedDecor;
     }
 
+    private void createInputChannel(int displayId) {
+        InputManager inputManager = mInputManagerSupplier.get();
+        InputMonitor inputMonitor =
+                inputManager.monitorGestureInput("caption-touch", mContext.getDisplayId());
+        EventReceiver eventReceiver = mEventReceiverFactory.create(
+                inputMonitor, inputMonitor.getInputChannel(), Looper.myLooper());
+        mEventReceiversByDisplay.put(displayId, eventReceiver);
+    }
+
+    private void disposeInputChannel(int displayId) {
+        EventReceiver eventReceiver = mEventReceiversByDisplay.removeReturnOld(displayId);
+        if (eventReceiver != null) {
+            eventReceiver.dispose();
+        }
+    }
 
     private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
         if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
@@ -410,7 +522,40 @@
                 .getResources().getConfiguration().smallestScreenWidthDp >= 600;
     }
 
-    private class DragStartListenerImpl implements TaskPositioner.DragStartListener{
+    private void createWindowDecoration(
+            ActivityManager.RunningTaskInfo taskInfo,
+            SurfaceControl taskSurface,
+            SurfaceControl.Transaction startT,
+            SurfaceControl.Transaction finishT) {
+        CaptionWindowDecoration oldDecoration = mWindowDecorByTaskId.get(taskInfo.taskId);
+        if (oldDecoration != null) {
+            // close the old decoration if it exists to avoid two window decorations being added
+            oldDecoration.close();
+        }
+        final CaptionWindowDecoration windowDecoration =
+                mCaptionWindowDecorFactory.create(
+                        mContext,
+                        mDisplayController,
+                        mTaskOrganizer,
+                        taskInfo,
+                        taskSurface,
+                        mMainHandler,
+                        mMainChoreographer,
+                        mSyncQueue);
+        mWindowDecorByTaskId.put(taskInfo.taskId, windowDecoration);
+
+        TaskPositioner taskPositioner =
+                new TaskPositioner(mTaskOrganizer, windowDecoration, mDragStartListener);
+        CaptionTouchEventListener touchEventListener =
+                new CaptionTouchEventListener(
+                        taskInfo, taskPositioner, windowDecoration.getDragDetector());
+        windowDecoration.setCaptionListeners(touchEventListener, touchEventListener);
+        windowDecoration.setDragResizeCallback(taskPositioner);
+        windowDecoration.relayout(taskInfo, startT, finishT);
+        incrementEventReceiverTasks(taskInfo.displayId);
+    }
+
+    private class DragStartListenerImpl implements TaskPositioner.DragStartListener {
         @Override
         public void onDragStart(int taskId) {
             mWindowDecorByTaskId.get(taskId).closeHandleMenu();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
index 59576cd..037ca20 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/CaptionWindowDecoration.java
@@ -42,7 +42,8 @@
 
 /**
  * Defines visuals and behaviors of a window decoration of a caption bar and shadows. It works with
- * {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close button.
+ * {@link CaptionWindowDecorViewModel}. The caption bar contains a handle, back button, and close
+ * button.
  *
  * The shadow's thickness is 20dp when the window is in focus and 5dp when the window isn't.
  */
@@ -181,12 +182,12 @@
         if (oldDecorationSurface != mDecorationContainerSurface || mDragResizeListener == null) {
             closeDragResizeListener();
             mDragResizeListener = new DragResizeInputListener(
-                        mContext,
-                        mHandler,
-                        mChoreographer,
-                        mDisplay.getDisplayId(),
-                        mDecorationContainerSurface,
-                        mDragResizeCallback);
+                    mContext,
+                    mHandler,
+                    mChoreographer,
+                    mDisplay.getDisplayId(),
+                    mDecorationContainerSurface,
+                    mDragResizeCallback);
         }
 
         int touchSlop = ViewConfiguration.get(mResult.mRootView.getContext()).getScaledTouchSlop();
@@ -242,7 +243,6 @@
 
     /**
      * Sets the visibility of buttons and color of caption based on desktop mode status
-     *
      */
     void setButtonVisibility() {
         mDesktopActive = DesktopModeStatus.isActive(mContext);
@@ -313,6 +313,7 @@
 
     /**
      * Close an open handle menu if input is outside of menu coordinates
+     *
      * @param ev the tapped point to compare against
      */
     void closeHandleMenuIfNeeded(MotionEvent ev) {
@@ -329,6 +330,7 @@
 
     /**
      * Offset the coordinates of a {@link MotionEvent} to be in the same coordinate space as caption
+     *
      * @param ev the {@link MotionEvent} to offset
      * @return the point of the input in local space
      */
@@ -343,7 +345,8 @@
 
     /**
      * Determine if a passed MotionEvent is in a view in caption
-     * @param ev the {@link MotionEvent} to check
+     *
+     * @param ev       the {@link MotionEvent} to check
      * @param layoutId the id of the view
      * @return {@code true} if event is inside the specified view, {@code false} if not
      */
@@ -363,6 +366,7 @@
      * Check a passed MotionEvent if a click has occurred on any button on this caption
      * Note this should only be called when a regular onClick is not possible
      * (i.e. the button was clicked through status bar layer)
+     *
      * @param ev the MotionEvent to compare
      */
     void checkClickEvent(MotionEvent ev) {
@@ -399,4 +403,27 @@
         closeHandleMenu();
         super.close();
     }
+
+    static class Factory {
+
+        CaptionWindowDecoration create(
+                Context context,
+                DisplayController displayController,
+                ShellTaskOrganizer taskOrganizer,
+                ActivityManager.RunningTaskInfo taskInfo,
+                SurfaceControl taskSurface,
+                Handler handler,
+                Choreographer choreographer,
+                SyncTransactionQueue syncQueue) {
+            return new CaptionWindowDecoration(
+                    context,
+                    displayController,
+                    taskOrganizer,
+                    taskInfo,
+                    taskSurface,
+                    handler,
+                    choreographer,
+                    syncQueue);
+        }
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
index 2ce4d04..907977c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecorViewModel.java
@@ -28,7 +28,6 @@
  * servers.
  */
 public interface WindowDecorViewModel {
-
     /**
      * Sets the transition starter that starts freeform task transitions.
      *
@@ -37,16 +36,16 @@
     void setFreeformTaskTransitionStarter(FreeformTaskTransitionStarter transitionStarter);
 
     /**
-     * Creates a window decoration for the given task.
-     * Can be {@code null} for Fullscreen tasks but not Freeform ones.
+     * Creates a window decoration for the given task. Can be {@code null} for Fullscreen tasks but
+     * not Freeform ones.
      *
-     * @param taskInfo the initial task info of the task
+     * @param taskInfo    the initial task info of the task
      * @param taskSurface the surface of the task
-     * @param startT the start transaction to be applied before the transition
-     * @param finishT the finish transaction to restore states after the transition
+     * @param startT      the start transaction to be applied before the transition
+     * @param finishT     the finish transaction to restore states after the transition
      * @return {@code true} if window decoration was created, {@code false} otherwise
      */
-    boolean createWindowDecoration(
+    boolean onTaskOpening(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl taskSurface,
             SurfaceControl.Transaction startT,
@@ -54,7 +53,7 @@
 
     /**
      * Notifies a task info update on the given task, with the window decoration created previously
-     * for this task by {@link #createWindowDecoration}.
+     * for this task by {@link #onTaskOpening}.
      *
      * @param taskInfo the new task info of the task
      */
@@ -62,13 +61,29 @@
 
     /**
      * Notifies a transition is about to start about the given task to give the window decoration a
-     * chance to prepare for this transition.
+     * chance to prepare for this transition. Unlike {@link #onTaskInfoChanged}, this method creates
+     * a window decoration if one does not exist but is required.
      *
-     * @param startT the start transaction to be applied before the transition
-     * @param finishT the finish transaction to restore states after the transition
-     * @return {@code true} if window decoration exists, {@code false} otherwise
+     * @param taskInfo    the initial task info of the task
+     * @param taskSurface the surface of the task
+     * @param startT      the start transaction to be applied before the transition
+     * @param finishT     the finish transaction to restore states after the transition
      */
-    boolean setupWindowDecorationForTransition(
+    void onTaskChanging(
+            ActivityManager.RunningTaskInfo taskInfo,
+            SurfaceControl taskSurface,
+            SurfaceControl.Transaction startT,
+            SurfaceControl.Transaction finishT);
+
+    /**
+     * Notifies that the given task is about to close to give the window decoration a chance to
+     * prepare for this transition.
+     *
+     * @param taskInfo the initial task info of the task
+     * @param startT   the start transaction to be applied before the transition
+     * @param finishT  the finish transaction to restore states after the transition
+     */
+    void onTaskClosing(
             ActivityManager.RunningTaskInfo taskInfo,
             SurfaceControl.Transaction startT,
             SurfaceControl.Transaction finishT);
@@ -77,7 +92,6 @@
      * Destroys the window decoration of the give task.
      *
      * @param taskInfo the info of the task
-     * @return {@code true} if window decoration was destroyed, {@code false} otherwise
      */
-    boolean destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
-}
+    void destroyWindowDecoration(ActivityManager.RunningTaskInfo taskInfo);
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
index 7ecb3f3..9215496 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/WindowDecoration.java
@@ -251,7 +251,9 @@
         }
 
         final int captionHeight = loadDimensionPixelSize(resources, params.mCaptionHeightId);
-        final int captionWidth = loadDimensionPixelSize(resources, params.mCaptionWidthId);
+        final int captionWidth = params.mCaptionWidthId == Resources.ID_NULL
+                ? taskBounds.width()
+                : loadDimensionPixelSize(resources, params.mCaptionWidthId);
 
         startT.setPosition(
                         mCaptionContainerSurface,
diff --git a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
index 08913c6..27fc381a 100644
--- a/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
+++ b/libs/WindowManager/Shell/tests/flicker/AndroidTest.xml
@@ -19,6 +19,8 @@
         <option name="run-command" value="locksettings set-disabled false" />
         <!-- restart launcher to activate TAPL -->
         <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+        <!-- Ensure output directory is empty at the start -->
+        <option name="run-command" value="rm -rf /sdcard/flicker" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true"/>
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
index 6370df4..8465678 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/BaseTest.kt
@@ -20,10 +20,10 @@
 import android.platform.test.annotations.Presubmit
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.entireScreenCovered
+import com.android.server.wm.flicker.junit.FlickerBuilderProvider
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
 import com.android.server.wm.flicker.navBarWindowIsAlwaysVisible
@@ -45,12 +45,12 @@
 abstract class BaseTest
 @JvmOverloads
 constructor(
-    protected val testSpec: FlickerTestParameter,
+    protected val flicker: FlickerTest,
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
     protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
 ) {
     init {
-        testSpec.setIsTablet(
+        flicker.scenario.setIsTablet(
             WindowManagerStateHelper(instrumentation, clearCacheAfterParsing = false)
                 .currentState
                 .wmState
@@ -68,13 +68,13 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            setup { testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet) }
+            setup { flicker.scenario.setIsTablet(wmHelper.currentState.wmState.isTablet) }
             transition()
         }
     }
 
     /** Checks that all parts of the screen are covered during the transition */
-    @Presubmit @Test open fun entireScreenCovered() = testSpec.entireScreenCovered()
+    @Presubmit @Test open fun entireScreenCovered() = flicker.entireScreenCovered()
 
     /**
      * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
@@ -82,8 +82,8 @@
     @Presubmit
     @Test
     open fun navBarLayerIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerIsVisibleAtStartAndEnd()
     }
 
     /**
@@ -93,8 +93,8 @@
     @Presubmit
     @Test
     open fun navBarLayerPositionAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerPositionAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerPositionAtStartAndEnd()
     }
 
     /**
@@ -105,8 +105,8 @@
     @Presubmit
     @Test
     open fun navBarWindowIsAlwaysVisible() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsAlwaysVisible()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsAlwaysVisible()
     }
 
     /**
@@ -115,8 +115,8 @@
     @Presubmit
     @Test
     open fun taskBarLayerIsVisibleAtStartAndEnd() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarLayerIsVisibleAtStartAndEnd()
     }
 
     /**
@@ -127,8 +127,8 @@
     @Presubmit
     @Test
     open fun taskBarWindowIsAlwaysVisible() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarWindowIsAlwaysVisible()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarWindowIsAlwaysVisible()
     }
 
     /**
@@ -137,8 +137,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarLayerIsVisibleAtStartAndEnd() =
-        testSpec.statusBarLayerIsVisibleAtStartAndEnd()
+    open fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
 
     /**
      * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
@@ -146,7 +145,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarLayerPositionAtStartAndEnd() = testSpec.statusBarLayerPositionAtStartAndEnd()
+    open fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
 
     /**
      * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
@@ -154,7 +153,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
 
     /**
      * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
@@ -163,7 +162,7 @@
     @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
+        flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
     }
 
     /**
@@ -173,6 +172,6 @@
     @Presubmit
     @Test
     open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
+        flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
index 8765ad1..5186914 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/CommonAssertions.kt
@@ -18,23 +18,23 @@
 
 package com.android.wm.shell.flicker
 
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.traces.layers.LayerTraceEntrySubject
 import com.android.server.wm.flicker.traces.layers.LayersTraceSubject
 import com.android.server.wm.traces.common.IComponentMatcher
 import com.android.server.wm.traces.common.region.Region
+import com.android.server.wm.traces.common.service.PlatformConsts
 
-fun FlickerTestParameter.appPairsDividerIsVisibleAtEnd() {
+fun FlickerTest.appPairsDividerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.appPairsDividerIsInvisibleAtEnd() {
+fun FlickerTest.appPairsDividerIsInvisibleAtEnd() {
     assertLayersEnd { this.notContains(APP_PAIR_SPLIT_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.appPairsDividerBecomesVisible() {
+fun FlickerTest.appPairsDividerBecomesVisible() {
     assertLayers {
         this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
             .then()
@@ -42,7 +42,7 @@
     }
 }
 
-fun FlickerTestParameter.splitScreenEntered(
+fun FlickerTest.splitScreenEntered(
     component1: IComponentMatcher,
     component2: IComponentMatcher,
     fromOtherApp: Boolean,
@@ -69,7 +69,7 @@
     splitScreenDividerIsVisibleAtEnd()
 }
 
-fun FlickerTestParameter.splitScreenDismissed(
+fun FlickerTest.splitScreenDismissed(
     component1: IComponentMatcher,
     component2: IComponentMatcher,
     toHome: Boolean
@@ -87,27 +87,27 @@
     splitScreenDividerIsInvisibleAtEnd()
 }
 
-fun FlickerTestParameter.splitScreenDividerIsVisibleAtStart() {
+fun FlickerTest.splitScreenDividerIsVisibleAtStart() {
     assertLayersStart { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.splitScreenDividerIsVisibleAtEnd() {
+fun FlickerTest.splitScreenDividerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.splitScreenDividerIsInvisibleAtStart() {
+fun FlickerTest.splitScreenDividerIsInvisibleAtStart() {
     assertLayersStart { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.splitScreenDividerIsInvisibleAtEnd() {
+fun FlickerTest.splitScreenDividerIsInvisibleAtEnd() {
     assertLayersEnd { this.isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.splitScreenDividerBecomesVisible() {
+fun FlickerTest.splitScreenDividerBecomesVisible() {
     layerBecomesVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 }
 
-fun FlickerTestParameter.splitScreenDividerBecomesInvisible() {
+fun FlickerTest.splitScreenDividerBecomesInvisible() {
     assertLayers {
         this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
             .then()
@@ -115,23 +115,23 @@
     }
 }
 
-fun FlickerTestParameter.layerBecomesVisible(component: IComponentMatcher) {
+fun FlickerTest.layerBecomesVisible(component: IComponentMatcher) {
     assertLayers { this.isInvisible(component).then().isVisible(component) }
 }
 
-fun FlickerTestParameter.layerBecomesInvisible(component: IComponentMatcher) {
+fun FlickerTest.layerBecomesInvisible(component: IComponentMatcher) {
     assertLayers { this.isVisible(component).then().isInvisible(component) }
 }
 
-fun FlickerTestParameter.layerIsVisibleAtEnd(component: IComponentMatcher) {
+fun FlickerTest.layerIsVisibleAtEnd(component: IComponentMatcher) {
     assertLayersEnd { this.isVisible(component) }
 }
 
-fun FlickerTestParameter.layerKeepVisible(component: IComponentMatcher) {
+fun FlickerTest.layerKeepVisible(component: IComponentMatcher) {
     assertLayers { this.isVisible(component) }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsBecomesVisible(
+fun FlickerTest.splitAppLayerBoundsBecomesVisible(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean
@@ -145,12 +145,12 @@
                 component,
                 landscapePosLeft,
                 portraitPosTop,
-                endRotation
+                scenario.endRotation
             )
     }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
+fun FlickerTest.splitAppLayerBoundsBecomesVisibleByDrag(component: IComponentMatcher) {
     assertLayers {
         this.notContains(SPLIT_SCREEN_DIVIDER_COMPONENT.or(component), isOptional = true)
             .then()
@@ -161,7 +161,7 @@
     }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsBecomesInvisible(
+fun FlickerTest.splitAppLayerBoundsBecomesInvisible(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean
@@ -171,7 +171,7 @@
                 component,
                 landscapePosLeft,
                 portraitPosTop,
-                endRotation
+                scenario.endRotation
             )
             .then()
             .isVisible(component, true)
@@ -180,27 +180,37 @@
     }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsIsVisibleAtEnd(
+fun FlickerTest.splitAppLayerBoundsIsVisibleAtEnd(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean
 ) {
     assertLayersEnd {
-        splitAppLayerBoundsSnapToDivider(component, landscapePosLeft, portraitPosTop, endRotation)
+        splitAppLayerBoundsSnapToDivider(
+            component,
+            landscapePosLeft,
+            portraitPosTop,
+            scenario.endRotation
+        )
     }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsKeepVisible(
+fun FlickerTest.splitAppLayerBoundsKeepVisible(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean
 ) {
     assertLayers {
-        splitAppLayerBoundsSnapToDivider(component, landscapePosLeft, portraitPosTop, endRotation)
+        splitAppLayerBoundsSnapToDivider(
+            component,
+            landscapePosLeft,
+            portraitPosTop,
+            scenario.endRotation
+        )
     }
 }
 
-fun FlickerTestParameter.splitAppLayerBoundsChanges(
+fun FlickerTest.splitAppLayerBoundsChanges(
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean
@@ -211,14 +221,14 @@
                 component,
                 landscapePosLeft,
                 portraitPosTop,
-                endRotation
+                scenario.endRotation
             )
         } else {
             this.splitAppLayerBoundsSnapToDivider(
                     component,
                     landscapePosLeft,
                     portraitPosTop,
-                    endRotation
+                    scenario.endRotation
                 )
                 .then()
                 .isInvisible(component)
@@ -227,7 +237,7 @@
                     component,
                     landscapePosLeft,
                     portraitPosTop,
-                    endRotation
+                    scenario.endRotation
                 )
         }
     }
@@ -237,7 +247,7 @@
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean,
-    rotation: Int
+    rotation: PlatformConsts.Rotation
 ): LayersTraceSubject {
     return invoke("splitAppLayerBoundsSnapToDivider") {
         it.splitAppLayerBoundsSnapToDivider(component, landscapePosLeft, portraitPosTop, rotation)
@@ -248,7 +258,7 @@
     component: IComponentMatcher,
     landscapePosLeft: Boolean,
     portraitPosTop: Boolean,
-    rotation: Int
+    rotation: PlatformConsts.Rotation
 ): LayerTraceEntrySubject {
     val displayBounds = WindowUtils.getDisplayBounds(rotation)
     return invoke {
@@ -292,7 +302,7 @@
     }
 }
 
-fun FlickerTestParameter.appWindowBecomesVisible(component: IComponentMatcher) {
+fun FlickerTest.appWindowBecomesVisible(component: IComponentMatcher) {
     assertWm {
         this.isAppWindowInvisible(component)
             .then()
@@ -304,39 +314,39 @@
     }
 }
 
-fun FlickerTestParameter.appWindowBecomesInvisible(component: IComponentMatcher) {
+fun FlickerTest.appWindowBecomesInvisible(component: IComponentMatcher) {
     assertWm { this.isAppWindowVisible(component).then().isAppWindowInvisible(component) }
 }
 
-fun FlickerTestParameter.appWindowIsVisibleAtStart(component: IComponentMatcher) {
+fun FlickerTest.appWindowIsVisibleAtStart(component: IComponentMatcher) {
     assertWmStart { this.isAppWindowVisible(component) }
 }
 
-fun FlickerTestParameter.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
+fun FlickerTest.appWindowIsVisibleAtEnd(component: IComponentMatcher) {
     assertWmEnd { this.isAppWindowVisible(component) }
 }
 
-fun FlickerTestParameter.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
+fun FlickerTest.appWindowIsInvisibleAtStart(component: IComponentMatcher) {
     assertWmStart { this.isAppWindowInvisible(component) }
 }
 
-fun FlickerTestParameter.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
+fun FlickerTest.appWindowIsInvisibleAtEnd(component: IComponentMatcher) {
     assertWmEnd { this.isAppWindowInvisible(component) }
 }
 
-fun FlickerTestParameter.appWindowIsNotContainAtStart(component: IComponentMatcher) {
+fun FlickerTest.appWindowIsNotContainAtStart(component: IComponentMatcher) {
     assertWmStart { this.notContains(component) }
 }
 
-fun FlickerTestParameter.appWindowKeepVisible(component: IComponentMatcher) {
+fun FlickerTest.appWindowKeepVisible(component: IComponentMatcher) {
     assertWm { this.isAppWindowVisible(component) }
 }
 
-fun FlickerTestParameter.dockedStackDividerIsVisibleAtEnd() {
+fun FlickerTest.dockedStackDividerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.dockedStackDividerBecomesVisible() {
+fun FlickerTest.dockedStackDividerBecomesVisible() {
     assertLayers {
         this.isInvisible(DOCKED_STACK_DIVIDER_COMPONENT)
             .then()
@@ -344,7 +354,7 @@
     }
 }
 
-fun FlickerTestParameter.dockedStackDividerBecomesInvisible() {
+fun FlickerTest.dockedStackDividerBecomesInvisible() {
     assertLayers {
         this.isVisible(DOCKED_STACK_DIVIDER_COMPONENT)
             .then()
@@ -352,12 +362,12 @@
     }
 }
 
-fun FlickerTestParameter.dockedStackDividerNotExistsAtEnd() {
+fun FlickerTest.dockedStackDividerNotExistsAtEnd() {
     assertLayersEnd { this.notContains(DOCKED_STACK_DIVIDER_COMPONENT) }
 }
 
-fun FlickerTestParameter.appPairsPrimaryBoundsIsVisibleAtEnd(
-    rotation: Int,
+fun FlickerTest.appPairsPrimaryBoundsIsVisibleAtEnd(
+    rotation: PlatformConsts.Rotation,
     primaryComponent: IComponentMatcher
 ) {
     assertLayersEnd {
@@ -366,8 +376,8 @@
     }
 }
 
-fun FlickerTestParameter.dockedStackPrimaryBoundsIsVisibleAtEnd(
-    rotation: Int,
+fun FlickerTest.dockedStackPrimaryBoundsIsVisibleAtEnd(
+    rotation: PlatformConsts.Rotation,
     primaryComponent: IComponentMatcher
 ) {
     assertLayersEnd {
@@ -376,8 +386,8 @@
     }
 }
 
-fun FlickerTestParameter.appPairsSecondaryBoundsIsVisibleAtEnd(
-    rotation: Int,
+fun FlickerTest.appPairsSecondaryBoundsIsVisibleAtEnd(
+    rotation: PlatformConsts.Rotation,
     secondaryComponent: IComponentMatcher
 ) {
     assertLayersEnd {
@@ -386,8 +396,8 @@
     }
 }
 
-fun FlickerTestParameter.dockedStackSecondaryBoundsIsVisibleAtEnd(
-    rotation: Int,
+fun FlickerTest.dockedStackSecondaryBoundsIsVisibleAtEnd(
+    rotation: PlatformConsts.Rotation,
     secondaryComponent: IComponentMatcher
 ) {
     assertLayersEnd {
@@ -396,38 +406,38 @@
     }
 }
 
-fun getPrimaryRegion(dividerRegion: Region, rotation: Int): Region {
+fun getPrimaryRegion(dividerRegion: Region, rotation: PlatformConsts.Rotation): Region {
     val displayBounds = WindowUtils.getDisplayBounds(rotation)
-    return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
-        Region.from(
-            0,
-            0,
-            displayBounds.bounds.right,
-            dividerRegion.bounds.top + WindowUtils.dockedStackDividerInset
-        )
-    } else {
+    return if (rotation.isRotated()) {
         Region.from(
             0,
             0,
             dividerRegion.bounds.left + WindowUtils.dockedStackDividerInset,
             displayBounds.bounds.bottom
         )
+    } else {
+        Region.from(
+            0,
+            0,
+            displayBounds.bounds.right,
+            dividerRegion.bounds.top + WindowUtils.dockedStackDividerInset
+        )
     }
 }
 
-fun getSecondaryRegion(dividerRegion: Region, rotation: Int): Region {
+fun getSecondaryRegion(dividerRegion: Region, rotation: PlatformConsts.Rotation): Region {
     val displayBounds = WindowUtils.getDisplayBounds(rotation)
-    return if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
+    return if (rotation.isRotated()) {
         Region.from(
+            dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset,
             0,
-            dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset,
             displayBounds.bounds.right,
             displayBounds.bounds.bottom
         )
     } else {
         Region.from(
-            dividerRegion.bounds.right - WindowUtils.dockedStackDividerInset,
             0,
+            dividerRegion.bounds.bottom - WindowUtils.dockedStackDividerInset,
             displayBounds.bounds.right,
             displayBounds.bounds.bottom
         )
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
index 0fc2004..996b677 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/BaseBubbleScreen.kt
@@ -21,21 +21,21 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.os.ServiceManager
-import android.view.Surface
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.Flicker
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.IFlickerTestData
 import com.android.server.wm.flicker.helpers.LaunchBubbleHelper
 import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.BaseTest
 import org.junit.runners.Parameterized
 
 /** Base configurations for Bubble flicker tests */
-abstract class BaseBubbleScreen(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class BaseBubbleScreen(flicker: FlickerTest) : BaseTest(flicker) {
 
     protected val context: Context = instrumentation.context
     protected val testApp = LaunchBubbleHelper(instrumentation)
@@ -79,17 +79,18 @@
         }
     }
 
-    protected fun Flicker.waitAndGetAddBubbleBtn(): UiObject2? =
+    protected fun IFlickerTestData.waitAndGetAddBubbleBtn(): UiObject2? =
         device.wait(Until.findObject(By.text("Add Bubble")), FIND_OBJECT_TIMEOUT)
-    protected fun Flicker.waitAndGetCancelAllBtn(): UiObject2? =
+    protected fun IFlickerTestData.waitAndGetCancelAllBtn(): UiObject2? =
         device.wait(Until.findObject(By.text("Cancel All Bubble")), FIND_OBJECT_TIMEOUT)
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
 
         const val FIND_OBJECT_TIMEOUT = 2000L
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
index ab72117..7fc12f0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/DismissBubbleScreen.kt
@@ -25,9 +25,9 @@
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -45,7 +45,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class DismissBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class DismissBubbleScreen(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
 
     private val wm = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
     private val displaySize = DisplayMetrics()
@@ -72,7 +72,7 @@
     @Presubmit
     @Test
     open fun testAppIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 
     /** {@inheritDoc} */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
index 226eab8..0cda626 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/ExpandBubbleScreen.kt
@@ -20,9 +20,9 @@
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -42,7 +42,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class ExpandBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class ExpandBubbleScreen(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
@@ -64,6 +64,6 @@
     @Presubmit
     @Test
     open fun testAppIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
index 47167b8..04b1bdd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleFromLockScreen.kt
@@ -23,9 +23,9 @@
 import androidx.test.filters.RequiresDevice
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -43,7 +43,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-class LaunchBubbleFromLockScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+class LaunchBubbleFromLockScreen(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
@@ -88,7 +88,7 @@
     @FlakyTest(bugId = 242088970)
     @Test
     fun testAppIsVisibleAtEnd() {
-        testSpec.assertLayersEnd { this.isVisible(testApp) }
+        flicker.assertLayersEnd { this.isVisible(testApp) }
     }
 
     /** {@inheritDoc} */
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
index b865999..9b4e39c 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/LaunchBubbleScreen.kt
@@ -19,9 +19,9 @@
 import android.platform.test.annotations.RequiresDevice
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.Parameterized
@@ -40,7 +40,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class LaunchBubbleScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class LaunchBubbleScreen(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
@@ -59,6 +59,6 @@
 
     @Test
     open fun testAppIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
index bf4d7d4..b3a2ad3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreen.kt
@@ -22,10 +22,10 @@
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.Test
@@ -45,7 +45,7 @@
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-open class MultiBubblesScreen(testSpec: FlickerTestParameter) : BaseBubbleScreen(testSpec) {
+open class MultiBubblesScreen(flicker: FlickerTest) : BaseBubbleScreen(flicker) {
 
     @Before
     open fun before() {
@@ -87,6 +87,6 @@
     @Presubmit
     @Test
     open fun testAppIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt
index 57adeab..191f4fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/bubble/MultiBubblesScreenShellTransit.kt
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.runner.RunWith
@@ -30,8 +30,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FlakyTest(bugId = 217777115)
-class MultiBubblesScreenShellTransit(testSpec: FlickerTestParameter) :
-    MultiBubblesScreen(testSpec) {
+class MultiBubblesScreenShellTransit(flicker: FlickerTest) : MultiBubblesScreen(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 7546a55..5e898e8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -18,15 +18,15 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -59,7 +59,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @FlakyTest(bugId = 238367575)
-class AutoEnterPipOnGoToHomeTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
+class AutoEnterPipOnGoToHomeTest(flicker: FlickerTest) : EnterPipTest(flicker) {
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -73,7 +73,7 @@
                 // close gracefully so that onActivityUnpinned() can be called before force exit
                 pipApp.closePipWindow(wmHelper)
 
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
                 pipApp.exit(wmHelper)
             }
@@ -83,7 +83,7 @@
     @FlakyTest(bugId = 256863309)
     @Test
     override fun pipLayerReduces() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
@@ -96,8 +96,8 @@
     @Test
     fun pipLayerMovesTowardsRightBottomCorner() {
         // in gestural nav the swipe makes PiP first go upwards
-        Assume.assumeFalse(testSpec.isGesturalNavigation)
-        testSpec.assertLayers {
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             // Pip animates towards the right bottom corner, but because it is being resized at the
             // same time, it is possible it shrinks first quickly below the default position and get
@@ -112,7 +112,7 @@
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
-        Assume.assumeFalse(testSpec.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
         super.focusChanges()
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index c8aa6d2..79feeaa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -17,14 +17,14 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -56,7 +56,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipOnUserLeaveHintTest(testSpec: FlickerTestParameter) : EnterPipTest(testSpec) {
+class EnterPipOnUserLeaveHintTest(flicker: FlickerTest) : EnterPipTest(flicker) {
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -68,7 +68,7 @@
                 pipApp.enableEnterPipOnUserLeaveHint()
             }
             teardown {
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
                 pipApp.exit(wmHelper)
             }
@@ -78,10 +78,10 @@
     @Presubmit
     @Test
     override fun pipAppLayerAlwaysVisible() {
-        if (!testSpec.isGesturalNavigation) super.pipAppLayerAlwaysVisible()
+        if (!flicker.scenario.isGesturalNavigation) super.pipAppLayerAlwaysVisible()
         else {
             // pip layer in gesture nav will disappear during transition
-            testSpec.assertLayers {
+            flicker.assertLayers {
                 this.isVisible(pipApp).then().isInvisible(pipApp).then().isVisible(pipApp)
             }
         }
@@ -91,7 +91,7 @@
     @Test
     override fun pipLayerReduces() {
         // in gestural nav the pip enters through alpha animation
-        Assume.assumeFalse(testSpec.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
         super.pipLayerReduces()
     }
 
@@ -99,7 +99,7 @@
     @Test
     override fun focusChanges() {
         // in gestural nav the focus goes to different activity on swipe up
-        Assume.assumeFalse(testSpec.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
         super.focusChanges()
     }
 
@@ -112,11 +112,11 @@
     @Presubmit
     @Test
     override fun pipLayerRemainInsideVisibleBounds() {
-        if (!testSpec.isGesturalNavigation) super.pipLayerRemainInsideVisibleBounds()
+        if (!flicker.scenario.isGesturalNavigation) super.pipLayerRemainInsideVisibleBounds()
         else {
             // pip layer in gesture nav will disappear during transition
-            testSpec.assertLayersStart { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
-            testSpec.assertLayersEnd { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
+            flicker.assertLayersStart { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
+            flicker.assertLayersEnd { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 2b629e7..1a76142 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -17,16 +17,16 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,7 +57,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+open class EnterPipTest(flicker: FlickerTest) : PipTransition(flicker) {
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
@@ -68,7 +68,7 @@
                 pipApp.launchViaIntent(wmHelper)
             }
             teardown {
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
                 pipApp.exit(wmHelper)
             }
@@ -79,16 +79,14 @@
     @Presubmit
     @Test
     open fun pipAppWindowAlwaysVisible() {
-        testSpec.assertWm { this.isAppWindowVisible(pipApp) }
+        flicker.assertWm { this.isAppWindowVisible(pipApp) }
     }
 
-    /**
-     * Checks [pipApp] layer remains visible throughout the animation
-     */
+    /** Checks [pipApp] layer remains visible throughout the animation */
     @Presubmit
     @Test
     open fun pipAppLayerAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(pipApp) }
+        flicker.assertLayers { this.isVisible(pipApp) }
     }
 
     /**
@@ -98,7 +96,7 @@
     @Presubmit
     @Test
     fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -108,14 +106,14 @@
     @Presubmit
     @Test
     open fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /** Checks that the visible region of [pipApp] always reduces during the animation */
     @Presubmit
     @Test
     open fun pipLayerReduces() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
@@ -127,7 +125,7 @@
     @Presubmit
     @Test
     fun pipWindowBecomesPinned() {
-        testSpec.assertWm {
+        flicker.assertWm {
             invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp) }
                 .then()
                 .invoke("pipWindowIsPinned") { it.isPinned(pipApp) }
@@ -138,7 +136,7 @@
     @Presubmit
     @Test
     fun launcherLayerBecomesVisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             isInvisible(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isVisible(ComponentNameMatcher.LAUNCHER)
@@ -152,21 +150,22 @@
     @Presubmit
     @Test
     open fun focusChanges() {
-        testSpec.assertEventLog { this.focusChanges(pipApp.`package`, "NexusLauncherActivity") }
+        flicker.assertEventLog { this.focusChanges(pipApp.`package`, "NexusLauncherActivity") }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+         * and navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index b4594de..2b90243 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -19,22 +19,22 @@
 import android.app.Activity
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.entireScreenCovered
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.server.wm.flicker.testapp.ActivityOptions.Pip.ACTION_ENTER_PIP
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
 import org.junit.Assume
@@ -51,32 +51,31 @@
  * To run this test: `atest WMShellFlickerTests:EnterPipToOtherOrientationTest`
  *
  * Actions:
+ * ```
  *     Launch [testApp] on a fixed portrait orientation
  *     Launch [pipApp] on a fixed landscape orientation
  *     Broadcast action [ACTION_ENTER_PIP] to enter pip mode
- *
+ * ```
  * Notes:
+ * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
  *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
+ * ```
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterPipToOtherOrientationTest(
-    testSpec: FlickerTestParameter
-) : PipTransition(testSpec) {
+class EnterPipToOtherOrientationTest(flicker: FlickerTest) : PipTransition(flicker) {
     private val testApp = FixedOrientationAppHelper(instrumentation)
-    private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
-    private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+    private val startingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_90)
+    private val endingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_0)
 
-    /**
-     * Defines the transition used to run the test
-     */
+    /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             setup {
@@ -85,19 +84,18 @@
 
                 // Launch a portrait only app on the fullscreen stack
                 testApp.launchViaIntent(
-                    wmHelper, stringExtras = mapOf(
-                        EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString()
-                    )
+                    wmHelper,
+                    stringExtras = mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_PORTRAIT.toString())
                 )
                 // Launch the PiP activity fixed as landscape
                 pipApp.launchViaIntent(
-                    wmHelper, stringExtras = mapOf(
-                        EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()
-                    )
+                    wmHelper,
+                    stringExtras =
+                        mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
                 )
             }
             teardown {
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
                 pipApp.exit(wmHelper)
                 testApp.exit(wmHelper)
@@ -107,7 +105,8 @@
                 // in portrait
                 broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
                 // during rotation the status bar becomes invisible and reappears at the end
-                wmHelper.StateSyncBuilder()
+                wmHelper
+                    .StateSyncBuilder()
                     .withPipShown()
                     .withNavOrTaskBarVisible()
                     .withStatusBarVisible()
@@ -116,21 +115,21 @@
         }
 
     /**
-     * This test is not compatible with Tablets. When using [Activity.setRequestedOrientation]
-     * to fix a orientation, Tablets instead keep the same orientation and add letterboxes
+     * This test is not compatible with Tablets. When using [Activity.setRequestedOrientation] to
+     * fix a orientation, Tablets instead keep the same orientation and add letterboxes
      */
     @Before
     fun setup() {
-        Assume.assumeFalse(testSpec.isTablet)
+        Assume.assumeFalse(flicker.scenario.isTablet)
     }
 
     /**
-     * Checks that the [ComponentNameMatcher.NAV_BAR] has the correct position at
-     * the start and end of the transition
+     * Checks that the [ComponentNameMatcher.NAV_BAR] has the correct position at the start and end
+     * of the transition
      */
     @FlakyTest
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() = testSpec.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = flicker.navBarLayerPositionAtStartAndEnd()
 
     /**
      * Checks that all parts of the screen are covered at the start and end of the transition
@@ -139,7 +138,7 @@
      */
     @Presubmit
     @Test
-    fun entireScreenCoveredAtStartAndEnd() = testSpec.entireScreenCovered(allStates = false)
+    fun entireScreenCoveredAtStartAndEnd() = flicker.entireScreenCovered(allStates = false)
 
     @FlakyTest(bugId = 251219769)
     @Test
@@ -147,89 +146,65 @@
         super.entireScreenCovered()
     }
 
-    /**
-     * Checks [pipApp] window remains visible and on top throughout the transition
-     */
+    /** Checks [pipApp] window remains visible and on top throughout the transition */
     @Presubmit
     @Test
     fun pipAppWindowIsAlwaysOnTop() {
-        testSpec.assertWm {
-            isAppWindowOnTop(pipApp)
-        }
+        flicker.assertWm { isAppWindowOnTop(pipApp) }
     }
 
-    /**
-     * Checks that [testApp] window is not visible at the start
-     */
+    /** Checks that [testApp] window is not visible at the start */
     @Presubmit
     @Test
     fun testAppWindowInvisibleOnStart() {
-        testSpec.assertWmStart {
-            isAppWindowInvisible(testApp)
-        }
+        flicker.assertWmStart { isAppWindowInvisible(testApp) }
     }
 
-    /**
-     * Checks that [testApp] window is visible at the end
-     */
+    /** Checks that [testApp] window is visible at the end */
     @Presubmit
     @Test
     fun testAppWindowVisibleOnEnd() {
-        testSpec.assertWmEnd {
-            isAppWindowVisible(testApp)
-        }
+        flicker.assertWmEnd { isAppWindowVisible(testApp) }
     }
 
-    /**
-     * Checks that [testApp] layer is not visible at the start
-     */
+    /** Checks that [testApp] layer is not visible at the start */
     @Presubmit
     @Test
     fun testAppLayerInvisibleOnStart() {
-        testSpec.assertLayersStart {
-            isInvisible(testApp)
-        }
+        flicker.assertLayersStart { isInvisible(testApp) }
     }
 
-    /**
-     * Checks that [testApp] layer is visible at the end
-     */
+    /** Checks that [testApp] layer is visible at the end */
     @Presubmit
     @Test
     fun testAppLayerVisibleOnEnd() {
-        testSpec.assertLayersEnd {
-            isVisible(testApp)
-        }
+        flicker.assertLayersEnd { isVisible(testApp) }
     }
 
     /**
-     * Checks that the visible region of [pipApp] covers the full display area at the start of
-     * the transition
+     * Checks that the visible region of [pipApp] covers the full display area at the start of the
+     * transition
      */
     @Presubmit
     @Test
     fun pipAppLayerCoversFullScreenOnStart() {
-        testSpec.assertLayersStart {
-            visibleRegion(pipApp).coversExactly(startingBounds)
-        }
+        flicker.assertLayersStart { visibleRegion(pipApp).coversExactly(startingBounds) }
     }
 
     /**
-     * Checks that the visible region of [testApp] plus the visible region of [pipApp]
-     * cover the full display area at the end of the transition
+     * Checks that the visible region of [testApp] plus the visible region of [pipApp] cover the
+     * full display area at the end of the transition
      */
     @Presubmit
     @Test
     fun testAppPlusPipLayerCoversFullScreenOnEnd() {
-        testSpec.assertLayersEnd {
+        flicker.assertLayersEnd {
             val pipRegion = visibleRegion(pipApp).region
-            visibleRegion(testApp)
-                .plus(pipRegion)
-                .coversExactly(endingBounds)
+            visibleRegion(testApp).plus(pipRegion).coversExactly(endingBounds)
         }
     }
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @Presubmit
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
@@ -239,16 +214,15 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
index 1dc03b9..7466916 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import org.junit.Test
 
 /** Base class for pip expand tests */
-abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+abstract class ExitPipToAppTransition(flicker: FlickerTest) : PipTransition(flicker) {
     protected val testApp = SimpleAppHelper(instrumentation)
 
     /**
@@ -32,7 +32,7 @@
     @Presubmit
     @Test
     open fun pipAppWindowRemainInsideVisibleBounds() {
-        testSpec.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -42,7 +42,7 @@
     @Presubmit
     @Test
     open fun pipAppLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -52,7 +52,7 @@
     @Presubmit
     @Test
     open fun showBothAppWindowsThenHidePip() {
-        testSpec.assertWm {
+        flicker.assertWm {
             // when the activity is STOPPING, sometimes it becomes invisible in an entry before
             // the window, sometimes in the same entry. This occurs because we log 1x per frame
             // thus we ignore activity here
@@ -71,7 +71,7 @@
     @Presubmit
     @Test
     open fun showBothAppLayersThenHidePip() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             isVisible(testApp).isVisible(pipApp).then().isInvisible(testApp).isVisible(pipApp)
         }
     }
@@ -83,7 +83,7 @@
     @Presubmit
     @Test
     open fun testPlusPipAppsCoverFullScreenAtStart() {
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             val pipRegion = visibleRegion(pipApp).region
             visibleRegion(testApp).plus(pipRegion).coversExactly(displayBounds)
         }
@@ -96,14 +96,14 @@
     @Presubmit
     @Test
     open fun pipAppCoversFullScreenAtEnd() {
-        testSpec.assertLayersEnd { visibleRegion(pipApp).coversExactly(displayBounds) }
+        flicker.assertLayersEnd { visibleRegion(pipApp).coversExactly(displayBounds) }
     }
 
     /** Checks that the visible region of [pipApp] always expands during the animation */
     @Presubmit
     @Test
     open fun pipLayerExpands() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 3b8bb90..1b5c227 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -17,20 +17,20 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.LAUNCHER
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Test
 
 /** Base class for exiting pip (closing pip window) without returning to the app */
-abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+abstract class ExitPipTransition(flicker: FlickerTest) : PipTransition(flicker) {
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
-            setup { this.setRotation(testSpec.startRotation) }
-            teardown { this.setRotation(Surface.ROTATION_0) }
+            setup { this.setRotation(flicker.scenario.startRotation) }
+            teardown { this.setRotation(PlatformConsts.Rotation.ROTATION_0) }
         }
 
     /**
@@ -45,16 +45,16 @@
             // When Shell transition is enabled, we change the windowing mode at start, but
             // update the visibility after the transition is finished, so we can't check isNotPinned
             // and isAppWindowInvisible in the same assertion block.
-            testSpec.assertWm {
+            flicker.assertWm {
                 this.invoke("hasPipWindow") {
                         it.isPinned(pipApp).isAppWindowVisible(pipApp).isAppWindowOnTop(pipApp)
                     }
                     .then()
                     .invoke("!hasPipWindow") { it.isNotPinned(pipApp).isAppWindowNotOnTop(pipApp) }
             }
-            testSpec.assertWmEnd { isAppWindowInvisible(pipApp) }
+            flicker.assertWmEnd { isAppWindowInvisible(pipApp) }
         } else {
-            testSpec.assertWm {
+            flicker.assertWm {
                 this.invoke("hasPipWindow") { it.isPinned(pipApp).isAppWindowVisible(pipApp) }
                     .then()
                     .invoke("!hasPipWindow") { it.isNotPinned(pipApp).isAppWindowInvisible(pipApp) }
@@ -69,7 +69,7 @@
     @Presubmit
     @Test
     open fun pipLayerBecomesInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(pipApp)
                 .isVisible(LAUNCHER)
                 .then()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
index 6bf7e8c..1420f8ce 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -18,12 +18,12 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -36,30 +36,29 @@
  * To run this test: `atest WMShellFlickerTests:ExitPipViaExpandButtonClickTest`
  *
  * Actions:
+ * ```
  *     Launch an app in pip mode [pipApp],
  *     Launch another full screen mode [testApp]
  *     Expand [pipApp] app to full screen by clicking on the pip window and
  *     then on the expand button
- *
+ * ```
  * Notes:
+ * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
  *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
+ * ```
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipViaExpandButtonClickTest(
-    testSpec: FlickerTestParameter
-) : ExitPipToAppTransition(testSpec) {
+class ExitPipViaExpandButtonClickTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
 
-    /**
-     * Defines the transition used to run the test
-     */
+    /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             setup {
@@ -70,34 +69,29 @@
                 // This will bring PipApp to fullscreen
                 pipApp.expandPipWindowToApp(wmHelper)
                 // Wait until the other app is no longer visible
-                wmHelper.StateSyncBuilder()
-                    .withWindowSurfaceDisappeared(testApp)
-                    .waitForAndVerify()
+                wmHelper.StateSyncBuilder().withWindowSurfaceDisappeared(testApp).waitForAndVerify()
             }
         }
 
-    /** {@inheritDoc}  */
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    /** {@inheritDoc} */
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
-    /** {@inheritDoc}  */
-    @FlakyTest(bugId = 197726610)
-    @Test
-    override fun pipLayerExpands() = super.pipLayerExpands()
+    /** {@inheritDoc} */
+    @FlakyTest(bugId = 197726610) @Test override fun pipLayerExpands() = super.pipLayerExpands()
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
index 3356d3e..dffbe7e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -18,13 +18,13 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -57,7 +57,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransition(testSpec) {
+class ExitPipViaIntentTest(flicker: FlickerTest) : ExitPipToAppTransition(flicker) {
 
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
@@ -74,10 +74,8 @@
             }
         }
 
-    /** {@inheritDoc}  */
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    /** {@inheritDoc} */
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -113,14 +111,15 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+         * and navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
index d195abb..232c025 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,7 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
+class ExitPipWithDismissButtonTest(flicker: FlickerTest) : ExitPipTransition(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -69,21 +69,22 @@
     @Presubmit
     @Test
     fun focusChanges() {
-        testSpec.assertEventLog { this.focusChanges("PipMenuView", "NexusLauncherActivity") }
+        flicker.assertEventLog { this.focusChanges("PipMenuView", "NexusLauncherActivity") }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+         * and navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index f7a2447..dbbfdcc 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -54,7 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
+class ExitPipWithSwipeDownTest(flicker: FlickerTest) : ExitPipTransition(flicker) {
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
@@ -64,7 +64,7 @@
                 val pipCenterY = pipRegion.centerY()
                 val displayCenterX = device.displayWidth / 2
                 val barComponent =
-                    if (testSpec.isTablet) {
+                    if (flicker.scenario.isTablet) {
                         ComponentNameMatcher.TASK_BAR
                     } else {
                         ComponentNameMatcher.NAV_BAR
@@ -92,21 +92,22 @@
     @Presubmit
     @Test
     fun focusDoesNotChange() {
-        testSpec.assertEventLog { this.focusDoesNotChange() }
+        flicker.assertEventLog { this.focusDoesNotChange() }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+         * and navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
index fa5ce5b..f213cc9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -17,13 +17,13 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.FlakyTest
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -36,28 +36,27 @@
  * To run this test: `atest WMShellFlickerTests:ExpandPipOnDoubleClickTest`
  *
  * Actions:
+ * ```
  *     Launch an app in pip mode [pipApp],
  *     Expand [pipApp] app to its maximum pip size by double clicking on it
- *
+ * ```
  * Notes:
+ * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
  *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
+ * ```
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+class ExpandPipOnDoubleClickTest(flicker: FlickerTest) : PipTransition(flicker) {
     override val transition: FlickerBuilder.() -> Unit
-        get() = buildTransition {
-            transitions {
-                pipApp.doubleClickPipWindow(wmHelper)
-            }
-        }
+        get() = buildTransition { transitions { pipApp.doubleClickPipWindow(wmHelper) } }
 
     /**
      * Checks that the pip app window remains inside the display bounds throughout the whole
@@ -66,9 +65,7 @@
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWmVisibleRegion(pipApp) {
-            coversAtMost(displayBounds)
-        }
+        flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -78,40 +75,28 @@
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayersVisibleRegion(pipApp) {
-            coversAtMost(displayBounds)
-        }
+        flicker.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
-    /**
-     * Checks [pipApp] window remains visible throughout the animation
-     */
+    /** Checks [pipApp] window remains visible throughout the animation */
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipWindowIsAlwaysVisible() {
-        testSpec.assertWm {
-            isAppWindowVisible(pipApp)
-        }
+        flicker.assertWm { isAppWindowVisible(pipApp) }
     }
 
-    /**
-     * Checks [pipApp] layer remains visible throughout the animation
-     */
+    /** Checks [pipApp] layer remains visible throughout the animation */
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipLayerIsAlwaysVisible() {
-        testSpec.assertLayers {
-            isVisible(pipApp)
-        }
+        flicker.assertLayers { isVisible(pipApp) }
     }
 
-    /**
-     * Checks that the visible region of [pipApp] always expands during the animation
-     */
+    /** Checks that the visible region of [pipApp] always expands during the animation */
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipLayerExpands() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
@@ -122,7 +107,7 @@
     @FlakyTest(bugId = 249308003)
     @Test
     fun pipSameAspectRatio() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 current.visibleRegion.isSameAspectRatio(previous.visibleRegion)
@@ -130,37 +115,25 @@
         }
     }
 
-    /**
-     * Checks [pipApp] window remains pinned throughout the animation
-     */
+    /** Checks [pipApp] window remains pinned throughout the animation */
     @FlakyTest(bugId = 249308003)
     @Test
     fun windowIsAlwaysPinned() {
-        testSpec.assertWm {
-            this.invoke("hasPipWindow") { it.isPinned(pipApp) }
-        }
+        flicker.assertWm { this.invoke("hasPipWindow") { it.isPinned(pipApp) } }
     }
 
-    /**
-     * Checks [ComponentMatcher.LAUNCHER] layer remains visible throughout the animation
-     */
+    /** Checks [ComponentMatcher.LAUNCHER] layer remains visible throughout the animation */
     @FlakyTest(bugId = 249308003)
     @Test
     fun launcherIsAlwaysVisible() {
-        testSpec.assertLayers {
-            isVisible(ComponentNameMatcher.LAUNCHER)
-        }
+        flicker.assertLayers { isVisible(ComponentNameMatcher.LAUNCHER) }
     }
 
-    /**
-     * Checks that the focus doesn't change between windows during the transition
-     */
+    /** Checks that the focus doesn't change between windows during the transition */
     @FlakyTest(bugId = 216306753)
     @Test
     fun focusDoesNotChange() {
-        testSpec.assertEventLog {
-            this.focusDoesNotChange()
-        }
+        flicker.assertEventLog { this.focusDoesNotChange() }
     }
 
     @FlakyTest(bugId = 216306753)
@@ -233,16 +206,15 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
index bcd01a4..34f6659 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnPinchOpenTest.kt
@@ -17,40 +17,32 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Postsubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
 import org.junit.runners.Parameterized
 
-/**
- * Test expanding a pip window via pinch out gesture.
- */
+/** Test expanding a pip window via pinch out gesture. */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ExpandPipOnPinchOpenTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+class ExpandPipOnPinchOpenTest(flicker: FlickerTest) : PipTransition(flicker) {
     override val transition: FlickerBuilder.() -> Unit
-        get() = buildTransition {
-            transitions {
-                pipApp.pinchOpenPipWindow(wmHelper, 0.4f, 30)
-            }
-        }
+        get() = buildTransition { transitions { pipApp.pinchOpenPipWindow(wmHelper, 0.4f, 30) } }
 
-    /**
-     * Checks that the visible region area of [pipApp] always increases during the animation.
-     */
+    /** Checks that the visible region area of [pipApp] always increases during the animation. */
     @Postsubmit
     @Test
     fun pipLayerAreaIncreases() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
             pipLayerList.zipWithNext { previous, current ->
                 previous.visibleRegion.notBiggerThan(current.visibleRegion.region)
@@ -62,16 +54,15 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
index 0c0228e..e9847fa 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.Direction
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -36,71 +36,56 @@
  * To run this test: `atest WMShellFlickerTests:MovePipUpShelfHeightChangeTest`
  *
  * Actions:
+ * ```
  *     Launch [pipApp] in pip mode
  *     Press home
  *     Launch [testApp]
  *     Check if pip window moves down (visually)
- *
+ * ```
  * Notes:
+ * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
  *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
+ * ```
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class MovePipDownShelfHeightChangeTest(
-    testSpec: FlickerTestParameter
-) : MovePipShelfHeightTransition(testSpec) {
-//    @Before
-//    fun before() {
-//        Assume.assumeFalse(isShellTransitionsEnabled)
-//    }
-
-    /**
-     * Defines the transition used to run the test
-     */
+class MovePipDownShelfHeightChangeTest(flicker: FlickerTest) :
+    MovePipShelfHeightTransition(flicker) {
+    /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = buildTransition {
             teardown {
                 tapl.pressHome()
                 testApp.exit(wmHelper)
             }
-            transitions {
-                testApp.launchViaIntent(wmHelper)
-            }
+            transitions { testApp.launchViaIntent(wmHelper) }
         }
 
-    /**
-     * Checks that the visible region of [pipApp] window always moves down during the animation.
-     */
-    @Presubmit
-    @Test
-    fun pipWindowMovesDown() = pipWindowMoves(Direction.DOWN)
+    /** Checks that the visible region of [pipApp] window always moves down during the animation. */
+    @Presubmit @Test fun pipWindowMovesDown() = pipWindowMoves(Direction.DOWN)
 
-    /**
-     * Checks that the visible region of [pipApp] layer always moves down during the animation.
-     */
-    @Presubmit
-    @Test
-    fun pipLayerMovesDown() = pipLayerMoves(Direction.DOWN)
+    /** Checks that the visible region of [pipApp] layer always moves down during the animation. */
+    @Presubmit @Test fun pipLayerMovesDown() = pipLayerMoves(Direction.DOWN)
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0)
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
index b401067..35525cb 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -17,29 +17,28 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.FixedOrientationAppHelper
 import com.android.server.wm.flicker.traces.region.RegionSubject
 import com.android.wm.shell.flicker.Direction
 import org.junit.Test
 
 /** Base class for pip tests with Launcher shelf height change */
-abstract class MovePipShelfHeightTransition(testSpec: FlickerTestParameter) :
-    PipTransition(testSpec) {
+abstract class MovePipShelfHeightTransition(flicker: FlickerTest) : PipTransition(flicker) {
     protected val testApp = FixedOrientationAppHelper(instrumentation)
 
     /** Checks [pipApp] window remains visible throughout the animation */
     @Presubmit
     @Test
     open fun pipWindowIsAlwaysVisible() {
-        testSpec.assertWm { isAppWindowVisible(pipApp) }
+        flicker.assertWm { isAppWindowVisible(pipApp) }
     }
 
     /** Checks [pipApp] layer remains visible throughout the animation */
     @Presubmit
     @Test
     open fun pipLayerIsAlwaysVisible() {
-        testSpec.assertLayers { isVisible(pipApp) }
+        flicker.assertLayers { isVisible(pipApp) }
     }
 
     /**
@@ -49,7 +48,7 @@
     @Presubmit
     @Test
     open fun pipWindowRemainInsideVisibleBounds() {
-        testSpec.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertWmVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -59,7 +58,7 @@
     @Presubmit
     @Test
     open fun pipLayerRemainInsideVisibleBounds() {
-        testSpec.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
+        flicker.assertLayersVisibleRegion(pipApp) { coversAtMost(displayBounds) }
     }
 
     /**
@@ -67,7 +66,7 @@
      * during the animation.
      */
     protected fun pipWindowMoves(direction: Direction) {
-        testSpec.assertWm {
+        flicker.assertWm {
             val pipWindowFrameList =
                 this.windowStates { pipApp.windowMatchesAnyOf(it) && it.isVisible }.map { it.frame }
             when (direction) {
@@ -83,7 +82,7 @@
      * during the animation.
      */
     protected fun pipLayerMoves(direction: Direction) {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             val pipLayerRegionList =
                 this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
                     .map { it.visibleRegion }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
index 7f8ef32..3a12a34 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.Direction
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -36,68 +36,55 @@
  * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
  *
  * Actions:
+ * ```
  *     Launch [pipApp] in pip mode
  *     Launch [testApp]
  *     Press home
  *     Check if pip window moves up (visually)
- *
+ * ```
  * Notes:
+ * ```
  *     1. Some default assertions (e.g., nav bar, status bar and screen covered)
  *        are inherited [PipTransition]
  *     2. Part of the test setup occurs automatically via
  *        [com.android.server.wm.flicker.TransitionRunnerWithRules],
  *        including configuring navigation mode, initial orientation and ensuring no
  *        apps are running before setup
+ * ```
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class MovePipUpShelfHeightChangeTest(
-    testSpec: FlickerTestParameter
-) : MovePipShelfHeightTransition(testSpec) {
-    /**
-     * Defines the transition used to run the test
-     */
+open class MovePipUpShelfHeightChangeTest(flicker: FlickerTest) :
+    MovePipShelfHeightTransition(flicker) {
+    /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
-        get() = buildTransition() {
-            setup {
-                testApp.launchViaIntent(wmHelper)
+        get() =
+            buildTransition() {
+                setup { testApp.launchViaIntent(wmHelper) }
+                transitions { tapl.pressHome() }
+                teardown { testApp.exit(wmHelper) }
             }
-            transitions {
-                tapl.pressHome()
-            }
-            teardown {
-                testApp.exit(wmHelper)
-            }
-        }
 
-    /**
-     * Checks that the visible region of [pipApp] window always moves up during the animation.
-     */
-    @Presubmit
-    @Test
-    fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
+    /** Checks that the visible region of [pipApp] window always moves up during the animation. */
+    @Presubmit @Test fun pipWindowMovesUp() = pipWindowMoves(Direction.UP)
 
-    /**
-     * Checks that the visible region of [pipApp] layer always moves up during the animation.
-     */
-    @Presubmit
-    @Test
-    fun pipLayerMovesUp() = pipLayerMoves(Direction.UP)
+    /** Checks that the visible region of [pipApp] layer always moves up during the animation. */
+    @Presubmit @Test fun pipLayerMovesUp() = pipLayerMoves(Direction.UP)
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
-         * repetitions, screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedRotations = listOf(Surface.ROTATION_0)
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
index 3b64d21..12d6362 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTest.kt
@@ -17,17 +17,17 @@
 package com.android.wm.shell.flicker.pip
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume.assumeFalse
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -41,7 +41,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class PipKeyboardTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+open class PipKeyboardTest(flicker: FlickerTest) : PipTransition(flicker) {
     private val imeApp = ImeAppHelper(instrumentation)
 
     @Before
@@ -54,11 +54,11 @@
         get() = buildTransition {
             setup {
                 imeApp.launchViaIntent(wmHelper)
-                setRotation(testSpec.startRotation)
+                setRotation(flicker.scenario.startRotation)
             }
             teardown {
                 imeApp.exit(wmHelper)
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
             }
             transitions {
                 // open the soft keyboard
@@ -74,8 +74,8 @@
     @Presubmit
     @Test
     open fun pipInVisibleBounds() {
-        testSpec.assertWmVisibleRegion(pipApp) {
-            val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+        flicker.assertWmVisibleRegion(pipApp) {
+            val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
             coversAtMost(displayBounds)
         }
     }
@@ -84,7 +84,7 @@
     @Presubmit
     @Test
     open fun pipIsAboveAppWindow() {
-        testSpec.assertWmTag(TAG_IME_VISIBLE) { isAboveWindow(ComponentNameMatcher.IME, pipApp) }
+        flicker.assertWmTag(TAG_IME_VISIBLE) { isAboveWindow(ComponentNameMatcher.IME, pipApp) }
     }
 
     companion object {
@@ -92,9 +92,10 @@
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
index 2a82c00..901814e 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipKeyboardTestShellTransit.kt
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -33,7 +33,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class PipKeyboardTestShellTransit(testSpec: FlickerTestParameter) : PipKeyboardTest(testSpec) {
+class PipKeyboardTestShellTransit(flicker: FlickerTest) : PipKeyboardTest(flicker) {
 
     @Before
     override fun before() {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 7de5494..eee00bd 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -18,16 +18,15 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -45,7 +44,7 @@
  * ```
  *     Launch a [pipApp] in pip mode
  *     Launch another app [fixedApp] (appears below pip)
- *     Rotate the screen from [testSpec.startRotation] to [testSpec.endRotation]
+ *     Rotate the screen from [flicker.scenario.startRotation] to [flicker.scenario.endRotation]
  *     (usually, 0->90 and 90->0)
  * ```
  * Notes:
@@ -62,10 +61,10 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+open class PipRotationTest(flicker: FlickerTest) : PipTransition(flicker) {
     private val testApp = SimpleAppHelper(instrumentation)
-    private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.startRotation)
-    private val screenBoundsEnd = WindowUtils.getDisplayBounds(testSpec.endRotation)
+    private val screenBoundsStart = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
+    private val screenBoundsEnd = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
 
     @Before
     open fun before() {
@@ -76,9 +75,9 @@
         get() = buildTransition {
             setup {
                 testApp.launchViaIntent(wmHelper)
-                setRotation(testSpec.startRotation)
+                setRotation(flicker.scenario.startRotation)
             }
-            transitions { setRotation(testSpec.endRotation) }
+            transitions { setRotation(flicker.scenario.endRotation) }
         }
 
     /** Checks the position of the navigation bar at the start and end of the transition */
@@ -90,14 +89,14 @@
     @Presubmit
     @Test
     fun fixedAppLayer_StartingBounds() {
-        testSpec.assertLayersStart { visibleRegion(testApp).coversAtMost(screenBoundsStart) }
+        flicker.assertLayersStart { visibleRegion(testApp).coversAtMost(screenBoundsStart) }
     }
 
     /** Checks that [testApp] layer is within [screenBoundsEnd] at the end of the transition */
     @Presubmit
     @Test
     fun fixedAppLayer_EndingBounds() {
-        testSpec.assertLayersEnd { visibleRegion(testApp).coversAtMost(screenBoundsEnd) }
+        flicker.assertLayersEnd { visibleRegion(testApp).coversAtMost(screenBoundsEnd) }
     }
 
     /**
@@ -107,7 +106,7 @@
     @Presubmit
     @Test
     fun appLayers_StartingBounds() {
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             visibleRegion(testApp.or(pipApp)).coversExactly(screenBoundsStart)
         }
     }
@@ -119,14 +118,12 @@
     @Presubmit
     @Test
     fun appLayers_EndingBounds() {
-        testSpec.assertLayersEnd {
-            visibleRegion(testApp.or(pipApp)).coversExactly(screenBoundsEnd)
-        }
+        flicker.assertLayersEnd { visibleRegion(testApp.or(pipApp)).coversExactly(screenBoundsEnd) }
     }
 
     /** Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition */
     private fun pipLayerRotates_StartingBounds_internal() {
-        testSpec.assertLayersStart { visibleRegion(pipApp).coversAtMost(screenBoundsStart) }
+        flicker.assertLayersStart { visibleRegion(pipApp).coversAtMost(screenBoundsStart) }
     }
 
     /** Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition */
@@ -140,7 +137,7 @@
     @Presubmit
     @Test
     fun pipLayerRotates_EndingBounds() {
-        testSpec.assertLayersEnd { visibleRegion(pipApp).coversAtMost(screenBoundsEnd) }
+        flicker.assertLayersEnd { visibleRegion(pipApp).coversAtMost(screenBoundsEnd) }
     }
 
     /**
@@ -149,7 +146,7 @@
     @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_Start() {
-        testSpec.assertWmStart { isAboveWindow(pipApp, testApp) }
+        flicker.assertWmStart { isAboveWindow(pipApp, testApp) }
     }
 
     /**
@@ -158,7 +155,7 @@
     @Presubmit
     @Test
     fun pipIsAboveFixedAppWindow_End() {
-        testSpec.assertWmEnd { isAboveWindow(pipApp, testApp) }
+        flicker.assertWmEnd { isAboveWindow(pipApp, testApp) }
     }
 
     @Presubmit
@@ -171,16 +168,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring repetitions, screen orientation
+         * and navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.rotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
index 983cb1c..d0d9167 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest_ShellTransit.kt
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -38,7 +38,7 @@
  * ```
  *     Launch a [pipApp] in pip mode
  *     Launch another app [fixedApp] (appears below pip)
- *     Rotate the screen from [testSpec.startRotation] to [testSpec.endRotation]
+ *     Rotate the screen from [flicker.scenario.startRotation] to [flicker.scenario.endRotation]
  *     (usually, 0->90 and 90->0)
  * ```
  * Notes:
@@ -56,7 +56,7 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @FlakyTest(bugId = 239575053)
-class PipRotationTest_ShellTransit(testSpec: FlickerTestParameter) : PipRotationTest(testSpec) {
+class PipRotationTest_ShellTransit(flicker: FlickerTest) : PipRotationTest(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index dfa2510..0e0be79 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -18,19 +18,19 @@
 
 import android.app.Instrumentation
 import android.content.Intent
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.PipAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.BaseTest
 
-abstract class PipTransition(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class PipTransition(flicker: FlickerTest) : BaseTest(flicker) {
     protected val pipApp = PipAppHelper(instrumentation)
-    protected val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+    protected val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
     protected val broadcastActionTrigger = BroadcastActionTrigger(instrumentation)
 
     // Helper class to process test actions by broadcast.
@@ -67,12 +67,12 @@
     ): FlickerBuilder.() -> Unit {
         return {
             setup {
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 removeAllTasksButHome()
                 pipApp.launchViaIntentAndWaitForPip(wmHelper, stringExtras = stringExtras)
             }
             teardown {
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 removeAllTasksButHome()
                 pipApp.exit(wmHelper)
             }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index f0093e6..157aa98 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -20,19 +20,19 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.WindowUtils
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.flicker.testapp.ActivityOptions.PortraitOnlyActivity.EXTRA_FIXED_ORIENTATION
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
 import org.junit.Assume
 import org.junit.Before
@@ -43,20 +43,18 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test exiting Pip with orientation changes.
- * To run this test: `atest WMShellFlickerTests:SetRequestedOrientationWhilePinnedTest`
+ * Test exiting Pip with orientation changes. To run this test: `atest
+ * WMShellFlickerTests:SetRequestedOrientationWhilePinnedTest`
  */
 @RequiresDevice
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SetRequestedOrientationWhilePinnedTest(
-    testSpec: FlickerTestParameter
-) : PipTransition(testSpec) {
-    private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
-    private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
+open class SetRequestedOrientationWhilePinnedTest(flicker: FlickerTest) : PipTransition(flicker) {
+    private val startingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_0)
+    private val endingBounds = WindowUtils.getDisplayBounds(PlatformConsts.Rotation.ROTATION_90)
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             setup {
@@ -64,30 +62,35 @@
                 device.wakeUpAndGoToHomeScreen()
 
                 // Launch the PiP activity fixed as landscape.
-                pipApp.launchViaIntent(wmHelper, stringExtras = mapOf(
-                    EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString()))
+                pipApp.launchViaIntent(
+                    wmHelper,
+                    stringExtras =
+                        mapOf(EXTRA_FIXED_ORIENTATION to ORIENTATION_LANDSCAPE.toString())
+                )
                 // Enter PiP.
                 broadcastActionTrigger.doAction(ActivityOptions.Pip.ACTION_ENTER_PIP)
                 // System bar may fade out during fixed rotation.
-                wmHelper.StateSyncBuilder()
+                wmHelper
+                    .StateSyncBuilder()
                     .withPipShown()
-                    .withRotation(Surface.ROTATION_0)
+                    .withRotation(PlatformConsts.Rotation.ROTATION_0)
                     .withNavOrTaskBarVisible()
                     .withStatusBarVisible()
                     .waitForAndVerify()
             }
             teardown {
                 pipApp.exit(wmHelper)
-                setRotation(Surface.ROTATION_0)
+                setRotation(PlatformConsts.Rotation.ROTATION_0)
                 removeAllTasksButHome()
             }
             transitions {
                 // Launch the activity back into fullscreen and ensure that it is now in landscape
                 pipApp.launchViaIntent(wmHelper)
                 // System bar may fade out during fixed rotation.
-                wmHelper.StateSyncBuilder()
+                wmHelper
+                    .StateSyncBuilder()
                     .withFullScreenApp(pipApp)
-                    .withRotation(Surface.ROTATION_90)
+                    .withRotation(PlatformConsts.Rotation.ROTATION_90)
                     .withNavOrTaskBarVisible()
                     .withStatusBarVisible()
                     .waitForAndVerify()
@@ -95,34 +98,32 @@
         }
 
     /**
-     * This test is not compatible with Tablets. When using [Activity.setRequestedOrientation]
-     * to fix a orientation, Tablets instead keep the same orientation and add letterboxes
+     * This test is not compatible with Tablets. When using [Activity.setRequestedOrientation] to
+     * fix a orientation, Tablets instead keep the same orientation and add letterboxes
      */
     @Before
     fun setup() {
-        Assume.assumeFalse(testSpec.isTablet)
+        Assume.assumeFalse(flicker.scenario.isTablet)
     }
 
     @Presubmit
     @Test
     fun displayEndsAt90Degrees() {
-        testSpec.assertWmEnd {
-            hasRotation(Surface.ROTATION_90)
-        }
+        flicker.assertWmEnd { hasRotation(PlatformConsts.Rotation.ROTATION_90) }
     }
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @Presubmit
     @Test
     override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @Presubmit
     @Test
     override fun statusBarLayerIsVisibleAtStartAndEnd() =
         super.statusBarLayerIsVisibleAtStartAndEnd()
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @FlakyTest
     @Test
     override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
@@ -130,23 +131,17 @@
     @Presubmit
     @Test
     fun pipWindowInsideDisplay() {
-        testSpec.assertWmStart {
-            visibleRegion(pipApp).coversAtMost(startingBounds)
-        }
+        flicker.assertWmStart { visibleRegion(pipApp).coversAtMost(startingBounds) }
     }
 
     @Presubmit
     @Test
     fun pipAppShowsOnTop() {
-        testSpec.assertWmEnd {
-            isAppWindowOnTop(pipApp)
-        }
+        flicker.assertWmEnd { isAppWindowOnTop(pipApp) }
     }
 
     private fun pipLayerInsideDisplay_internal() {
-        testSpec.assertLayersStart {
-            visibleRegion(pipApp).coversAtMost(startingBounds)
-        }
+        flicker.assertLayersStart { visibleRegion(pipApp).coversAtMost(startingBounds) }
     }
 
     @Presubmit
@@ -166,40 +161,35 @@
     @Presubmit
     @Test
     fun pipAlwaysVisible() {
-        testSpec.assertWm {
-            this.isAppWindowVisible(pipApp)
-        }
+        flicker.assertWm { this.isAppWindowVisible(pipApp) }
     }
 
     @Presubmit
     @Test
     fun pipAppLayerCoversFullScreen() {
-        testSpec.assertLayersEnd {
-            visibleRegion(pipApp).coversExactly(endingBounds)
-        }
+        flicker.assertLayersEnd { visibleRegion(pipApp).coversExactly(endingBounds) }
     }
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @Postsubmit
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
-    /** {@inheritDoc}  */
+    /** {@inheritDoc} */
     @Postsubmit
     @Test
     override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
-    /** {@inheritDoc}  */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt
index 2cb18f9..a16f5f6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/tv/PipTestBase.kt
@@ -24,7 +24,10 @@
 import org.junit.Before
 import org.junit.runners.Parameterized
 
-abstract class PipTestBase(protected val rotationName: String, protected val rotation: Int) {
+abstract class PipTestBase(
+    protected val rotationName: String,
+    protected val rotation: Int
+) {
     val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     val uiDevice = UiDevice.getInstance(instrumentation)
     val packageManager: PackageManager = instrumentation.context.packageManager
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
index 9533b91..65cbea0 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/CopyContentInSplit.kt
@@ -20,10 +20,10 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.EdgeExtensionComponentMatcher
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
@@ -49,7 +49,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CopyContentInSplit(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class CopyContentInSplit(flicker: FlickerTest) : SplitScreenBase(flicker) {
     private val textEditApp = SplitScreenUtils.getIme(instrumentation)
     private val MagnifierLayer = ComponentNameMatcher("", "magnifier surface bbq wrapper#")
     private val PopupWindowLayer = ComponentNameMatcher("", "PopupWindow:")
@@ -72,29 +72,29 @@
     @Presubmit
     @Test
     fun cujCompleted() {
-        testSpec.appWindowIsVisibleAtStart(primaryApp)
-        testSpec.appWindowIsVisibleAtStart(textEditApp)
-        testSpec.splitScreenDividerIsVisibleAtStart()
+        flicker.appWindowIsVisibleAtStart(primaryApp)
+        flicker.appWindowIsVisibleAtStart(textEditApp)
+        flicker.splitScreenDividerIsVisibleAtStart()
 
-        testSpec.appWindowIsVisibleAtEnd(primaryApp)
-        testSpec.appWindowIsVisibleAtEnd(textEditApp)
-        testSpec.splitScreenDividerIsVisibleAtEnd()
+        flicker.appWindowIsVisibleAtEnd(primaryApp)
+        flicker.appWindowIsVisibleAtEnd(textEditApp)
+        flicker.splitScreenDividerIsVisibleAtEnd()
 
         // The validation of copied text is already done in SplitScreenUtils.copyContentInSplit()
     }
 
     @Presubmit
     @Test
-    fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+    fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 
-    @Presubmit @Test fun primaryAppLayerKeepVisible() = testSpec.layerKeepVisible(primaryApp)
+    @Presubmit @Test fun primaryAppLayerKeepVisible() = flicker.layerKeepVisible(primaryApp)
 
-    @Presubmit @Test fun textEditAppLayerKeepVisible() = testSpec.layerKeepVisible(textEditApp)
+    @Presubmit @Test fun textEditAppLayerKeepVisible() = flicker.layerKeepVisible(textEditApp)
 
     @Presubmit
     @Test
     fun primaryAppBoundsKeepVisible() =
-        testSpec.splitAppLayerBoundsKeepVisible(
+        flicker.splitAppLayerBoundsKeepVisible(
             primaryApp,
             landscapePosLeft = tapl.isTablet,
             portraitPosTop = false
@@ -103,21 +103,18 @@
     @Presubmit
     @Test
     fun textEditAppBoundsKeepVisible() =
-        testSpec.splitAppLayerBoundsKeepVisible(
+        flicker.splitAppLayerBoundsKeepVisible(
             textEditApp,
             landscapePosLeft = !tapl.isTablet,
             portraitPosTop = true
         )
 
-    @Presubmit @Test fun primaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(primaryApp)
+    @Presubmit @Test fun primaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(primaryApp)
 
-    @Presubmit @Test fun textEditAppWindowKeepVisible() = testSpec.appWindowKeepVisible(textEditApp)
+    @Presubmit @Test fun textEditAppWindowKeepVisible() = flicker.appWindowKeepVisible(textEditApp)
 
     /** {@inheritDoc} */
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -164,15 +161,18 @@
     @Presubmit
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
-                ignoreLayers = listOf(
-                    ComponentNameMatcher.SPLASH_SCREEN,
-                    ComponentNameMatcher.SNAPSHOT,
-                    ComponentNameMatcher.IME_SNAPSHOT,
-                    EdgeExtensionComponentMatcher(),
-                    MagnifierLayer,
-                    PopupWindowLayer))
+                ignoreLayers =
+                    listOf(
+                        ComponentNameMatcher.SPLASH_SCREEN,
+                        ComponentNameMatcher.SNAPSHOT,
+                        ComponentNameMatcher.IME_SNAPSHOT,
+                        EdgeExtensionComponentMatcher(),
+                        MagnifierLayer,
+                        PopupWindowLayer
+                    )
+            )
         }
     }
 
@@ -185,9 +185,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
index 4757498..d0f02e2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByDivider.kt
@@ -21,11 +21,11 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesInvisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -49,54 +49,62 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByDivider (testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class DismissSplitScreenByDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
-            setup {
-                SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-            }
+            setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
             transitions {
                 if (tapl.isTablet) {
-                    SplitScreenUtils.dragDividerToDismissSplit(device, wmHelper,
-                        dragToRight = false, dragToBottom = true)
+                    SplitScreenUtils.dragDividerToDismissSplit(
+                        device,
+                        wmHelper,
+                        dragToRight = false,
+                        dragToBottom = true
+                    )
                 } else {
-                    SplitScreenUtils.dragDividerToDismissSplit(device, wmHelper,
-                        dragToRight = true, dragToBottom = true)
+                    SplitScreenUtils.dragDividerToDismissSplit(
+                        device,
+                        wmHelper,
+                        dragToRight = true,
+                        dragToBottom = true
+                    )
                 }
-                wmHelper.StateSyncBuilder()
-                    .withFullScreenApp(secondaryApp)
-                    .waitForAndVerify()
+                wmHelper.StateSyncBuilder().withFullScreenApp(secondaryApp).waitForAndVerify()
             }
         }
 
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
+    fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = false)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesInvisible() = testSpec.splitScreenDividerBecomesInvisible()
+    fun splitScreenDividerBecomesInvisible() = flicker.splitScreenDividerBecomesInvisible()
 
     @Presubmit
     @Test
-    fun primaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
+    fun primaryAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(secondaryApp)
+    fun secondaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(secondaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
-        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+    fun primaryAppBoundsBecomesInvisible() =
+        flicker.splitAppLayerBoundsBecomesInvisible(
+            primaryApp,
+            landscapePosLeft = tapl.isTablet,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
     fun secondaryAppBoundsIsFullscreenAtEnd() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(secondaryApp)
                 .isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
                 .then()
@@ -109,7 +117,7 @@
                 .contains(SPLIT_SCREEN_DIVIDER_COMPONENT)
                 .then()
                 .invoke("secondaryAppBoundsIsFullscreenAtEnd") {
-                    val displayBounds = WindowUtils.getDisplayBounds(testSpec.endRotation)
+                    val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.endRotation)
                     it.visibleRegion(secondaryApp).coversExactly(displayBounds)
                 }
         }
@@ -117,35 +125,29 @@
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(primaryApp)
+    fun primaryAppWindowBecomesInvisible() = flicker.appWindowBecomesInvisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
+    fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
+
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 206753786)
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -156,26 +158,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -192,8 +190,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
index 1d61955..b44b681 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DismissSplitScreenByGoHome.kt
@@ -20,10 +20,10 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.wm.shell.flicker.appWindowBecomesInvisible
 import com.android.wm.shell.flicker.layerBecomesInvisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsBecomesInvisible
@@ -44,89 +44,81 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DismissSplitScreenByGoHome(
-    testSpec: FlickerTestParameter
-) : SplitScreenBase(testSpec) {
+class DismissSplitScreenByGoHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
-            setup {
-                SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-            }
+            setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
             transitions {
                 tapl.goHome()
-                wmHelper.StateSyncBuilder()
-                    .withHomeActivityVisible()
-                    .waitForAndVerify()
+                wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
             }
         }
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
+    fun cujCompleted() = flicker.splitScreenDismissed(primaryApp, secondaryApp, toHome = true)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesInvisible() = testSpec.splitScreenDividerBecomesInvisible()
+    fun splitScreenDividerBecomesInvisible() = flicker.splitScreenDividerBecomesInvisible()
 
     @FlakyTest(bugId = 241525302)
     @Test
-    fun primaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
+    fun primaryAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(primaryApp)
 
     // TODO(b/245472831): Move back to presubmit after shell transitions landing.
     @FlakyTest(bugId = 245472831)
     @Test
-    fun secondaryAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(primaryApp)
+    fun secondaryAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(primaryApp)
 
     // TODO(b/245472831): Move back to presubmit after shell transitions landing.
     @FlakyTest(bugId = 245472831)
     @Test
-    fun primaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
-        primaryApp,
-        landscapePosLeft = tapl.isTablet,
-        portraitPosTop = false
-    )
+    fun primaryAppBoundsBecomesInvisible() =
+        flicker.splitAppLayerBoundsBecomesInvisible(
+            primaryApp,
+            landscapePosLeft = tapl.isTablet,
+            portraitPosTop = false
+        )
 
     @FlakyTest(bugId = 250530241)
     @Test
-    fun secondaryAppBoundsBecomesInvisible() = testSpec.splitAppLayerBoundsBecomesInvisible(
-        secondaryApp,
-        landscapePosLeft = !tapl.isTablet,
-        portraitPosTop = true
-    )
+    fun secondaryAppBoundsBecomesInvisible() =
+        flicker.splitAppLayerBoundsBecomesInvisible(
+            secondaryApp,
+            landscapePosLeft = !tapl.isTablet,
+            portraitPosTop = true
+        )
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(primaryApp)
+    fun primaryAppWindowBecomesInvisible() = flicker.appWindowBecomesInvisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesInvisible() = testSpec.appWindowBecomesInvisible(secondaryApp)
+    fun secondaryAppWindowBecomesInvisible() = flicker.appWindowBecomesInvisible(secondaryApp)
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 251268711)
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 206753786)
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -137,26 +129,22 @@
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @FlakyTest
@@ -173,8 +161,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
index 8d771fe..5b656b3 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/DragDividerToResize.kt
@@ -21,10 +21,10 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
@@ -50,35 +50,31 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class DragDividerToResize(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class DragDividerToResize(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
-            setup {
-                SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-            }
-            transitions {
-                SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper)
-            }
+            setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
+            transitions { SplitScreenUtils.dragDividerToResizeAndWait(device, wmHelper) }
         }
 
     @Before
     fun before() {
-        Assume.assumeTrue(tapl.isTablet || !testSpec.isLandscapeOrSeascapeAtStart)
+        Assume.assumeTrue(tapl.isTablet || !flicker.scenario.isLandscapeOrSeascapeAtStart)
     }
 
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
     fun cujCompleted() {
-        testSpec.appWindowIsVisibleAtStart(primaryApp)
-        testSpec.appWindowIsVisibleAtStart(secondaryApp)
-        testSpec.splitScreenDividerIsVisibleAtStart()
+        flicker.appWindowIsVisibleAtStart(primaryApp)
+        flicker.appWindowIsVisibleAtStart(secondaryApp)
+        flicker.splitScreenDividerIsVisibleAtStart()
 
-        testSpec.appWindowIsVisibleAtEnd(primaryApp)
-        testSpec.appWindowIsVisibleAtEnd(secondaryApp)
-        testSpec.splitScreenDividerIsVisibleAtEnd()
+        flicker.appWindowIsVisibleAtEnd(primaryApp)
+        flicker.appWindowIsVisibleAtEnd(secondaryApp)
+        flicker.splitScreenDividerIsVisibleAtEnd()
 
         // TODO(b/246490534): Add validation for resized app after withAppTransitionIdle is
         // robust enough to get the correct end state.
@@ -86,16 +82,14 @@
 
     @Presubmit
     @Test
-    fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+    fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
 
-    @Presubmit
-    @Test
-    fun primaryAppLayerKeepVisible() = testSpec.layerKeepVisible(primaryApp)
+    @Presubmit @Test fun primaryAppLayerKeepVisible() = flicker.layerKeepVisible(primaryApp)
 
     @Presubmit
     @Test
     fun secondaryAppLayerVisibilityChanges() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(secondaryApp)
                 .then()
                 .isInvisible(secondaryApp)
@@ -104,53 +98,47 @@
         }
     }
 
-    @Presubmit
-    @Test
-    fun primaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(primaryApp)
+    @Presubmit @Test fun primaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowKeepVisible() = testSpec.appWindowKeepVisible(secondaryApp)
+    fun secondaryAppWindowKeepVisible() = flicker.appWindowKeepVisible(secondaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppBoundsChanges() = testSpec.splitAppLayerBoundsChanges(
-        primaryApp,
-        landscapePosLeft = true,
-        portraitPosTop = false
-    )
+    fun primaryAppBoundsChanges() =
+        flicker.splitAppLayerBoundsChanges(
+            primaryApp,
+            landscapePosLeft = true,
+            portraitPosTop = false
+        )
 
     @FlakyTest(bugId = 250530664)
     @Test
-    fun secondaryAppBoundsChanges() = testSpec.splitAppLayerBoundsChanges(
-        secondaryApp,
-        landscapePosLeft = false,
-        portraitPosTop = true
-    )
+    fun secondaryAppBoundsChanges() =
+        flicker.splitAppLayerBoundsChanges(
+            secondaryApp,
+            landscapePosLeft = false,
+            portraitPosTop = true
+        )
+
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -161,26 +149,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -197,8 +181,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
index 7378e21..4e36c36 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromAllApps.kt
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -44,8 +44,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test enter split screen by dragging app icon from all apps.
- * This test is only for large screen devices.
+ * Test enter split screen by dragging app icon from all apps. This test is only for large screen
+ * devices.
  *
  * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromAllApps`
  */
@@ -53,9 +53,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromAllApps(
-    testSpec: FlickerTestParameter
-) : SplitScreenBase(testSpec) {
+class EnterSplitScreenByDragFromAllApps(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     @Before
     fun before() {
@@ -71,9 +69,9 @@
             }
             transitions {
                 tapl.launchedAppState.taskbar
-                        .openAllApps()
-                        .getAppIcon(secondaryApp.appName)
-                        .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
+                    .openAllApps()
+                    .getAppIcon(secondaryApp.appName)
+                    .dragToSplitscreen(secondaryApp.`package`, primaryApp.`package`)
                 SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, secondaryApp)
             }
         }
@@ -81,13 +79,13 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
 
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.splitScreenDividerBecomesVisible()
+        flicker.splitScreenDividerBecomesVisible()
     }
 
     // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
@@ -95,60 +93,54 @@
     @Test
     fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.assertLayersEnd {
-            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
-        }
+        flicker.assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
     }
 
-    @Presubmit
-    @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp, landscapePosLeft = false, portraitPosTop = false)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = false,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
-        secondaryApp)
+    fun secondaryAppBoundsBecomesVisible() =
+        flicker.splitAppLayerBoundsBecomesVisibleByDrag(secondaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+    fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
+
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -159,26 +151,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -195,11 +183,11 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes =
-                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
index 0c03d31..5d37e85 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromNotification.kt
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.layerBecomesVisible
@@ -43,8 +43,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test enter split screen by dragging app icon from notification.
- * This test is only for large screen devices.
+ * Test enter split screen by dragging app icon from notification. This test is only for large
+ * screen devices.
  *
  * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromNotification`
  */
@@ -52,9 +52,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromNotification(
-    testSpec: FlickerTestParameter
-) : SplitScreenBase(testSpec) {
+class EnterSplitScreenByDragFromNotification(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     private val sendNotificationApp = SplitScreenUtils.getSendNotification(instrumentation)
 
@@ -78,21 +76,19 @@
                 SplitScreenUtils.dragFromNotificationToSplit(instrumentation, device, wmHelper)
                 SplitScreenUtils.waitForSplitComplete(wmHelper, primaryApp, sendNotificationApp)
             }
-            teardown {
-                sendNotificationApp.exit(wmHelper)
-            }
+            teardown { sendNotificationApp.exit(wmHelper) }
         }
 
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
 
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.splitScreenDividerBecomesVisible()
+        flicker.splitScreenDividerBecomesVisible()
     }
 
     // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
@@ -100,20 +96,16 @@
     @Test
     fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.assertLayersEnd {
-            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
-        }
+        flicker.assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
     }
 
-    @Presubmit
-    @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isInvisible(sendNotificationApp)
                 .then()
                 .isVisible(sendNotificationApp)
@@ -129,50 +121,48 @@
     @Test
     fun secondaryAppLayerBecomesVisible_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.layerBecomesVisible(sendNotificationApp)
+        flicker.layerBecomesVisible(sendNotificationApp)
     }
 
     @Presubmit
     @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp, landscapePosLeft = false, portraitPosTop = false)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = false,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
-        sendNotificationApp)
+    fun secondaryAppBoundsBecomesVisible() =
+        flicker.splitAppLayerBoundsBecomesVisibleByDrag(sendNotificationApp)
 
     @Presubmit
     @Test
-    fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+    fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(sendNotificationApp)
+    fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(sendNotificationApp)
+
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -183,26 +173,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -219,11 +205,10 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes =
-                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
index dcadb5a..abf9426 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromShortcut.kt
@@ -17,14 +17,14 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.platform.test.annotations.IwTest
-import android.view.WindowManagerPolicyConstants
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
@@ -41,8 +41,7 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test enter split screen by dragging a shortcut.
- * This test is only for large screen devices.
+ * Test enter split screen by dragging a shortcut. This test is only for large screen devices.
  *
  * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromShortcut`
  */
@@ -50,13 +49,11 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromShortcut(
-    testSpec: FlickerTestParameter
-) : SplitScreenBase(testSpec) {
+class EnterSplitScreenByDragFromShortcut(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     @Before
     fun before() {
-        Assume.assumeTrue(testSpec.isTablet)
+        Assume.assumeTrue(flicker.scenario.isTablet)
     }
 
     override val transition: FlickerBuilder.() -> Unit
@@ -80,39 +77,46 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp,
-        fromOtherApp = false, appExistAtStart = false)
+    fun cujCompleted() =
+        flicker.splitScreenEntered(
+            primaryApp,
+            secondaryApp,
+            fromOtherApp = false,
+            appExistAtStart = false
+        )
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
+
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = false,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp, landscapePosLeft = false, portraitPosTop = false)
+    fun secondaryAppBoundsBecomesVisible() =
+        flicker.splitAppLayerBoundsBecomesVisibleByDrag(secondaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
-        secondaryApp)
-
-    @Presubmit
-    @Test
-    fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+    fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
     fun secondaryAppWindowBecomesVisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.notContains(secondaryApp)
                 .then()
                 .isAppWindowInvisible(secondaryApp, isOptional = true)
@@ -122,28 +126,22 @@
     }
 
     /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -154,26 +152,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -190,11 +184,11 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes =
-                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY))
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
-}
\ No newline at end of file
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
index 496d439..795a2c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenByDragFromTaskbar.kt
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -44,8 +44,8 @@
 import org.junit.runners.Parameterized
 
 /**
- * Test enter split screen by dragging app icon from taskbar.
- * This test is only for large screen devices.
+ * Test enter split screen by dragging app icon from taskbar. This test is only for large screen
+ * devices.
  *
  * To run this test: `atest WMShellFlickerTests:EnterSplitScreenByDragFromTaskbar`
  */
@@ -53,9 +53,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenByDragFromTaskbar(
-    testSpec: FlickerTestParameter
-) : SplitScreenBase(testSpec) {
+class EnterSplitScreenByDragFromTaskbar(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     @Before
     fun before() {
@@ -68,9 +66,7 @@
             super.transition(this)
             setup {
                 tapl.goHome()
-                SplitScreenUtils.createShortcutOnHotseatIfNotExist(
-                    tapl, secondaryApp.appName
-                )
+                SplitScreenUtils.createShortcutOnHotseatIfNotExist(tapl, secondaryApp.appName)
                 primaryApp.launchViaIntent(wmHelper)
             }
             transitions {
@@ -84,13 +80,13 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = false)
 
     @Presubmit
     @Test
     fun splitScreenDividerBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.splitScreenDividerBecomesVisible()
+        flicker.splitScreenDividerBecomesVisible()
     }
 
     // TODO(b/245472831): Back to splitScreenDividerBecomesVisible after shell transition ready.
@@ -98,20 +94,16 @@
     @Test
     fun splitScreenDividerIsVisibleAtEnd_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.assertLayersEnd {
-            this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
-        }
+        flicker.assertLayersEnd { this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT) }
     }
 
-    @Presubmit
-    @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
     fun secondaryAppLayerBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isInvisible(secondaryApp)
                 .then()
                 .isVisible(secondaryApp)
@@ -127,50 +119,48 @@
     @Test
     fun secondaryAppLayerBecomesVisible_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.layerBecomesVisible(secondaryApp)
+        flicker.layerBecomesVisible(secondaryApp)
     }
 
     @Presubmit
     @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp, landscapePosLeft = false, portraitPosTop = false)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = false,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
-    fun secondaryAppBoundsBecomesVisible() = testSpec.splitAppLayerBoundsBecomesVisibleByDrag(
-        secondaryApp)
+    fun secondaryAppBoundsBecomesVisible() =
+        flicker.splitAppLayerBoundsBecomesVisibleByDrag(secondaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+    fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
+
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -181,26 +171,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -217,10 +203,9 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
-                supportedNavigationModes =
-                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
index fb7b8b7..c09ca91 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/EnterSplitScreenFromOverview.kt
@@ -21,11 +21,11 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.layerIsVisibleAtEnd
@@ -49,7 +49,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class EnterSplitScreenFromOverview(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class EnterSplitScreenFromOverview(flicker: FlickerTest) : SplitScreenBase(flicker) {
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
@@ -57,7 +57,8 @@
                 primaryApp.launchViaIntent(wmHelper)
                 secondaryApp.launchViaIntent(wmHelper)
                 tapl.goHome()
-                wmHelper.StateSyncBuilder()
+                wmHelper
+                    .StateSyncBuilder()
                     .withAppTransitionIdle()
                     .withHomeActivityVisible()
                     .waitForAndVerify()
@@ -71,72 +72,76 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
+
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
-
-    @Presubmit
-    @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp, landscapePosLeft = tapl.isTablet, portraitPosTop = false)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = tapl.isTablet,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
     fun secondaryAppBoundsBecomesVisible() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.splitAppLayerBoundsBecomesVisible(
-            secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+        flicker.splitAppLayerBoundsBecomesVisible(
+            secondaryApp,
+            landscapePosLeft = !tapl.isTablet,
+            portraitPosTop = true
+        )
     }
 
     @FlakyTest(bugId = 244407465)
     @Test
     fun secondaryAppBoundsBecomesVisible_shellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.splitAppLayerBoundsBecomesVisible(
-            secondaryApp, landscapePosLeft = !tapl.isTablet, portraitPosTop = true)
+        flicker.splitAppLayerBoundsBecomesVisible(
+            secondaryApp,
+            landscapePosLeft = !tapl.isTablet,
+            portraitPosTop = true
+        )
     }
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+    fun primaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 251269324)
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -147,26 +152,22 @@
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 252736515)
@@ -183,8 +184,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
index c841333..8c0a303 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenBase.kt
@@ -17,12 +17,12 @@
 package com.android.wm.shell.flicker.splitscreen
 
 import android.content.Context
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.wm.shell.flicker.BaseTest
 
-abstract class SplitScreenBase(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class SplitScreenBase(flicker: FlickerTest) : BaseTest(flicker) {
     protected val context: Context = instrumentation.context
     protected val primaryApp = SplitScreenUtils.getPrimary(instrumentation)
     protected val secondaryApp = SplitScreenUtils.getSecondary(instrumentation)
@@ -32,8 +32,8 @@
         get() = {
             setup {
                 tapl.setEnableRotation(true)
-                setRotation(testSpec.startRotation)
-                tapl.setExpectedRotation(testSpec.startRotation)
+                setRotation(flicker.scenario.startRotation)
+                tapl.setExpectedRotation(flicker.scenario.startRotation.value)
                 tapl.workspace.switchToOverview().dismissAllTasks()
             }
             teardown {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
index 4a3284e..f3927d4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SplitScreenUtils.kt
@@ -41,8 +41,8 @@
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.LAUNCHER_UI_PACKAGE_NAME
 import com.android.wm.shell.flicker.SYSTEM_UI_PACKAGE_NAME
-import org.junit.Assert.assertNotNull
 import java.util.Collections
+import org.junit.Assert.assertNotNull
 
 internal object SplitScreenUtils {
     private const val TIMEOUT_MS = 3_000L
@@ -129,10 +129,18 @@
 
             // Find the second task in the upper right corner in split select mode by sorting
             // 'left' in descending order and 'top' in ascending order.
-            Collections.sort(snapshots, { t1: UiObject2, t2: UiObject2 ->
-                t2.getVisibleBounds().left - t1.getVisibleBounds().left})
-            Collections.sort(snapshots, { t1: UiObject2, t2: UiObject2 ->
-                t1.getVisibleBounds().top - t2.getVisibleBounds().top})
+            Collections.sort(
+                snapshots,
+                { t1: UiObject2, t2: UiObject2 ->
+                    t2.getVisibleBounds().left - t1.getVisibleBounds().left
+                }
+            )
+            Collections.sort(
+                snapshots,
+                { t1: UiObject2, t2: UiObject2 ->
+                    t1.getVisibleBounds().top - t2.getVisibleBounds().top
+                }
+            )
             snapshots[0].click()
         } else {
             tapl.workspace
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
index f7610c4..09568b2 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchAppByDoubleTapDivider.kt
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
@@ -50,19 +50,15 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchAppByDoubleTapDivider(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class SwitchAppByDoubleTapDivider(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
-            setup {
-                SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp)
-            }
+            setup { SplitScreenUtils.enterSplit(wmHelper, tapl, device, primaryApp, secondaryApp) }
             transitions {
                 SplitScreenUtils.doubleTapDividerToSwitch(device)
-                wmHelper.StateSyncBuilder()
-                    .withAppTransitionIdle()
-                    .waitForAndVerify()
+                wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
 
                 waitForLayersToSwitch(wmHelper)
                 waitForWindowsToSwitch(wmHelper)
@@ -70,61 +66,74 @@
         }
 
     private fun waitForWindowsToSwitch(wmHelper: WindowManagerStateHelper) {
-        wmHelper.StateSyncBuilder().add("appWindowsSwitched") {
-            val primaryAppWindow = it.wmState.visibleWindows.firstOrNull { window ->
-                primaryApp.windowMatchesAnyOf(window)
-            } ?: return@add false
-            val secondaryAppWindow = it.wmState.visibleWindows.firstOrNull { window ->
-                secondaryApp.windowMatchesAnyOf(window)
-            } ?: return@add false
+        wmHelper
+            .StateSyncBuilder()
+            .add("appWindowsSwitched") {
+                val primaryAppWindow =
+                    it.wmState.visibleWindows.firstOrNull { window ->
+                        primaryApp.windowMatchesAnyOf(window)
+                    }
+                        ?: return@add false
+                val secondaryAppWindow =
+                    it.wmState.visibleWindows.firstOrNull { window ->
+                        secondaryApp.windowMatchesAnyOf(window)
+                    }
+                        ?: return@add false
 
-            if (isLandscape(testSpec.endRotation)) {
-                return@add if (testSpec.isTablet) {
-                    secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
+                if (isLandscape(flicker.scenario.endRotation)) {
+                    return@add if (flicker.scenario.isTablet) {
+                        secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
+                    } else {
+                        primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
+                    }
                 } else {
-                    primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
-                }
-            } else {
-                return@add if (testSpec.isTablet) {
-                    primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
-                } else {
-                    primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+                    return@add if (flicker.scenario.isTablet) {
+                        primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+                    } else {
+                        primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
+                    }
                 }
             }
-        }.waitForAndVerify()
+            .waitForAndVerify()
     }
 
     private fun waitForLayersToSwitch(wmHelper: WindowManagerStateHelper) {
-        wmHelper.StateSyncBuilder().add("appLayersSwitched") {
-            val primaryAppLayer = it.layerState.visibleLayers.firstOrNull { window ->
-                primaryApp.layerMatchesAnyOf(window)
-            } ?: return@add false
-            val secondaryAppLayer = it.layerState.visibleLayers.firstOrNull { window ->
-                secondaryApp.layerMatchesAnyOf(window)
-            } ?: return@add false
+        wmHelper
+            .StateSyncBuilder()
+            .add("appLayersSwitched") {
+                val primaryAppLayer =
+                    it.layerState.visibleLayers.firstOrNull { window ->
+                        primaryApp.layerMatchesAnyOf(window)
+                    }
+                        ?: return@add false
+                val secondaryAppLayer =
+                    it.layerState.visibleLayers.firstOrNull { window ->
+                        secondaryApp.layerMatchesAnyOf(window)
+                    }
+                        ?: return@add false
 
-            val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds
-                ?: return@add false
-            val secondaryVisibleRegion = secondaryAppLayer.visibleRegion?.bounds
-                ?: return@add false
+                val primaryVisibleRegion = primaryAppLayer.visibleRegion?.bounds ?: return@add false
+                val secondaryVisibleRegion =
+                    secondaryAppLayer.visibleRegion?.bounds ?: return@add false
 
-            if (isLandscape(testSpec.endRotation)) {
-                return@add if (testSpec.isTablet) {
-                    secondaryVisibleRegion.right <= primaryVisibleRegion.left
+                if (isLandscape(flicker.scenario.endRotation)) {
+                    return@add if (flicker.scenario.isTablet) {
+                        secondaryVisibleRegion.right <= primaryVisibleRegion.left
+                    } else {
+                        primaryVisibleRegion.right <= secondaryVisibleRegion.left
+                    }
                 } else {
-                    primaryVisibleRegion.right <= secondaryVisibleRegion.left
-                }
-            } else {
-                return@add if (testSpec.isTablet) {
-                    primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
-                } else {
-                    primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+                    return@add if (flicker.scenario.isTablet) {
+                        primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+                    } else {
+                        primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
+                    }
                 }
             }
-        }.waitForAndVerify()
+            .waitForAndVerify()
     }
 
-    private fun isLandscape(rotation: Int): Boolean {
+    private fun isLandscape(rotation: PlatformConsts.Rotation): Boolean {
         val displayBounds = WindowUtils.getDisplayBounds(rotation)
         return displayBounds.width > displayBounds.height
     }
@@ -133,13 +142,13 @@
     @Presubmit
     @Test
     fun cujCompleted() {
-        testSpec.appWindowIsVisibleAtStart(primaryApp)
-        testSpec.appWindowIsVisibleAtStart(secondaryApp)
-        testSpec.splitScreenDividerIsVisibleAtStart()
+        flicker.appWindowIsVisibleAtStart(primaryApp)
+        flicker.appWindowIsVisibleAtStart(secondaryApp)
+        flicker.splitScreenDividerIsVisibleAtStart()
 
-        testSpec.appWindowIsVisibleAtEnd(primaryApp)
-        testSpec.appWindowIsVisibleAtEnd(secondaryApp)
-        testSpec.splitScreenDividerIsVisibleAtEnd()
+        flicker.appWindowIsVisibleAtEnd(primaryApp)
+        flicker.appWindowIsVisibleAtEnd(secondaryApp)
+        flicker.splitScreenDividerIsVisibleAtEnd()
 
         // TODO(b/246490534): Add validation for switched app after withAppTransitionIdle is
         // robust enough to get the correct end state.
@@ -147,63 +156,57 @@
 
     @Presubmit
     @Test
-    fun splitScreenDividerKeepVisible() = testSpec.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+    fun splitScreenDividerKeepVisible() = flicker.layerKeepVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
+
+    @Presubmit @Test fun primaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(primaryApp)
+    fun secondaryAppLayerIsVisibleAtEnd() = flicker.layerIsVisibleAtEnd(secondaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerIsVisibleAtEnd() = testSpec.layerIsVisibleAtEnd(secondaryApp)
+    fun primaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            primaryApp,
+            landscapePosLeft = !tapl.isTablet,
+            portraitPosTop = true
+        )
 
     @Presubmit
     @Test
-    fun primaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        primaryApp,
-        landscapePosLeft = !tapl.isTablet,
-        portraitPosTop = true
-    )
+    fun secondaryAppBoundsIsVisibleAtEnd() =
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
+            secondaryApp,
+            landscapePosLeft = tapl.isTablet,
+            portraitPosTop = false
+        )
 
     @Presubmit
     @Test
-    fun secondaryAppBoundsIsVisibleAtEnd() = testSpec.splitAppLayerBoundsIsVisibleAtEnd(
-        secondaryApp,
-        landscapePosLeft = tapl.isTablet,
-        portraitPosTop = false
-    )
+    fun primaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(primaryApp)
 
     @Presubmit
     @Test
-    fun primaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(primaryApp)
+    fun secondaryAppWindowIsVisibleAtEnd() = flicker.appWindowIsVisibleAtEnd(secondaryApp)
 
-    @Presubmit
-    @Test
-    fun secondaryAppWindowIsVisibleAtEnd() = testSpec.appWindowIsVisibleAtEnd(secondaryApp)
+    /** {@inheritDoc} */
+    @Postsubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
-
-    /** {@inheritDoc} */
-    @Postsubmit
-    @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -214,26 +217,22 @@
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Postsubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Postsubmit
@@ -250,11 +249,10 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
                 // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                supportedNavigationModes =
-                listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
             )
         }
     }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
index 993dba2..940e0e9 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromAnotherApp.kt
@@ -19,12 +19,12 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
@@ -45,7 +45,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromAnotherApp(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class SwitchBackToSplitFromAnotherApp(flicker: FlickerTest) : SplitScreenBase(flicker) {
     val thirdApp = SplitScreenUtils.getNonResizeable(instrumentation)
 
     override val transition: FlickerBuilder.() -> Unit
@@ -66,22 +66,22 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
 
-    @Presubmit @Test fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
+    @Presubmit @Test fun primaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             primaryApp,
             landscapePosLeft = tapl.isTablet,
             portraitPosTop = false
@@ -90,7 +90,7 @@
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             secondaryApp,
             landscapePosLeft = !tapl.isTablet,
             portraitPosTop = true
@@ -98,17 +98,14 @@
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+    fun primaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
 
     /** {@inheritDoc} */
-    @FlakyTest
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    @FlakyTest @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -166,13 +163,11 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
-                )
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
index 2a552cd..85812c4 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromHome.kt
@@ -19,12 +19,12 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
@@ -45,7 +45,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromHome(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class SwitchBackToSplitFromHome(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -65,22 +65,22 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
 
-    @Presubmit @Test fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
+    @Presubmit @Test fun primaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             primaryApp,
             landscapePosLeft = tapl.isTablet,
             portraitPosTop = false
@@ -89,7 +89,7 @@
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             secondaryApp,
             landscapePosLeft = !tapl.isTablet,
             portraitPosTop = true
@@ -97,17 +97,14 @@
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+    fun primaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
 
     /** {@inheritDoc} */
-    @FlakyTest
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    @FlakyTest @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -165,13 +162,11 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
-                )
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
index 7f81bae..7c62433 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBackToSplitFromRecent.kt
@@ -19,12 +19,12 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
@@ -45,7 +45,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBackToSplitFromRecent(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class SwitchBackToSplitFromRecent(flicker: FlickerTest) : SplitScreenBase(flicker) {
 
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -65,22 +65,22 @@
     @IwTest(focusArea = "sysui")
     @Presubmit
     @Test
-    fun cujCompleted() = testSpec.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
+    fun cujCompleted() = flicker.splitScreenEntered(primaryApp, secondaryApp, fromOtherApp = true)
 
     @Presubmit
     @Test
-    fun splitScreenDividerBecomesVisible() = testSpec.splitScreenDividerBecomesVisible()
+    fun splitScreenDividerBecomesVisible() = flicker.splitScreenDividerBecomesVisible()
 
-    @Presubmit @Test fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
+    @Presubmit @Test fun primaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             primaryApp,
             landscapePosLeft = tapl.isTablet,
             portraitPosTop = false
@@ -89,7 +89,7 @@
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             secondaryApp,
             landscapePosLeft = !tapl.isTablet,
             portraitPosTop = true
@@ -97,17 +97,14 @@
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+    fun primaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
 
     /** {@inheritDoc} */
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -165,13 +162,11 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
-                )
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                // TODO(b/176061063):The 3 buttons of nav bar do not exist in the hierarchy.
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
index f5f5fd8..193ab98 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/splitscreen/SwitchBetweenSplitPairs.kt
@@ -20,22 +20,22 @@
 import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.wm.shell.flicker.SPLIT_SCREEN_DIVIDER_COMPONENT
 import com.android.wm.shell.flicker.appWindowBecomesInvisible
 import com.android.wm.shell.flicker.appWindowBecomesVisible
 import com.android.wm.shell.flicker.appWindowIsInvisibleAtEnd
-import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
 import com.android.wm.shell.flicker.appWindowIsVisibleAtEnd
+import com.android.wm.shell.flicker.appWindowIsVisibleAtStart
 import com.android.wm.shell.flicker.layerBecomesInvisible
 import com.android.wm.shell.flicker.layerBecomesVisible
 import com.android.wm.shell.flicker.splitAppLayerBoundsIsVisibleAtEnd
 import com.android.wm.shell.flicker.splitAppLayerBoundsSnapToDivider
-import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
 import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtEnd
+import com.android.wm.shell.flicker.splitScreenDividerIsVisibleAtStart
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -51,7 +51,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchBetweenSplitPairs(testSpec: FlickerTestParameter) : SplitScreenBase(testSpec) {
+class SwitchBetweenSplitPairs(flicker: FlickerTest) : SplitScreenBase(flicker) {
     private val thirdApp = SplitScreenUtils.getIme(instrumentation)
     private val fourthApp = SplitScreenUtils.getSendNotification(instrumentation)
 
@@ -77,21 +77,21 @@
     @Presubmit
     @Test
     fun cujCompleted() {
-        testSpec.appWindowIsVisibleAtStart(thirdApp)
-        testSpec.appWindowIsVisibleAtStart(fourthApp)
-        testSpec.splitScreenDividerIsVisibleAtStart()
+        flicker.appWindowIsVisibleAtStart(thirdApp)
+        flicker.appWindowIsVisibleAtStart(fourthApp)
+        flicker.splitScreenDividerIsVisibleAtStart()
 
-        testSpec.appWindowIsVisibleAtEnd(primaryApp)
-        testSpec.appWindowIsVisibleAtEnd(secondaryApp)
-        testSpec.appWindowIsInvisibleAtEnd(thirdApp)
-        testSpec.appWindowIsInvisibleAtEnd(fourthApp)
-        testSpec.splitScreenDividerIsVisibleAtEnd()
+        flicker.appWindowIsVisibleAtEnd(primaryApp)
+        flicker.appWindowIsVisibleAtEnd(secondaryApp)
+        flicker.appWindowIsInvisibleAtEnd(thirdApp)
+        flicker.appWindowIsInvisibleAtEnd(fourthApp)
+        flicker.splitScreenDividerIsVisibleAtEnd()
     }
 
     @Presubmit
     @Test
     fun splitScreenDividerInvisibleAtMiddle() =
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
                 .then()
                 .isInvisible(SPLIT_SCREEN_DIVIDER_COMPONENT)
@@ -101,24 +101,24 @@
 
     @FlakyTest(bugId = 247095572)
     @Test
-    fun primaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(primaryApp)
+    fun primaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(primaryApp)
 
     @FlakyTest(bugId = 247095572)
     @Test
-    fun secondaryAppLayerBecomesVisible() = testSpec.layerBecomesVisible(secondaryApp)
+    fun secondaryAppLayerBecomesVisible() = flicker.layerBecomesVisible(secondaryApp)
 
     @FlakyTest(bugId = 247095572)
     @Test
-    fun thirdAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(thirdApp)
+    fun thirdAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(thirdApp)
 
     @FlakyTest(bugId = 247095572)
     @Test
-    fun fourthAppLayerBecomesInvisible() = testSpec.layerBecomesInvisible(fourthApp)
+    fun fourthAppLayerBecomesInvisible() = flicker.layerBecomesInvisible(fourthApp)
 
     @Presubmit
     @Test
     fun primaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             primaryApp,
             landscapePosLeft = tapl.isTablet,
             portraitPosTop = false
@@ -127,7 +127,7 @@
     @Presubmit
     @Test
     fun secondaryAppBoundsIsVisibleAtEnd() =
-        testSpec.splitAppLayerBoundsIsVisibleAtEnd(
+        flicker.splitAppLayerBoundsIsVisibleAtEnd(
             secondaryApp,
             landscapePosLeft = !tapl.isTablet,
             portraitPosTop = true
@@ -136,66 +136,62 @@
     @Presubmit
     @Test
     fun thirdAppBoundsIsVisibleAtBegin() =
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             this.splitAppLayerBoundsSnapToDivider(
                 thirdApp,
                 landscapePosLeft = tapl.isTablet,
                 portraitPosTop = false,
-                testSpec.startRotation
+                flicker.scenario.startRotation
             )
         }
 
     @Presubmit
     @Test
     fun fourthAppBoundsIsVisibleAtBegin() =
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             this.splitAppLayerBoundsSnapToDivider(
                 fourthApp,
                 landscapePosLeft = !tapl.isTablet,
                 portraitPosTop = true,
-                testSpec.startRotation
+                flicker.scenario.startRotation
             )
         }
 
     @Presubmit
     @Test
-    fun primaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(primaryApp)
+    fun primaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(primaryApp)
 
     @Presubmit
     @Test
-    fun secondaryAppWindowBecomesVisible() = testSpec.appWindowBecomesVisible(secondaryApp)
+    fun secondaryAppWindowBecomesVisible() = flicker.appWindowBecomesVisible(secondaryApp)
 
     @Presubmit
     @Test
-    fun thirdAppWindowBecomesVisible() = testSpec.appWindowBecomesInvisible(thirdApp)
+    fun thirdAppWindowBecomesVisible() = flicker.appWindowBecomesInvisible(thirdApp)
 
     @Presubmit
     @Test
-    fun fourthAppWindowBecomesVisible() = testSpec.appWindowBecomesInvisible(fourthApp)
+    fun fourthAppWindowBecomesVisible() = flicker.appWindowBecomesInvisible(fourthApp)
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 251268711)
     @Test
-    override fun entireScreenCovered() =
-        super.entireScreenCovered()
+    override fun entireScreenCovered() = super.entireScreenCovered()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 206753786)
     @Test
-    override fun navBarLayerPositionAtStartAndEnd() =
-        super.navBarLayerPositionAtStartAndEnd()
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun navBarWindowIsAlwaysVisible() =
-        super.navBarWindowIsAlwaysVisible()
+    override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
@@ -206,26 +202,22 @@
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarLayerPositionAtStartAndEnd() =
-        super.statusBarLayerPositionAtStartAndEnd()
+    override fun statusBarLayerPositionAtStartAndEnd() = super.statusBarLayerPositionAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun statusBarWindowIsAlwaysVisible() =
-        super.statusBarWindowIsAlwaysVisible()
+    override fun statusBarWindowIsAlwaysVisible() = super.statusBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarLayerIsVisibleAtStartAndEnd() =
-        super.taskBarLayerIsVisibleAtStartAndEnd()
+    override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
-    override fun taskBarWindowIsAlwaysVisible() =
-        super.taskBarWindowIsAlwaysVisible()
+    override fun taskBarWindowIsAlwaysVisible() = super.taskBarWindowIsAlwaysVisible()
 
     /** {@inheritDoc} */
     @FlakyTest
@@ -242,8 +234,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
index d75c36c..8a5b490 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java
@@ -53,6 +53,7 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 import android.window.BackNavigationInfo;
 import android.window.IBackAnimationFinishedCallback;
 import android.window.IOnBackInvokedCallback;
@@ -110,6 +111,9 @@
     @Mock
     private ShellController mShellController;
 
+    @Mock
+    private BackAnimationBackground mAnimationBackground;
+
     private BackAnimationController mController;
     private TestableContentResolver mContentResolver;
     private TestableLooper mTestableLooper;
@@ -127,7 +131,7 @@
         mController = new BackAnimationController(mShellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()),
                 mActivityTaskManager, mContext,
-                mContentResolver);
+                mContentResolver, mAnimationBackground);
         mController.setEnableUAnimation(true);
         mShellInit.init();
         mShellExecutor.flushAll();
@@ -220,9 +224,10 @@
 
         simulateRemoteAnimationStart(BackNavigationInfo.TYPE_RETURN_TO_HOME);
 
-        verify(mAnimatorCallback).onBackStarted(any(BackEvent.class));
+        verify(mAnimatorCallback).onBackStarted(any(BackMotionEvent.class));
         verify(mBackAnimationRunner).onAnimationStart(anyInt(), any(), any(), any(), any());
-        ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
+        ArgumentCaptor<BackMotionEvent> backEventCaptor =
+                ArgumentCaptor.forClass(BackMotionEvent.class);
         verify(mAnimatorCallback, atLeastOnce()).onBackProgressed(backEventCaptor.capture());
 
         // Check that back invocation is dispatched.
@@ -239,11 +244,12 @@
         mController = new BackAnimationController(shellInit, mShellController,
                 mShellExecutor, new Handler(mTestableLooper.getLooper()),
                 mActivityTaskManager, mContext,
-                mContentResolver);
+                mContentResolver, mAnimationBackground);
         shellInit.init();
         registerAnimation(BackNavigationInfo.TYPE_RETURN_TO_HOME);
 
-        ArgumentCaptor<BackEvent> backEventCaptor = ArgumentCaptor.forClass(BackEvent.class);
+        ArgumentCaptor<BackMotionEvent> backEventCaptor =
+                ArgumentCaptor.forClass(BackMotionEvent.class);
 
         createNavigationInfo(BackNavigationInfo.TYPE_RETURN_TO_HOME, false);
 
@@ -354,6 +360,10 @@
                 BackNavigationInfo.TYPE_DIALOG_CLOSE};
 
         for (int type: testTypes) {
+            unregisterAnimation(type);
+        }
+
+        for (int type: testTypes) {
             final ResultListener result = new ResultListener();
             createNavigationInfo(new BackNavigationInfo.Builder()
                     .setType(type)
@@ -431,6 +441,10 @@
                 new BackAnimationRunner(mAnimatorCallback, mBackAnimationRunner));
     }
 
+    private void unregisterAnimation(int type) {
+        mController.unregisterAnimation(type);
+    }
+
     private static class ResultListener implements RemoteCallback.OnResultListener {
         boolean mBackNavigationDone = false;
         boolean mTriggerBack = false;
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
index 3aefc3f..ba9c159 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/TouchTrackerTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.assertEquals;
 
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -38,7 +39,7 @@
     @Test
     public void generatesProgress_onStart() {
         mTouchTracker.setGestureStartLocation(INITIAL_X_LEFT_EDGE, 0, BackEvent.EDGE_LEFT);
-        BackEvent event = mTouchTracker.createStartEvent(null);
+        BackMotionEvent event = mTouchTracker.createStartEvent(null);
         assertEquals(event.getProgress(), 0f, 0f);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
index 7068a84..48415d4 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/freeform/FreeformTaskTransitionObserverTest.java
@@ -103,7 +103,7 @@
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
         mTransitionObserver.onTransitionStarting(transition);
 
-        verify(mWindowDecorViewModel).createWindowDecoration(
+        verify(mWindowDecorViewModel).onTaskOpening(
                 change.getTaskInfo(), change.getLeash(), startT, finishT);
     }
 
@@ -120,7 +120,7 @@
         mTransitionObserver.onTransitionReady(transition, info, startT, finishT);
         mTransitionObserver.onTransitionStarting(transition);
 
-        verify(mWindowDecorViewModel).setupWindowDecorationForTransition(
+        verify(mWindowDecorViewModel).onTaskClosing(
                 change.getTaskInfo(), startT, finishT);
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index 38b75f8..f8ded77 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -178,10 +178,10 @@
         Intent startIntent = createStartIntent("startActivity");
         PendingIntent pendingIntent =
                 PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
-        // Put the same component into focus task
-        ActivityManager.RunningTaskInfo focusTaskInfo =
+        // Put the same component to the top running task
+        ActivityManager.RunningTaskInfo topRunningTask =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
-        doReturn(focusTaskInfo).when(mStageCoordinator).getFocusingTaskInfo();
+        doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask();
         doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any());
 
         mSplitScreenController.startIntent(pendingIntent, null, SPLIT_POSITION_TOP_OR_LEFT, null);
@@ -199,10 +199,10 @@
         Intent startIntent = createStartIntent("startActivity");
         PendingIntent pendingIntent =
                 PendingIntent.getActivity(mContext, 0, startIntent, FLAG_IMMUTABLE);
-        // Put the same component into focus task
-        ActivityManager.RunningTaskInfo focusTaskInfo =
+        // Put the same component to the top running task
+        ActivityManager.RunningTaskInfo topRunningTask =
                 createTaskInfo(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, startIntent);
-        doReturn(focusTaskInfo).when(mStageCoordinator).getFocusingTaskInfo();
+        doReturn(topRunningTask).when(mRecentTasks).getTopRunningTask();
         doReturn(true).when(mStageCoordinator).isValidToEnterSplitScreen(any());
         // Put the same component into a task in the background
         ActivityManager.RecentTaskInfo sameTaskInfo = new ActivityManager.RecentTaskInfo();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
deleted file mode 100644
index 004df2a2..0000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/TaskSnapshotWindowTest.java
+++ /dev/null
@@ -1,295 +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.wm.shell.startingsurface;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
-import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
-import static org.mockito.Matchers.eq;
-
-import android.app.ActivityManager.TaskDescription;
-import android.content.ComponentName;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorSpace;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.hardware.HardwareBuffer;
-import android.view.Surface;
-import android.view.SurfaceControl;
-import android.view.WindowInsets;
-import android.window.TaskSnapshot;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.ShellTestCase;
-import com.android.wm.shell.TestShellExecutor;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test class for {@link TaskSnapshotWindow}.
- *
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TaskSnapshotWindowTest extends ShellTestCase {
-
-    private TaskSnapshotWindow mWindow;
-
-    private void setupSurface(int width, int height) {
-        setupSurface(width, height, new Rect(), 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, width, height));
-    }
-
-    private void setupSurface(int width, int height, Rect contentInsets, int sysuiVis,
-            int windowFlags, Rect taskBounds) {
-        // Previously when constructing TaskSnapshots for this test, scale was 1.0f, so to mimic
-        // this behavior set the taskSize to be the same as the taskBounds width and height. The
-        // taskBounds passed here are assumed to be the same task bounds as when the snapshot was
-        // taken. We assume there is no aspect ratio mismatch between the screenshot and the
-        // taskBounds
-        assertEquals(width, taskBounds.width());
-        assertEquals(height, taskBounds.height());
-        Point taskSize = new Point(taskBounds.width(), taskBounds.height());
-
-        final TaskSnapshot snapshot = createTaskSnapshot(width, height, taskSize, contentInsets);
-        mWindow = new TaskSnapshotWindow(new SurfaceControl(), snapshot, "Test",
-                createTaskDescription(Color.WHITE, Color.RED, Color.BLUE),
-                0 /* appearance */, windowFlags /* windowFlags */, 0 /* privateWindowFlags */,
-                taskBounds, ORIENTATION_PORTRAIT, ACTIVITY_TYPE_STANDARD,
-                WindowInsets.Type.defaultVisible(), null /* clearWindow */,
-                new TestShellExecutor());
-    }
-
-    private TaskSnapshot createTaskSnapshot(int width, int height, Point taskSize,
-            Rect contentInsets) {
-        final HardwareBuffer buffer = HardwareBuffer.create(width, height, HardwareBuffer.RGBA_8888,
-                1, HardwareBuffer.USAGE_CPU_READ_RARELY);
-        return new TaskSnapshot(
-                System.currentTimeMillis(),
-                new ComponentName("", ""), buffer,
-                ColorSpace.get(ColorSpace.Named.SRGB), ORIENTATION_PORTRAIT,
-                Surface.ROTATION_0, taskSize, contentInsets, new Rect() /* letterboxInsets */,
-                false, true /* isRealSnapshot */, WINDOWING_MODE_FULLSCREEN,
-                0 /* systemUiVisibility */, false /* isTranslucent */, false /* hasImeSurface */);
-    }
-
-    private static TaskDescription createTaskDescription(int background, int statusBar,
-            int navigationBar) {
-        final TaskDescription td = new TaskDescription();
-        td.setBackgroundColor(background);
-        td.setStatusBarColor(statusBar);
-        td.setNavigationBarColor(navigationBar);
-        return td;
-    }
-
-    @Test
-    public void fillEmptyBackground_fillHorizontally() {
-        setupSurface(200, 100);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(200);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 200));
-        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
-    }
-
-    @Test
-    public void fillEmptyBackground_fillVertically() {
-        setupSurface(100, 200);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(200);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 100));
-        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(100.0f), eq(200.0f), any());
-    }
-
-    @Test
-    public void fillEmptyBackground_fillBoth() {
-        setupSurface(200, 200);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(200);
-        when(mockCanvas.getHeight()).thenReturn(200);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
-        verify(mockCanvas).drawRect(eq(100.0f), eq(0.0f), eq(200.0f), eq(100.0f), any());
-        verify(mockCanvas).drawRect(eq(0.0f), eq(100.0f), eq(200.0f), eq(200.0f), any());
-    }
-
-    @Test
-    public void fillEmptyBackground_dontFill_sameSize() {
-        setupSurface(100, 100);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 100, 100));
-        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
-    }
-
-    @Test
-    public void fillEmptyBackground_dontFill_bitmapLarger() {
-        setupSurface(100, 100);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawBackgroundAndBars(mockCanvas, new Rect(0, 0, 200, 200));
-        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 100, 90), mWindow.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_taskNotOnTop() {
-        setupSurface(100, 100, new Rect(0, 10, 0, 10), 0, 0, new Rect(0, 50, 100, 150));
-        assertEquals(new Rect(0, 10, 100, 90), mWindow.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_navBarLeft() {
-        setupSurface(100, 100, new Rect(10, 10, 0, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(10, 0, 100, 100), mWindow.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_navBarRight() {
-        setupSurface(100, 100, new Rect(0, 10, 10, 0), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(0, 0, 90, 100), mWindow.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotCrop_waterfall() {
-        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
-        assertEquals(new Rect(5, 0, 95, 90), mWindow.calculateSnapshotCrop());
-    }
-
-    @Test
-    public void testCalculateSnapshotFrame() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 0, 10);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        assertEquals(new Rect(0, 0, 100, 80),
-                mWindow.calculateSnapshotFrame(new Rect(0, 10, 100, 90)));
-    }
-
-    @Test
-    public void testCalculateSnapshotFrame_navBarLeft() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(10, 10, 0, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        assertEquals(new Rect(10, 0, 100, 90),
-                mWindow.calculateSnapshotFrame(new Rect(10, 10, 100, 100)));
-    }
-
-    @Test
-    public void testCalculateSnapshotFrame_waterfall() {
-        setupSurface(100, 100, new Rect(5, 10, 5, 10), 0, 0, new Rect(0, 0, 100, 100));
-        final Rect insets = new Rect(0, 10, 0, 10);
-        mWindow.setFrames(new Rect(5, 0, 95, 100), insets);
-        assertEquals(new Rect(0, 0, 90, 90),
-                mWindow.calculateSnapshotFrame(new Rect(5, 0, 95, 90)));
-    }
-
-    @Test
-    public void testDrawStatusBarBackground() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 50, 100));
-        verify(mockCanvas).drawRect(eq(50.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
-    }
-
-    @Test
-    public void testDrawStatusBarBackground_nullFrame() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, null);
-        verify(mockCanvas).drawRect(eq(0.0f), eq(0.0f), eq(90.0f), eq(10.0f), any());
-    }
-
-    @Test
-    public void testDrawStatusBarBackground_nope() {
-        setupSurface(100, 100);
-        final Rect insets = new Rect(0, 10, 10, 0);
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawStatusBarBackground(mockCanvas, new Rect(0, 0, 100, 100));
-        verify(mockCanvas, never()).drawRect(anyInt(), anyInt(), anyInt(), anyInt(), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground() {
-        final Rect insets = new Rect(0, 10, 0, 10);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(0, 90, 100, 100)), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground_left() {
-        final Rect insets = new Rect(10, 10, 0, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(0, 0, 10, 100)), any());
-    }
-
-    @Test
-    public void testDrawNavigationBarBackground_right() {
-        final Rect insets = new Rect(0, 10, 10, 0);
-        setupSurface(100, 100, insets, 0, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,
-                new Rect(0, 0, 100, 100));
-        mWindow.setFrames(new Rect(0, 0, 100, 100), insets);
-        final Canvas mockCanvas = mock(Canvas.class);
-        when(mockCanvas.getWidth()).thenReturn(100);
-        when(mockCanvas.getHeight()).thenReturn(100);
-        mWindow.drawNavigationBarBackground(mockCanvas);
-        verify(mockCanvas).drawRect(eq(new Rect(90, 0, 100, 100)), any());
-    }
-}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java
new file mode 100644
index 0000000..9b37b97
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/CaptionWindowDecorViewModelTests.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.wm.shell.windowdecor;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.hardware.input.InputManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.view.Choreographer;
+import android.view.Display;
+import android.view.InputChannel;
+import android.view.InputMonitor;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.rule.GrantPermissionRule;
+
+import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.TestRunningTaskInfoBuilder;
+import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.SyncTransactionQueue;
+import com.android.wm.shell.desktopmode.DesktopModeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Supplier;
+
+/** Tests of {@link CaptionWindowDecorViewModel} */
+@SmallTest
+public class CaptionWindowDecorViewModelTests extends ShellTestCase {
+    @Mock private CaptionWindowDecoration mCaptionWindowDecoration;
+
+    @Mock private CaptionWindowDecoration.Factory mCaptionWindowDecorFactory;
+
+    @Mock private Handler mMainHandler;
+
+    @Mock private Choreographer mMainChoreographer;
+
+    @Mock private ShellTaskOrganizer mTaskOrganizer;
+
+    @Mock private DisplayController mDisplayController;
+
+    @Mock private SyncTransactionQueue mSyncQueue;
+
+    @Mock private DesktopModeController mDesktopModeController;
+
+    @Mock private InputMonitor mInputMonitor;
+
+    @Mock private InputChannel mInputChannel;
+
+    @Mock private CaptionWindowDecorViewModel.EventReceiverFactory mEventReceiverFactory;
+
+    @Mock private CaptionWindowDecorViewModel.EventReceiver mEventReceiver;
+
+    @Mock private InputManager mInputManager;
+
+    private final List<InputManager> mMockInputManagers = new ArrayList<>();
+
+    private CaptionWindowDecorViewModel mCaptionWindowDecorViewModel;
+
+    @Before
+    public void setUp() {
+        mMockInputManagers.add(mInputManager);
+
+        mCaptionWindowDecorViewModel =
+            new CaptionWindowDecorViewModel(
+                mContext,
+                mMainHandler,
+                mMainChoreographer,
+                mTaskOrganizer,
+                mDisplayController,
+                mSyncQueue,
+                mDesktopModeController,
+                mCaptionWindowDecorFactory,
+                new MockObjectSupplier<>(mMockInputManagers, () -> mock(InputManager.class)));
+        mCaptionWindowDecorViewModel.setEventReceiverFactory(mEventReceiverFactory);
+
+        doReturn(mCaptionWindowDecoration)
+            .when(mCaptionWindowDecorFactory)
+            .create(any(), any(), any(), any(), any(), any(), any(), any());
+
+        when(mInputManager.monitorGestureInput(any(), anyInt())).thenReturn(mInputMonitor);
+        when(mEventReceiverFactory.create(any(), any(), any())).thenReturn(mEventReceiver);
+        when(mInputMonitor.getInputChannel()).thenReturn(mInputChannel);
+    }
+
+    @Test
+    public void testDeleteCaptionOnChangeTransitionWhenNecessary() throws Exception {
+        Looper.prepare();
+        final int taskId = 1;
+        final ActivityManager.RunningTaskInfo taskInfo =
+                createTaskInfo(taskId, WINDOWING_MODE_FREEFORM);
+        SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+        GrantPermissionRule.grant(android.Manifest.permission.MONITOR_INPUT);
+
+        mCaptionWindowDecorViewModel.onTaskOpening(taskInfo, surfaceControl, startT, finishT);
+        verify(mCaptionWindowDecorFactory)
+                .create(
+                    mContext,
+                    mDisplayController,
+                    mTaskOrganizer,
+                    taskInfo,
+                    surfaceControl,
+                    mMainHandler,
+                    mMainChoreographer,
+                    mSyncQueue);
+
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_UNDEFINED);
+        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+        mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
+        verify(mCaptionWindowDecoration).close();
+    }
+
+    @Test
+    public void testCreateCaptionOnChangeTransitionWhenNecessary() throws Exception {
+        final int taskId = 1;
+        final ActivityManager.RunningTaskInfo taskInfo =
+                createTaskInfo(taskId, WINDOWING_MODE_UNDEFINED);
+        SurfaceControl surfaceControl = mock(SurfaceControl.class);
+        final SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
+        final SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
+        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_UNDEFINED);
+
+        mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
+
+        verify(mCaptionWindowDecorFactory, never())
+                .create(
+                    mContext,
+                    mDisplayController,
+                    mTaskOrganizer,
+                    taskInfo,
+                    surfaceControl,
+                    mMainHandler,
+                    mMainChoreographer,
+                    mSyncQueue);
+
+        taskInfo.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        taskInfo.configuration.windowConfiguration.setActivityType(ACTIVITY_TYPE_STANDARD);
+
+        mCaptionWindowDecorViewModel.onTaskChanging(taskInfo, surfaceControl, startT, finishT);
+
+        verify(mCaptionWindowDecorFactory)
+                .create(
+                    mContext,
+                    mDisplayController,
+                    mTaskOrganizer,
+                    taskInfo,
+                    surfaceControl,
+                    mMainHandler,
+                    mMainChoreographer,
+                    mSyncQueue);
+    }
+
+    private static ActivityManager.RunningTaskInfo createTaskInfo(int taskId, int windowingMode) {
+        ActivityManager.RunningTaskInfo taskInfo =
+                 new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setVisible(true)
+                .build();
+        taskInfo.taskId = taskId;
+        taskInfo.configuration.windowConfiguration.setWindowingMode(windowingMode);
+        return taskInfo;
+    }
+
+    private static class MockObjectSupplier<T> implements Supplier<T> {
+        private final List<T> mObjects;
+        private final Supplier<T> mDefaultSupplier;
+        private int mNumOfCalls = 0;
+
+        private MockObjectSupplier(List<T> objects, Supplier<T> defaultSupplier) {
+            mObjects = objects;
+            mDefaultSupplier = defaultSupplier;
+        }
+
+        @Override
+        public T get() {
+            final T mock =
+                    mNumOfCalls < mObjects.size() ? mObjects.get(mNumOfCalls)
+                        : mDefaultSupplier.get();
+            ++mNumOfCalls;
+            return mock;
+        }
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
index 15181b1..dd9ab98 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/WindowDecorationTests.java
@@ -113,6 +113,12 @@
         mMockSurfaceControlFinishT = createMockSurfaceControlTransaction();
         mMockSurfaceControlAddWindowT = createMockSurfaceControlTransaction();
 
+        mRelayoutParams.mLayoutResId = 0;
+        mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
+        // Caption should have fixed width except in testLayoutResultCalculation_fullWidthCaption()
+        mRelayoutParams.mCaptionWidthId = R.dimen.test_freeform_decor_caption_width;
+        mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
+
         doReturn(mMockSurfaceControlViewHost).when(mMockSurfaceControlViewHostFactory)
                 .create(any(), any(), any());
     }
@@ -435,6 +441,58 @@
         assertThat(additionalWindow.mWindowSurface).isNull();
     }
 
+    @Test
+    public void testLayoutResultCalculation_fullWidthCaption() {
+        final Display defaultDisplay = mock(Display.class);
+        doReturn(defaultDisplay).when(mMockDisplayController)
+                .getDisplay(Display.DEFAULT_DISPLAY);
+
+        final SurfaceControl decorContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder decorContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(decorContainerSurface);
+        mMockSurfaceControlBuilders.add(decorContainerSurfaceBuilder);
+        final SurfaceControl taskBackgroundSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder taskBackgroundSurfaceBuilder =
+                createMockSurfaceControlBuilder(taskBackgroundSurface);
+        mMockSurfaceControlBuilders.add(taskBackgroundSurfaceBuilder);
+        final SurfaceControl captionContainerSurface = mock(SurfaceControl.class);
+        final SurfaceControl.Builder captionContainerSurfaceBuilder =
+                createMockSurfaceControlBuilder(captionContainerSurface);
+        mMockSurfaceControlBuilders.add(captionContainerSurfaceBuilder);
+
+        final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
+        mMockSurfaceControlTransactions.add(t);
+        final ActivityManager.TaskDescription.Builder taskDescriptionBuilder =
+                new ActivityManager.TaskDescription.Builder()
+                        .setBackgroundColor(Color.YELLOW);
+        final ActivityManager.RunningTaskInfo taskInfo = new TestRunningTaskInfoBuilder()
+                .setDisplayId(Display.DEFAULT_DISPLAY)
+                .setTaskDescriptionBuilder(taskDescriptionBuilder)
+                .setBounds(TASK_BOUNDS)
+                .setPositionInParent(TASK_POSITION_IN_PARENT.x, TASK_POSITION_IN_PARENT.y)
+                .setVisible(true)
+                .build();
+        taskInfo.isFocused = true;
+        taskInfo.configuration.densityDpi = DisplayMetrics.DENSITY_DEFAULT * 2;
+        mRelayoutParams.setOutsets(
+                R.dimen.test_window_decor_left_outset,
+                R.dimen.test_window_decor_top_outset,
+                R.dimen.test_window_decor_right_outset,
+                R.dimen.test_window_decor_bottom_outset);
+        final SurfaceControl taskSurface = mock(SurfaceControl.class);
+        final TestWindowDecoration windowDecor = createWindowDecoration(taskInfo, taskSurface);
+
+        mRelayoutParams.mCaptionWidthId = Resources.ID_NULL;
+        windowDecor.relayout(taskInfo);
+
+        verify(captionContainerSurfaceBuilder).setParent(decorContainerSurface);
+        verify(captionContainerSurfaceBuilder).setContainerLayer();
+        verify(mMockSurfaceControlStartT).setPosition(captionContainerSurface, 20, 40);
+        // Width of the captionContainerSurface should match the width of TASK_BOUNDS
+        verify(mMockSurfaceControlStartT).setWindowCrop(captionContainerSurface, 300, 64);
+        verify(mMockSurfaceControlStartT).show(captionContainerSurface);
+    }
+
     private TestWindowDecoration createWindowDecoration(
             ActivityManager.RunningTaskInfo taskInfo, SurfaceControl testSurface) {
         return new TestWindowDecoration(InstrumentationRegistry.getInstrumentation().getContext(),
@@ -490,11 +548,6 @@
 
         @Override
         void relayout(ActivityManager.RunningTaskInfo taskInfo) {
-            mRelayoutParams.mLayoutResId = 0;
-            mRelayoutParams.mCaptionHeightId = R.dimen.test_freeform_decor_caption_height;
-            mRelayoutParams.mCaptionWidthId = R.dimen.test_freeform_decor_caption_width;
-            mRelayoutParams.mShadowRadiusId = R.dimen.test_window_decor_shadow_radius;
-
             relayout(mRelayoutParams, mMockSurfaceControlStartT, mMockSurfaceControlFinishT,
                     mMockWindowContainerTransaction, mMockView, mRelayoutResult);
         }
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
old mode 100755
new mode 100644
index 9aa3787..15aaae2
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -18,6 +18,7 @@
 
 #include "android-base/errors.h"
 #include "android-base/logging.h"
+#include "android-base/utf8.h"
 
 namespace android {
 
@@ -83,15 +84,16 @@
     return {};
   }
 
+  std::string overlay_path(loaded_idmap->OverlayApkPath());
+  auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC));
   std::unique_ptr<AssetsProvider> overlay_assets;
-  const std::string overlay_path(loaded_idmap->OverlayApkPath());
-  if (IsFabricatedOverlay(overlay_path)) {
+  if (IsFabricatedOverlay(fd)) {
     // Fabricated overlays do not contain resource definitions. All of the overlay resource values
     // are defined inline in the idmap.
-    overlay_assets = EmptyAssetsProvider::Create(overlay_path);
+    overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path));
   } else {
     // The overlay should be an APK.
-    overlay_assets = ZipAssetsProvider::Create(overlay_path, flags);
+    overlay_assets = ZipAssetsProvider::Create(std::move(overlay_path), flags, std::move(fd));
   }
   if (overlay_assets == nullptr) {
     return {};
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 3fa369d..68f5e4a 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -22,6 +22,7 @@
 #include <iterator>
 #include <map>
 #include <set>
+#include <span>
 
 #include "android-base/logging.h"
 #include "android-base/stringprintf.h"
@@ -111,7 +112,7 @@
   // A mapping from path of apk assets that could be target packages of overlays to the runtime
   // package id of its first loaded package. Overlays currently can only override resources in the
   // first package in the target resource table.
-  std::unordered_map<std::string, uint8_t> target_assets_package_ids;
+  std::unordered_map<std::string_view, uint8_t> target_assets_package_ids;
 
   // Overlay resources are not directly referenced by an application so their resource ids
   // can change throughout the application's lifetime. Assign overlay package ids last.
@@ -134,7 +135,7 @@
     if (auto loaded_idmap = apk_assets->GetLoadedIdmap(); loaded_idmap != nullptr) {
       // The target package must precede the overlay package in the apk assets paths in order
       // to take effect.
-      auto iter = target_assets_package_ids.find(std::string(loaded_idmap->TargetApkPath()));
+      auto iter = target_assets_package_ids.find(loaded_idmap->TargetApkPath());
       if (iter == target_assets_package_ids.end()) {
          LOG(INFO) << "failed to find target package for overlay "
                    << loaded_idmap->OverlayApkPath();
@@ -179,7 +180,7 @@
         if (overlay_ref_table != nullptr) {
           // If this package is from an overlay, use a dynamic reference table that can rewrite
           // overlay resource ids to their corresponding target resource ids.
-          new_group.dynamic_ref_table = overlay_ref_table;
+          new_group.dynamic_ref_table = std::move(overlay_ref_table);
         }
 
         DynamicRefTable* ref_table = new_group.dynamic_ref_table.get();
@@ -187,9 +188,9 @@
         ref_table->mAppAsLib = package->IsDynamic() && package->GetPackageId() == 0x7f;
       }
 
-      // Add the package and to the set of packages with the same ID.
+      // Add the package to the set of packages with the same ID.
       PackageGroup* package_group = &package_groups_[idx];
-      package_group->packages_.push_back(ConfiguredPackage{package.get(), {}});
+      package_group->packages_.emplace_back().loaded_package_ = package.get();
       package_group->cookies_.push_back(apk_assets_cookies[apk_assets]);
 
       // Add the package name -> build time ID mappings.
@@ -201,29 +202,38 @@
 
       if (auto apk_assets_path = apk_assets->GetPath()) {
         // Overlay target ApkAssets must have been created using path based load apis.
-        target_assets_package_ids.insert(std::make_pair(std::string(*apk_assets_path), package_id));
+        target_assets_package_ids.emplace(*apk_assets_path, package_id);
       }
     }
   }
 
   // Now assign the runtime IDs so that we have a build-time to runtime ID map.
-  const auto package_groups_end = package_groups_.end();
-  for (auto iter = package_groups_.begin(); iter != package_groups_end; ++iter) {
-    const std::string& package_name = iter->packages_[0].loaded_package_->GetPackageName();
-    for (auto iter2 = package_groups_.begin(); iter2 != package_groups_end; ++iter2) {
-      iter2->dynamic_ref_table->addMapping(String16(package_name.c_str(), package_name.size()),
-                                           iter->dynamic_ref_table->mAssignedPackageId);
-
-      // Add the alias resources to the dynamic reference table of every package group. Since
-      // staging aliases can only be defined by the framework package (which is not a shared
-      // library), the compile-time package id of the framework is the same across all packages
-      // that compile against the framework.
-      for (const auto& package : iter->packages_) {
-        for (const auto& entry : package.loaded_package_->GetAliasResourceIdMap()) {
-          iter2->dynamic_ref_table->addAlias(entry.first, entry.second);
-        }
-      }
+  DynamicRefTable::AliasMap aliases;
+  for (const auto& group : package_groups_) {
+    const std::string& package_name = group.packages_[0].loaded_package_->GetPackageName();
+    const auto name_16 = String16(package_name.c_str(), package_name.size());
+    for (auto&& inner_group : package_groups_) {
+      inner_group.dynamic_ref_table->addMapping(name_16,
+                                                group.dynamic_ref_table->mAssignedPackageId);
     }
+
+    for (const auto& package : group.packages_) {
+      const auto& package_aliases = package.loaded_package_->GetAliasResourceIdMap();
+      aliases.insert(aliases.end(), package_aliases.begin(), package_aliases.end());
+    }
+  }
+
+  if (!aliases.empty()) {
+    std::sort(aliases.begin(), aliases.end(), [](auto&& l, auto&& r) { return l.first < r.first; });
+
+    // Add the alias resources to the dynamic reference table of every package group. Since
+    // staging aliases can only be defined by the framework package (which is not a shared
+    // library), the compile-time package id of the framework is the same across all packages
+    // that compile against the framework.
+    for (auto& group : std::span(package_groups_.data(), package_groups_.size() - 1)) {
+      group.dynamic_ref_table->setAliases(aliases);
+    }
+    package_groups_.back().dynamic_ref_table->setAliases(std::move(aliases));
   }
 }
 
@@ -317,7 +327,7 @@
   return &loaded_package->GetOverlayableMap();
 }
 
-bool AssetManager2::GetOverlayablesToString(const android::StringPiece& package_name,
+bool AssetManager2::GetOverlayablesToString(android::StringPiece package_name,
                                             std::string* out) const {
   uint8_t package_id = 0U;
   for (const auto& apk_assets : apk_assets_) {
@@ -364,7 +374,7 @@
         const std::string name = ToFormattedResourceString(*res_name);
         output.append(base::StringPrintf(
             "resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
-            name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
+            name.c_str(), info->name.data(), info->actor.data(), info->policy_flags));
       }
     }
   }
@@ -492,7 +502,7 @@
       continue;
     }
 
-    auto func = [&](const StringPiece& name, FileType type) {
+    auto func = [&](StringPiece name, FileType type) {
       AssetDir::FileInfo info;
       info.setFileName(String8(name.data(), name.size()));
       info.setFileType(type);
@@ -1271,7 +1281,7 @@
   return result;
 }
 
-static bool Utf8ToUtf16(const StringPiece& str, std::u16string* out) {
+static bool Utf8ToUtf16(StringPiece str, std::u16string* out) {
   ssize_t len =
       utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(str.data()), str.size(), false);
   if (len < 0) {
@@ -1346,22 +1356,22 @@
 
 void AssetManager2::RebuildFilterList() {
   for (PackageGroup& group : package_groups_) {
-    for (ConfiguredPackage& impl : group.packages_) {
-      // Destroy it.
-      impl.filtered_configs_.~ByteBucketArray();
-
-      // Re-create it.
-      new (&impl.filtered_configs_) ByteBucketArray<FilteredConfigGroup>();
-
+    for (ConfiguredPackage& package : group.packages_) {
+      package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); });
       // Create the filters here.
-      impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
-        FilteredConfigGroup& group = impl.filtered_configs_.editItemAt(type_id - 1);
+      package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
+        FilteredConfigGroup* group = nullptr;
         for (const auto& type_entry : type_spec.type_entries) {
           if (type_entry.config.match(configuration_)) {
-            group.type_entries.push_back(&type_entry);
+            if (!group) {
+              group = &package.filtered_configs_.editItemAt(type_id - 1);
+            }
+            group->type_entries.push_back(&type_entry);
           }
         }
       });
+      package.filtered_configs_.trimBuckets(
+          [](const auto& fcg) { return fcg.type_entries.empty(); });
     }
   }
 }
@@ -1402,30 +1412,34 @@
 std::unique_ptr<Theme> AssetManager2::NewTheme() {
   constexpr size_t kInitialReserveSize = 32;
   auto theme = std::unique_ptr<Theme>(new Theme(this));
+  theme->keys_.reserve(kInitialReserveSize);
   theme->entries_.reserve(kInitialReserveSize);
   return theme;
 }
 
+void AssetManager2::ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+                                   package_property_t excluded_property_flags) const {
+  for (const PackageGroup& package_group : package_groups_) {
+    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;
+    }
+  }
+}
+
 Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
 }
 
 Theme::~Theme() = default;
 
 struct Theme::Entry {
-  uint32_t attr_res_id;
   ApkAssetsCookie cookie;
   uint32_t type_spec_flags;
   Res_value value;
 };
 
-namespace {
-struct ThemeEntryKeyComparer {
-  bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
-    return entry.attr_res_id < attr_res_id;
-  }
-};
-} // namespace
-
 base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
   ATRACE_NAME("Theme::ApplyStyle");
 
@@ -1454,18 +1468,20 @@
       continue;
     }
 
-    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
-                                     ThemeEntryKeyComparer{});
-    if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
+    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), attr_res_id);
+    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
+    if (key_it != keys_.end() && *key_it == attr_res_id) {
       if (is_undefined) {
         // DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
-        /// true.
+        // true.
+        keys_.erase(key_it);
         entries_.erase(entry_it);
       } else if (force) {
-        *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
+        *entry_it = Entry{it->cookie, (*bag)->type_spec_flags, it->value};
       }
     } else {
-      entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value});
+      keys_.insert(key_it, attr_res_id);
+      entries_.insert(entry_it, Entry{it->cookie, (*bag)->type_spec_flags, it->value});
     }
   }
   return {};
@@ -1476,6 +1492,7 @@
   ATRACE_NAME("Theme::Rebase");
   // Reset the entries without changing the vector capacity to prevent reallocations during
   // ApplyStyle.
+  keys_.clear();
   entries_.clear();
   asset_manager_ = am;
   for (size_t i = 0; i < style_count; i++) {
@@ -1484,16 +1501,14 @@
 }
 
 std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
-
   constexpr const uint32_t kMaxIterations = 20;
   uint32_t type_spec_flags = 0u;
   for (uint32_t i = 0; i <= kMaxIterations; i++) {
-    auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
-                                     ThemeEntryKeyComparer{});
-    if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
+    const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), resid);
+    if (key_it == keys_.end() || *key_it != resid) {
       return std::nullopt;
     }
-
+    const auto entry_it = entries_.begin() + (key_it - keys_.begin());
     type_spec_flags |= entry_it->type_spec_flags;
     if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
       resid = entry_it->value.data;
@@ -1527,6 +1542,7 @@
 }
 
 void Theme::Clear() {
+  keys_.clear();
   entries_.clear();
 }
 
@@ -1538,18 +1554,19 @@
   type_spec_flags_ = source.type_spec_flags_;
 
   if (asset_manager_ == source.asset_manager_) {
+    keys_ = source.keys_;
     entries_ = source.entries_;
   } else {
-    std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
-    typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
-    std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+    std::unordered_map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+    using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
+    std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
 
     // Determine which ApkAssets are loaded in both theme AssetManagers.
-    const auto src_assets = source.asset_manager_->GetApkAssets();
+    const auto& src_assets = source.asset_manager_->GetApkAssets();
     for (size_t i = 0; i < src_assets.size(); i++) {
       const ApkAssets* src_asset = src_assets[i];
 
-      const auto dest_assets = asset_manager_->GetApkAssets();
+      const auto& dest_assets = asset_manager_->GetApkAssets();
       for (size_t j = 0; j < dest_assets.size(); j++) {
         const ApkAssets* dest_asset = dest_assets[j];
         if (src_asset != dest_asset) {
@@ -1570,15 +1587,17 @@
         }
 
         src_to_dest_asset_cookies.insert(std::make_pair(i, j));
-        src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+        src_asset_cookie_id_map.insert(std::make_pair(i, std::move(package_map)));
         break;
       }
     }
 
     // Reset the data in the destination theme.
+    keys_.clear();
     entries_.clear();
 
-    for (const auto& entry : source.entries_) {
+    for (size_t i = 0, size = source.entries_.size(); i != size; ++i) {
+      const auto& entry = source.entries_[i];
       bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
                            || entry.value.dataType == Res_value::TYPE_REFERENCE
                            || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
@@ -1618,13 +1637,15 @@
         }
       }
 
+      const auto source_res_id = source.keys_[i];
+
       // The package id of the attribute needs to be rewritten to the package id of the
       // attribute in the destination.
-      int attribute_dest_package_id = get_package_id(entry.attr_res_id);
+      int attribute_dest_package_id = get_package_id(source_res_id);
       if (attribute_dest_package_id != 0x01) {
         // Find the cookie of the attribute resource id in the source AssetManager
         base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
-            source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
+            source.asset_manager_->FindEntry(source_res_id, 0 /* density_override */ ,
                                              true /* stop_at_first_match */,
                                              true /* ignore_configuration */);
         if (UNLIKELY(IsIOError(attribute_entry_result))) {
@@ -1648,16 +1669,15 @@
         attribute_dest_package_id = attribute_dest_package->second;
       }
 
-      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
-                                     get_entry_id(entry.attr_res_id));
-      Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
-                                            Res_value{.dataType = entry.value.dataType,
-                                                      .data = attribute_data}};
-
+      auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(source_res_id),
+                                     get_entry_id(source_res_id));
+      const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), dest_attr_id);
+      const auto entry_it = entries_.begin() + (key_it - keys_.begin());
       // Since the entries were cleared, the attribute resource id has yet been mapped to any value.
-      auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
-                                       ThemeEntryKeyComparer{});
-      entries_.insert(entry_it, new_entry);
+      keys_.insert(key_it, dest_attr_id);
+      entries_.insert(entry_it, Entry{data_dest_cookie, entry.type_spec_flags,
+                                      Res_value{.dataType = entry.value.dataType,
+                                                .data = attribute_data}});
     }
   }
   return {};
@@ -1665,9 +1685,11 @@
 
 void Theme::Dump() const {
   LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
-  for (auto& entry : entries_) {
+  for (size_t i = 0, size = keys_.size(); i != size; ++i) {
+    auto res_id = keys_[i];
+    const auto& entry = entries_[i];
     LOG(INFO) << base::StringPrintf("  entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
-                                    entry.attr_res_id, entry.value.data, entry.value.dataType,
+                                    res_id, entry.value.data, entry.value.dataType,
                                     entry.cookie);
   }
 }
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index bce34d3..2d3c065 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -73,9 +73,6 @@
                                           (path != nullptr) ? base::unique_fd(-1) : std::move(fd));
 }
 
-ZipAssetsProvider::PathOrDebugName::PathOrDebugName(std::string&& value, bool is_path)
-    : value_(std::forward<std::string>(value)), is_path_(is_path) {}
-
 const std::string* ZipAssetsProvider::PathOrDebugName::GetPath() const {
   return is_path_ ? &value_ : nullptr;
 }
@@ -84,34 +81,42 @@
   return value_;
 }
 
+void ZipAssetsProvider::ZipCloser::operator()(ZipArchive* a) const {
+  ::CloseArchive(a);
+}
+
 ZipAssetsProvider::ZipAssetsProvider(ZipArchiveHandle handle, PathOrDebugName&& path,
                                      package_property_t flags, time_t last_mod_time)
-    : zip_handle_(handle, ::CloseArchive),
-      name_(std::forward<PathOrDebugName>(path)),
+    : zip_handle_(handle),
+      name_(std::move(path)),
       flags_(flags),
       last_mod_time_(last_mod_time) {}
 
 std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
-                                                             package_property_t flags) {
+                                                             package_property_t flags,
+                                                             base::unique_fd fd) {
+  const auto released_fd = fd.ok() ? fd.release() : -1;
   ZipArchiveHandle handle;
-  if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
+  if (int32_t result = released_fd < 0 ? OpenArchive(path.c_str(), &handle)
+                                       : OpenArchiveFd(released_fd, path.c_str(), &handle)) {
     LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
     CloseArchive(handle);
     return {};
   }
 
   struct stat sb{.st_mtime = -1};
-  if (stat(path.c_str(), &sb) < 0) {
-    // Stat requires execute permissions on all directories path to the file. If the process does
-    // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
-    // always have to return true.
-    LOG(WARNING) << "Failed to stat file '" << path << "': "
-                 << base::SystemErrorCodeToString(errno);
+  // Skip all up-to-date checks if the file won't ever change.
+  if (!isReadonlyFilesystem(path.c_str())) {
+    if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) {
+      // Stat requires execute permissions on all directories path to the file. If the process does
+      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+      // always have to return true.
+      PLOG(WARNING) << "Failed to stat file '" << path << "'";
+    }
   }
 
   return std::unique_ptr<ZipAssetsProvider>(
-      new ZipAssetsProvider(handle, PathOrDebugName{std::move(path),
-                                                    true /* is_path */}, flags, sb.st_mtime));
+      new ZipAssetsProvider(handle, PathOrDebugName::Path(std::move(path)), flags, sb.st_mtime));
 }
 
 std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(base::unique_fd fd,
@@ -133,17 +138,19 @@
   }
 
   struct stat sb{.st_mtime = -1};
-  if (fstat(released_fd, &sb) < 0) {
-    // Stat requires execute permissions on all directories path to the file. If the process does
-    // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
-    // always have to return true.
-    LOG(WARNING) << "Failed to fstat file '" << friendly_name << "': "
-                 << base::SystemErrorCodeToString(errno);
+  // Skip all up-to-date checks if the file won't ever change.
+  if (!isReadonlyFilesystem(released_fd)) {
+    if (fstat(released_fd, &sb) < 0) {
+      // Stat requires execute permissions on all directories path to the file. If the process does
+      // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+      // always have to return true.
+      LOG(WARNING) << "Failed to fstat file '" << friendly_name
+                   << "': " << base::SystemErrorCodeToString(errno);
+    }
   }
 
-  return std::unique_ptr<ZipAssetsProvider>(
-      new ZipAssetsProvider(handle, PathOrDebugName{std::move(friendly_name),
-                                                    false /* is_path */}, flags, sb.st_mtime));
+  return std::unique_ptr<ZipAssetsProvider>(new ZipAssetsProvider(
+      handle, PathOrDebugName::DebugName(std::move(friendly_name)), flags, sb.st_mtime));
 }
 
 std::unique_ptr<Asset> ZipAssetsProvider::OpenInternal(const std::string& path,
@@ -210,9 +217,9 @@
     return asset;
 }
 
-bool ZipAssetsProvider::ForEachFile(const std::string& root_path,
-                                    const std::function<void(const StringPiece&, FileType)>& f)
-                                    const {
+bool ZipAssetsProvider::ForEachFile(
+    const std::string& root_path,
+    base::function_ref<void(StringPiece, FileType)> f) const {
     std::string root_path_full = root_path;
     if (root_path_full.back() != '/') {
       root_path_full += '/';
@@ -238,8 +245,7 @@
       if (!leaf_file_path.empty()) {
         auto iter = std::find(leaf_file_path.begin(), leaf_file_path.end(), '/');
         if (iter != leaf_file_path.end()) {
-          std::string dir =
-              leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)).to_string();
+          std::string dir(leaf_file_path.substr(0, std::distance(leaf_file_path.begin(), iter)));
           dirs.insert(std::move(dir));
         } else {
           f(leaf_file_path, kFileTypeRegular);
@@ -277,6 +283,9 @@
 }
 
 bool ZipAssetsProvider::IsUpToDate() const {
+  if (last_mod_time_ == -1) {
+    return true;
+  }
   struct stat sb{};
   if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
     // If fstat fails on the zip archive, return true so the zip archive the resource system does
@@ -287,10 +296,10 @@
 }
 
 DirectoryAssetsProvider::DirectoryAssetsProvider(std::string&& path, time_t last_mod_time)
-    : dir_(std::forward<std::string>(path)), last_mod_time_(last_mod_time) {}
+    : dir_(std::move(path)), last_mod_time_(last_mod_time) {}
 
 std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
-  struct stat sb{};
+  struct stat sb;
   const int result = stat(path.c_str(), &sb);
   if (result == -1) {
     LOG(ERROR) << "Failed to find directory '" << path << "'.";
@@ -302,12 +311,13 @@
     return nullptr;
   }
 
-  if (path[path.size() - 1] != OS_PATH_SEPARATOR) {
+  if (path.back() != OS_PATH_SEPARATOR) {
     path += OS_PATH_SEPARATOR;
   }
 
-  return std::unique_ptr<DirectoryAssetsProvider>(new DirectoryAssetsProvider(std::move(path),
-                                                                              sb.st_mtime));
+  const bool isReadonly = isReadonlyFilesystem(path.c_str());
+  return std::unique_ptr<DirectoryAssetsProvider>(
+      new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime));
 }
 
 std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
@@ -324,8 +334,7 @@
 
 bool DirectoryAssetsProvider::ForEachFile(
     const std::string& /* root_path */,
-    const std::function<void(const StringPiece&, FileType)>& /* f */)
-    const {
+    base::function_ref<void(StringPiece, FileType)> /* f */) const {
   return true;
 }
 
@@ -338,7 +347,10 @@
 }
 
 bool DirectoryAssetsProvider::IsUpToDate() const {
-  struct stat sb{};
+  if (last_mod_time_ == -1) {
+    return true;
+  }
+  struct stat sb;
   if (stat(dir_.c_str(), &sb) < 0) {
     // If stat fails on the zip archive, return true so the zip archive the resource system does
     // attempt to refresh the ApkAsset.
@@ -349,8 +361,7 @@
 
 MultiAssetsProvider::MultiAssetsProvider(std::unique_ptr<AssetsProvider>&& primary,
                                          std::unique_ptr<AssetsProvider>&& secondary)
-                      : primary_(std::forward<std::unique_ptr<AssetsProvider>>(primary)),
-                        secondary_(std::forward<std::unique_ptr<AssetsProvider>>(secondary)) {
+    : primary_(std::move(primary)), secondary_(std::move(secondary)) {
   debug_name_ = primary_->GetDebugName() + " and " + secondary_->GetDebugName();
   path_ = (primary_->GetDebugName() != kEmptyDebugString) ? primary_->GetPath()
                                                           : secondary_->GetPath();
@@ -372,9 +383,9 @@
   return (asset) ? std::move(asset) : secondary_->Open(path, mode, file_exists);
 }
 
-bool MultiAssetsProvider::ForEachFile(const std::string& root_path,
-                                      const std::function<void(const StringPiece&, FileType)>& f)
-                                      const {
+bool MultiAssetsProvider::ForEachFile(
+    const std::string& root_path,
+    base::function_ref<void(StringPiece, FileType)> f) const {
   return primary_->ForEachFile(root_path, f) && secondary_->ForEachFile(root_path, f);
 }
 
@@ -397,8 +408,8 @@
   return std::unique_ptr<EmptyAssetsProvider>(new EmptyAssetsProvider({}));
 }
 
-std::unique_ptr<AssetsProvider> EmptyAssetsProvider::Create(const std::string& path) {
-  return std::unique_ptr<EmptyAssetsProvider>(new EmptyAssetsProvider(path));
+std::unique_ptr<AssetsProvider> EmptyAssetsProvider::Create(std::string path) {
+  return std::unique_ptr<EmptyAssetsProvider>(new EmptyAssetsProvider(std::move(path)));
 }
 
 std::unique_ptr<Asset> EmptyAssetsProvider::OpenInternal(const std::string& /* path */,
@@ -412,7 +423,7 @@
 
 bool EmptyAssetsProvider::ForEachFile(
     const std::string& /* root_path */,
-    const std::function<void(const StringPiece&, FileType)>& /* f */) const {
+    base::function_ref<void(StringPiece, FileType)> /* f */) const {
   return true;
 }
 
@@ -435,4 +446,4 @@
   return true;
 }
 
-} // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/libs/androidfw/ConfigDescription.cpp b/libs/androidfw/ConfigDescription.cpp
index 19ead95..93a7d17 100644
--- a/libs/androidfw/ConfigDescription.cpp
+++ b/libs/androidfw/ConfigDescription.cpp
@@ -637,7 +637,7 @@
   return true;
 }
 
-bool ConfigDescription::Parse(const StringPiece& str, ConfigDescription* out) {
+bool ConfigDescription::Parse(StringPiece str, ConfigDescription* out) {
   std::vector<std::string> parts = util::SplitAndLowercase(str, '-');
 
   ConfigDescription config;
diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp
index e122d48..8983574 100644
--- a/libs/androidfw/Idmap.cpp
+++ b/libs/androidfw/Idmap.cpp
@@ -201,7 +201,7 @@
       const auto& config = configurations_[value.config_index];
       values_map[config] = value.value;
     }
-    return Result(values_map);
+    return Result(std::move(values_map));
   }
   return {};
 }
@@ -250,8 +250,7 @@
 }
 } // namespace
 
-LoadedIdmap::LoadedIdmap(std::string&& idmap_path,
-                         const Idmap_header* header,
+LoadedIdmap::LoadedIdmap(std::string&& idmap_path, const Idmap_header* header,
                          const Idmap_data_header* data_header,
                          const Idmap_target_entry* target_entries,
                          const Idmap_target_entry_inline* target_inline_entries,
@@ -259,23 +258,21 @@
                          const ConfigDescription* configs,
                          const Idmap_overlay_entry* overlay_entries,
                          std::unique_ptr<ResStringPool>&& string_pool,
-                         std::string_view overlay_apk_path,
-                         std::string_view target_apk_path)
-     : header_(header),
-       data_header_(data_header),
-       target_entries_(target_entries),
-       target_inline_entries_(target_inline_entries),
-       inline_entry_values_(inline_entry_values),
-       configurations_(configs),
-       overlay_entries_(overlay_entries),
-       string_pool_(std::move(string_pool)),
-       idmap_path_(std::move(idmap_path)),
-       overlay_apk_path_(overlay_apk_path),
-       target_apk_path_(target_apk_path),
-       idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {}
+                         std::string_view overlay_apk_path, std::string_view target_apk_path)
+    : header_(header),
+      data_header_(data_header),
+      target_entries_(target_entries),
+      target_inline_entries_(target_inline_entries),
+      inline_entry_values_(inline_entry_values),
+      configurations_(configs),
+      overlay_entries_(overlay_entries),
+      string_pool_(std::move(string_pool)),
+      idmap_path_(std::move(idmap_path)),
+      overlay_apk_path_(overlay_apk_path),
+      target_apk_path_(target_apk_path),
+      idmap_last_mod_time_(getFileModDate(idmap_path_.data())) {}
 
-std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path,
-                                               const StringPiece& idmap_data) {
+std::unique_ptr<LoadedIdmap> LoadedIdmap::Load(StringPiece idmap_path, StringPiece idmap_data) {
   ATRACE_CALL();
   size_t data_size = idmap_data.size();
   auto data_ptr = reinterpret_cast<const uint8_t*>(idmap_data.data());
@@ -365,7 +362,7 @@
 
   // Can't use make_unique because LoadedIdmap constructor is private.
   return std::unique_ptr<LoadedIdmap>(
-      new LoadedIdmap(idmap_path.to_string(), header, data_header, target_entries,
+      new LoadedIdmap(std::string(idmap_path), header, data_header, target_entries,
                       target_inline_entries, target_inline_entry_values, configurations,
                       overlay_entries, std::move(idmap_string_pool), *target_path, *overlay_path));
 }
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 386f718..c0fdfe2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -645,16 +645,16 @@
         }
 
         std::string name;
-        util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
+        util::ReadUtf16StringFromDevice(overlayable->name, std::size(overlayable->name), &name);
         std::string actor;
-        util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);
-
-        if (loaded_package->overlayable_map_.find(name) !=
-            loaded_package->overlayable_map_.end()) {
-          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
+        util::ReadUtf16StringFromDevice(overlayable->actor, std::size(overlayable->actor), &actor);
+        auto [name_to_actor_it, inserted] =
+            loaded_package->overlayable_map_.emplace(std::move(name), std::move(actor));
+        if (!inserted) {
+          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '"
+                     << name_to_actor_it->first << "'.";
           return {};
         }
-        loaded_package->overlayable_map_.emplace(name, actor);
 
         // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
@@ -669,7 +669,6 @@
                 LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
                 return {};
               }
-
               if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
                   < dtohl(policy_header->entry_count)) {
                 LOG(ERROR) <<  "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
@@ -691,8 +690,8 @@
 
               // Add the pairing of overlayable properties and resource ids to the package
               OverlayableInfo overlayable_info {
-                .name = name,
-                .actor = actor,
+                .name = name_to_actor_it->first,
+                .actor = name_to_actor_it->second,
                 .policy_flags = policy_header->policy_flags
               };
               loaded_package->overlayable_infos_.emplace_back(std::move(overlayable_info), std::move(ids));
@@ -736,6 +735,7 @@
         const auto entry_end = entry_begin + dtohl(lib_alias->count);
         std::unordered_set<uint32_t> finalized_ids;
         finalized_ids.reserve(entry_end - entry_begin);
+        loaded_package->alias_id_map_.reserve(entry_end - entry_begin);
         for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
           if (!entry_iter) {
             LOG(ERROR) << "NULL ResTable_staged_alias_entry record??";
@@ -749,13 +749,20 @@
           }
 
           auto staged_id = dtohl(entry_iter->stagedResId);
-          auto [_, success] = loaded_package->alias_id_map_.emplace(staged_id, finalized_id);
-          if (!success) {
+          loaded_package->alias_id_map_.emplace_back(staged_id, finalized_id);
+        }
+
+        std::sort(loaded_package->alias_id_map_.begin(), loaded_package->alias_id_map_.end(),
+            [](auto&& l, auto&& r) { return l.first < r.first; });
+        const auto duplicate_it =
+            std::adjacent_find(loaded_package->alias_id_map_.begin(),
+                               loaded_package->alias_id_map_.end(),
+                               [](auto&& l, auto&& r) { return l.first == r.first; });
+          if (duplicate_it != loaded_package->alias_id_map_.end()) {
             LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
-                                       staged_id);
+                                       duplicate_it->first);
             return {};
           }
-        }
       } break;
 
       default:
diff --git a/libs/androidfw/Locale.cpp b/libs/androidfw/Locale.cpp
index d87a3ce..272a988 100644
--- a/libs/androidfw/Locale.cpp
+++ b/libs/androidfw/Locale.cpp
@@ -66,7 +66,7 @@
   return std::all_of(std::begin(str), std::end(str), ::isdigit);
 }
 
-bool LocaleValue::InitFromFilterString(const StringPiece& str) {
+bool LocaleValue::InitFromFilterString(StringPiece str) {
   // A locale (as specified in the filter) is an underscore separated name such
   // as "en_US", "en_Latn_US", or "en_US_POSIX".
   std::vector<std::string> parts = util::SplitAndLowercase(str, '_');
@@ -132,11 +132,11 @@
   return true;
 }
 
-bool LocaleValue::InitFromBcp47Tag(const StringPiece& bcp47tag) {
+bool LocaleValue::InitFromBcp47Tag(StringPiece bcp47tag) {
   return InitFromBcp47TagImpl(bcp47tag, '-');
 }
 
-bool LocaleValue::InitFromBcp47TagImpl(const StringPiece& bcp47tag, const char separator) {
+bool LocaleValue::InitFromBcp47TagImpl(StringPiece bcp47tag, const char separator) {
   std::vector<std::string> subtags = util::SplitAndLowercase(bcp47tag, separator);
   if (subtags.size() == 1) {
     set_language(subtags[0].c_str());
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 267190a..31516dc 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -33,7 +33,9 @@
 #include <type_traits>
 #include <vector>
 
+#include <android-base/file.h>
 #include <android-base/macros.h>
+#include <android-base/utf8.h>
 #include <androidfw/ByteBucketArray.h>
 #include <androidfw/ResourceTypes.h>
 #include <androidfw/TypeWrappers.h>
@@ -236,12 +238,23 @@
 }
 
 bool IsFabricatedOverlay(const std::string& path) {
-  std::ifstream fin(path);
-  uint32_t magic;
-  if (fin.read(reinterpret_cast<char*>(&magic), sizeof(uint32_t))) {
-    return magic == kFabricatedOverlayMagic;
+  return IsFabricatedOverlay(path.c_str());
+}
+
+bool IsFabricatedOverlay(const char* path) {
+  auto fd = base::unique_fd(base::utf8::open(path, O_RDONLY|O_CLOEXEC));
+  if (fd < 0) {
+    return false;
   }
-  return false;
+  return IsFabricatedOverlay(fd);
+}
+
+bool IsFabricatedOverlay(base::borrowed_fd fd) {
+  uint32_t magic;
+  if (!base::ReadFullyAtOffset(fd, &magic, sizeof(magic), 0)) {
+    return false;
+  }
+  return magic == kFabricatedOverlayMagic;
 }
 
 static bool assertIdmapHeader(const void* idmap, size_t size) {
@@ -6988,11 +7001,10 @@
 DynamicRefTable::DynamicRefTable() : DynamicRefTable(0, false) {}
 
 DynamicRefTable::DynamicRefTable(uint8_t packageId, bool appAsLib)
-    : mAssignedPackageId(packageId)
+    : mLookupTable()
+    , mAssignedPackageId(packageId)
     , mAppAsLib(appAsLib)
 {
-    memset(mLookupTable, 0, sizeof(mLookupTable));
-
     // Reserved package ids
     mLookupTable[APP_PACKAGE_ID] = APP_PACKAGE_ID;
     mLookupTable[SYS_PACKAGE_ID] = SYS_PACKAGE_ID;
@@ -7073,10 +7085,6 @@
     mLookupTable[buildPackageId] = runtimePackageId;
 }
 
-void DynamicRefTable::addAlias(uint32_t stagedId, uint32_t finalizedId) {
-  mAliasId[stagedId] = finalizedId;
-}
-
 status_t DynamicRefTable::lookupResourceId(uint32_t* resId) const {
     uint32_t res = *resId;
     size_t packageId = Res_GETPACKAGE(res) + 1;
@@ -7086,11 +7094,12 @@
         return NO_ERROR;
     }
 
-    auto alias_id = mAliasId.find(res);
-    if (alias_id != mAliasId.end()) {
+    const auto alias_it = std::lower_bound(mAliasId.begin(), mAliasId.end(), res,
+        [](const AliasMap::value_type& pair, uint32_t val) { return pair.first < val; });
+    if (alias_it != mAliasId.end() && alias_it->first == res) {
       // Rewrite the resource id to its alias resource id. Since the alias resource id is a
       // compile-time id, it still needs to be resolved further.
-      res = alias_id->second;
+      res = alias_it->second;
     }
 
     if (packageId == SYS_PACKAGE_ID || (packageId == APP_PACKAGE_ID && !mAppAsLib)) {
diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp
index 87fb2c0..ccb6156 100644
--- a/libs/androidfw/ResourceUtils.cpp
+++ b/libs/androidfw/ResourceUtils.cpp
@@ -18,7 +18,7 @@
 
 namespace android {
 
-bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
+bool ExtractResourceName(StringPiece str, StringPiece* out_package, StringPiece* out_type,
                          StringPiece* out_entry) {
   *out_package = "";
   *out_type = "";
@@ -33,16 +33,16 @@
   while (current != end) {
     if (out_type->size() == 0 && *current == '/') {
       has_type_separator = true;
-      out_type->assign(start, current - start);
+      *out_type = StringPiece(start, current - start);
       start = current + 1;
     } else if (out_package->size() == 0 && *current == ':') {
       has_package_separator = true;
-      out_package->assign(start, current - start);
+      *out_package = StringPiece(start, current - start);
       start = current + 1;
     }
     current++;
   }
-  out_entry->assign(start, end - start);
+  *out_entry = StringPiece(start, end - start);
 
   return !(has_package_separator && out_package->empty()) &&
          !(has_type_separator && out_type->empty());
@@ -50,7 +50,7 @@
 
 base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
     const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
-    const StringPiece& package_name) {
+    StringPiece package_name) {
   AssetManager2::ResourceName name{
     .package = package_name.data(),
     .package_len = package_name.size(),
diff --git a/libs/androidfw/StringPool.cpp b/libs/androidfw/StringPool.cpp
index b59e906..1cb8df3 100644
--- a/libs/androidfw/StringPool.cpp
+++ b/libs/androidfw/StringPool.cpp
@@ -161,16 +161,15 @@
   return entry_->context;
 }
 
-StringPool::Ref StringPool::MakeRef(const StringPiece& str) {
+StringPool::Ref StringPool::MakeRef(StringPiece str) {
   return MakeRefImpl(str, Context{}, true);
 }
 
-StringPool::Ref StringPool::MakeRef(const StringPiece& str, const Context& context) {
+StringPool::Ref StringPool::MakeRef(StringPiece str, const Context& context) {
   return MakeRefImpl(str, context, true);
 }
 
-StringPool::Ref StringPool::MakeRefImpl(const StringPiece& str, const Context& context,
-                                        bool unique) {
+StringPool::Ref StringPool::MakeRefImpl(StringPiece str, const Context& context, bool unique) {
   if (unique) {
     auto range = indexed_strings_.equal_range(str);
     for (auto iter = range.first; iter != range.second; ++iter) {
@@ -181,7 +180,7 @@
   }
 
   std::unique_ptr<Entry> entry(new Entry());
-  entry->value = str.to_string();
+  entry->value = std::string(str);
   entry->context = context;
   entry->index_ = strings_.size();
   entry->ref_ = 0;
diff --git a/libs/androidfw/Util.cpp b/libs/androidfw/Util.cpp
index 52ad0dc..be55fe8 100644
--- a/libs/androidfw/Util.cpp
+++ b/libs/androidfw/Util.cpp
@@ -42,7 +42,7 @@
   }
 }
 
-std::u16string Utf8ToUtf16(const StringPiece& utf8) {
+std::u16string Utf8ToUtf16(StringPiece utf8) {
   ssize_t utf16_length =
       utf8_to_utf16_length(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
   if (utf16_length <= 0) {
@@ -56,7 +56,7 @@
   return utf16;
 }
 
-std::string Utf16ToUtf8(const StringPiece16& utf16) {
+std::string Utf16ToUtf8(StringPiece16 utf16) {
   ssize_t utf8_length = utf16_to_utf8_length(utf16.data(), utf16.length());
   if (utf8_length <= 0) {
     return {};
@@ -68,7 +68,7 @@
   return utf8;
 }
 
-std::string Utf8ToModifiedUtf8(const std::string& utf8) {
+std::string Utf8ToModifiedUtf8(std::string_view utf8) {
   // Java uses Modified UTF-8 which only supports the 1, 2, and 3 byte formats of UTF-8. To encode
   // 4 byte UTF-8 codepoints, Modified UTF-8 allows the use of surrogate pairs in the same format
   // of CESU-8 surrogate pairs. Calculate the size of the utf8 string with all 4 byte UTF-8
@@ -86,7 +86,7 @@
 
   // Early out if no 4 byte codepoints are found
   if (size == modified_size) {
-    return utf8;
+    return std::string(utf8);
   }
 
   std::string output;
@@ -115,7 +115,7 @@
   return output;
 }
 
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8) {
+std::string ModifiedUtf8ToUtf8(std::string_view modified_utf8) {
   // The UTF-8 representation will have a byte length less than or equal to the Modified UTF-8
   // representation.
   std::string output;
@@ -170,30 +170,28 @@
   return output;
 }
 
-static std::vector<std::string> SplitAndTransform(
-    const StringPiece& str, char sep, const std::function<char(char)>& f) {
+template <class Func>
+static std::vector<std::string> SplitAndTransform(StringPiece str, char sep, Func&& f) {
   std::vector<std::string> parts;
   const StringPiece::const_iterator end = std::end(str);
   StringPiece::const_iterator start = std::begin(str);
   StringPiece::const_iterator current;
   do {
     current = std::find(start, end, sep);
-    parts.emplace_back(str.substr(start, current).to_string());
-    if (f) {
-      std::string& part = parts.back();
-      std::transform(part.begin(), part.end(), part.begin(), f);
-    }
+    parts.emplace_back(StringPiece(start, current - start));
+    std::string& part = parts.back();
+    std::transform(part.begin(), part.end(), part.begin(), f);
     start = current + 1;
   } while (current != end);
   return parts;
 }
 
-std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep) {
-  return SplitAndTransform(str, sep, ::tolower);
+std::vector<std::string> SplitAndLowercase(StringPiece str, char sep) {
+  return SplitAndTransform(str, sep, [](char c) { return ::tolower(c); });
 }
 
 std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer) {
-  std::unique_ptr<uint8_t[]> data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
+  auto data = std::unique_ptr<uint8_t[]>(new uint8_t[buffer.size()]);
   uint8_t* p = data.get();
   for (const auto& block : buffer) {
     memcpy(p, block.buffer.get(), block.size);
@@ -211,7 +209,7 @@
 
 std::string GetString(const android::ResStringPool& pool, size_t idx) {
   if (auto str = pool.string8At(idx); str.ok()) {
-    return ModifiedUtf8ToUtf8(str->to_string());
+    return ModifiedUtf8ToUtf8(*str);
   }
   return Utf16ToUtf8(GetString16(pool, idx));
 }
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index 1bde792..f10cb9b 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -17,6 +17,7 @@
 #ifndef ANDROIDFW_ASSETMANAGER2_H_
 #define ANDROIDFW_ASSETMANAGER2_H_
 
+#include "android-base/function_ref.h"
 #include "android-base/macros.h"
 
 #include <array>
@@ -104,7 +105,7 @@
   // new resource IDs.
   bool SetApkAssets(std::vector<const ApkAssets*> apk_assets, bool invalidate_caches = true);
 
-  inline const std::vector<const ApkAssets*> GetApkAssets() const {
+  inline const std::vector<const ApkAssets*>& GetApkAssets() const {
     return apk_assets_;
   }
 
@@ -124,8 +125,7 @@
   uint8_t GetAssignedPackageId(const LoadedPackage* package) const;
 
   // Returns a string representation of the overlayable API of a package.
-  bool GetOverlayablesToString(const android::StringPiece& package_name,
-                               std::string* out) const;
+  bool GetOverlayablesToString(android::StringPiece package_name, std::string* out) const;
 
   const std::unordered_map<std::string, std::string>* GetOverlayableMapForPackage(
       uint32_t package_id) const;
@@ -321,17 +321,8 @@
   // Creates a new Theme from this AssetManager.
   std::unique_ptr<Theme> NewTheme();
 
-  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_) {
-      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;
-      }
-    }
-  }
+  void ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+                      package_property_t excluded_property_flags = 0U) const;
 
   void DumpToLog() const;
 
@@ -572,6 +563,7 @@
   AssetManager2* asset_manager_ = nullptr;
   uint32_t type_spec_flags_ = 0u;
 
+  std::vector<uint32_t> keys_;
   std::vector<Entry> entries_;
 };
 
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index 966ec74..d33c325 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <string>
 
+#include "android-base/function_ref.h"
 #include "android-base/macros.h"
 #include "android-base/unique_fd.h"
 
@@ -46,7 +47,7 @@
   // Iterate over all files and directories provided by the interface. The order of iteration is
   // stable.
   virtual bool ForEachFile(const std::string& path,
-                           const std::function<void(const StringPiece&, FileType)>& f) const = 0;
+                           base::function_ref<void(StringPiece, FileType)> f) const = 0;
 
   // Retrieves the path to the contents of the AssetsProvider on disk. The path could represent an
   // APk, a directory, or some other file type.
@@ -80,8 +81,8 @@
 
 // Supplies assets from a zip archive.
 struct ZipAssetsProvider : public AssetsProvider {
-  static std::unique_ptr<ZipAssetsProvider> Create(std::string path,
-                                                   package_property_t flags);
+  static std::unique_ptr<ZipAssetsProvider> Create(std::string path, package_property_t flags,
+                                                   base::unique_fd fd = {});
 
   static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
                                                    std::string friendly_name,
@@ -90,7 +91,7 @@
                                                    off64_t len = kUnknownLength);
 
   bool ForEachFile(const std::string& root_path,
-                   const std::function<void(const StringPiece&, FileType)>& f) const override;
+                   base::function_ref<void(StringPiece, FileType)> f) const override;
 
   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
@@ -108,7 +109,12 @@
                     time_t last_mod_time);
 
   struct PathOrDebugName {
-    PathOrDebugName(std::string&& value, bool is_path);
+    static PathOrDebugName Path(std::string value) {
+      return {std::move(value), true};
+    }
+    static PathOrDebugName DebugName(std::string value) {
+      return {std::move(value), false};
+    }
 
     // Retrieves the path or null if this class represents a debug name.
     WARN_UNUSED const std::string* GetPath() const;
@@ -117,11 +123,16 @@
     WARN_UNUSED const std::string& GetDebugName() const;
 
    private:
+    PathOrDebugName(std::string value, bool is_path) : value_(std::move(value)), is_path_(is_path) {
+    }
     std::string value_;
     bool is_path_;
   };
 
-  std::unique_ptr<ZipArchive, void (*)(ZipArchive*)> zip_handle_;
+  struct ZipCloser {
+    void operator()(ZipArchive* a) const;
+  };
+  std::unique_ptr<ZipArchive, ZipCloser> zip_handle_;
   PathOrDebugName name_;
   package_property_t flags_;
   time_t last_mod_time_;
@@ -132,7 +143,7 @@
   static std::unique_ptr<DirectoryAssetsProvider> Create(std::string root_dir);
 
   bool ForEachFile(const std::string& path,
-                   const std::function<void(const StringPiece&, FileType)>& f) const override;
+                   base::function_ref<void(StringPiece, FileType)> f) const override;
 
   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
@@ -157,7 +168,7 @@
                                                 std::unique_ptr<AssetsProvider>&& secondary);
 
   bool ForEachFile(const std::string& root_path,
-                   const std::function<void(const StringPiece&, FileType)>& f) const override;
+                   base::function_ref<void(StringPiece, FileType)> f) const override;
 
   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
@@ -181,10 +192,10 @@
 // Does not provide any assets.
 struct EmptyAssetsProvider : public AssetsProvider {
   static std::unique_ptr<AssetsProvider> Create();
-  static std::unique_ptr<AssetsProvider> Create(const std::string& path);
+  static std::unique_ptr<AssetsProvider> Create(std::string path);
 
   bool ForEachFile(const std::string& path,
-                  const std::function<void(const StringPiece&, FileType)>& f) const override;
+                   base::function_ref<void(StringPiece, FileType)> f) const override;
 
   WARN_UNUSED std::optional<std::string_view> GetPath() const override;
   WARN_UNUSED const std::string& GetDebugName() const override;
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index 949c9445..ca0a9ed 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -17,6 +17,7 @@
 #ifndef __BYTE_BUCKET_ARRAY_H
 #define __BYTE_BUCKET_ARRAY_H
 
+#include <algorithm>
 #include <cstdint>
 #include <cstring>
 
@@ -31,14 +32,16 @@
 template <typename T>
 class ByteBucketArray {
  public:
-  ByteBucketArray() : default_() { memset(buckets_, 0, sizeof(buckets_)); }
+  ByteBucketArray() {
+    memset(buckets_, 0, sizeof(buckets_));
+  }
 
   ~ByteBucketArray() {
-    for (size_t i = 0; i < kNumBuckets; i++) {
-      if (buckets_[i] != NULL) {
-        delete[] buckets_[i];
-      }
-    }
+    deleteBuckets();
+  }
+
+  void clear() {
+    deleteBuckets();
     memset(buckets_, 0, sizeof(buckets_));
   }
 
@@ -53,7 +56,7 @@
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
     T* bucket = buckets_[bucket_index];
-    if (bucket == NULL) {
+    if (bucket == nullptr) {
       return default_;
     }
     return bucket[0x0f & static_cast<uint8_t>(index)];
@@ -64,9 +67,9 @@
                           << ") with size=" << size();
 
     uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
-    T* bucket = buckets_[bucket_index];
-    if (bucket == NULL) {
-      bucket = buckets_[bucket_index] = new T[kBucketSize]();
+    T*& bucket = buckets_[bucket_index];
+    if (bucket == nullptr) {
+      bucket = new T[kBucketSize]();
     }
     return bucket[0x0f & static_cast<uint8_t>(index)];
   }
@@ -80,11 +83,44 @@
     return true;
   }
 
+  template <class Func>
+  void forEachItem(Func f) {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      const auto bucket = buckets_[i];
+      if (bucket != nullptr) {
+        for (size_t j = 0; j < kBucketSize; j++) {
+          f((i << 4) | j, bucket[j]);
+        }
+      }
+    }
+  }
+
+  template <class Func>
+  void trimBuckets(Func isEmptyFunc) {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      const auto bucket = buckets_[i];
+      if (bucket != nullptr) {
+        if (std::all_of(bucket, bucket + kBucketSize, isEmptyFunc)) {
+          delete[] bucket;
+          buckets_[i] = nullptr;
+        }
+      }
+    }
+  }
+
  private:
   enum { kNumBuckets = 16, kBucketSize = 16 };
 
+  void deleteBuckets() {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      if (buckets_[i] != nullptr) {
+        delete[] buckets_[i];
+      }
+    }
+  }
+
   T* buckets_[kNumBuckets];
-  T default_;
+  static inline const T default_ = {};
 };
 
 }  // namespace android
diff --git a/libs/androidfw/include/androidfw/ConfigDescription.h b/libs/androidfw/include/androidfw/ConfigDescription.h
index 61d10cd..71087cd 100644
--- a/libs/androidfw/include/androidfw/ConfigDescription.h
+++ b/libs/androidfw/include/androidfw/ConfigDescription.h
@@ -72,7 +72,7 @@
    * The resulting configuration has the appropriate sdkVersion defined
    * for backwards compatibility.
    */
-  static bool Parse(const android::StringPiece& str, ConfigDescription* out = nullptr);
+  static bool Parse(android::StringPiece str, ConfigDescription* out = nullptr);
 
   /**
    * If the configuration uses an axis that was added after
diff --git a/libs/androidfw/include/androidfw/IDiagnostics.h b/libs/androidfw/include/androidfw/IDiagnostics.h
index 273b05a..4d5844e 100644
--- a/libs/androidfw/include/androidfw/IDiagnostics.h
+++ b/libs/androidfw/include/androidfw/IDiagnostics.h
@@ -35,7 +35,7 @@
  public:
   DiagMessage() = default;
 
-  explicit DiagMessage(const android::StringPiece& src) : source_(src) {
+  explicit DiagMessage(android::StringPiece src) : source_(src) {
   }
 
   explicit DiagMessage(const Source& src) : source_(src) {
@@ -61,7 +61,7 @@
 
 template <>
 inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
-  message_ << android::StringPiece16(value);
+  message_ << value;
   return *this;
 }
 
diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h
index a1cbbbf..6068912 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -93,8 +93,8 @@
    public:
     Result() = default;
     explicit Result(uint32_t value) : data_(value) {};
-    explicit Result(const std::map<ConfigDescription, Res_value> &value)
-        : data_(value) { };
+    explicit Result(std::map<ConfigDescription, Res_value> value) : data_(std::move(value)) {
+    }
 
     // Returns `true` if the resource is overlaid.
     explicit operator bool() const {
@@ -157,8 +157,7 @@
 class LoadedIdmap {
  public:
   // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed.
-  static std::unique_ptr<LoadedIdmap> Load(const StringPiece& idmap_path,
-                                           const StringPiece& idmap_data);
+  static std::unique_ptr<LoadedIdmap> Load(StringPiece idmap_path, StringPiece idmap_data);
 
   // Returns the path to the IDMAP.
   std::string_view IdmapPath() const {
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 79d96282..4d12885 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -99,8 +99,8 @@
 };
 
 struct OverlayableInfo {
-  std::string name;
-  std::string actor;
+  std::string_view name;
+  std::string_view actor;
   uint32_t policy_flags;
 };
 
@@ -275,7 +275,7 @@
     return overlayable_map_;
   }
 
-  const std::map<uint32_t, uint32_t>& GetAliasResourceIdMap() const {
+  const std::vector<std::pair<uint32_t, uint32_t>>& GetAliasResourceIdMap() const {
     return alias_id_map_;
   }
 
@@ -295,8 +295,8 @@
   std::unordered_map<uint8_t, TypeSpec> type_specs_;
   ByteBucketArray<uint32_t> resource_ids_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
-  std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
-  std::map<uint32_t, uint32_t> alias_id_map_;
+  std::vector<std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+  std::vector<std::pair<uint32_t, uint32_t>> alias_id_map_;
 
   // A map of overlayable name to actor
   std::unordered_map<std::string, std::string> overlayable_map_;
diff --git a/libs/androidfw/include/androidfw/Locale.h b/libs/androidfw/include/androidfw/Locale.h
index 484ed79..8934bed 100644
--- a/libs/androidfw/include/androidfw/Locale.h
+++ b/libs/androidfw/include/androidfw/Locale.h
@@ -39,10 +39,10 @@
   /**
    * Initialize this LocaleValue from a config string.
    */
-  bool InitFromFilterString(const android::StringPiece& config);
+  bool InitFromFilterString(android::StringPiece config);
 
   // Initializes this LocaleValue from a BCP-47 locale tag.
-  bool InitFromBcp47Tag(const android::StringPiece& bcp47tag);
+  bool InitFromBcp47Tag(android::StringPiece bcp47tag);
 
   /**
    * Initialize this LocaleValue from parts of a vector.
@@ -70,7 +70,7 @@
   inline bool operator>(const LocaleValue& o) const;
 
  private:
-  bool InitFromBcp47TagImpl(const android::StringPiece& bcp47tag, const char separator);
+  bool InitFromBcp47TagImpl(android::StringPiece bcp47tag, const char separator);
 
   void set_language(const char* language);
   void set_region(const char* language);
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index c740832..52321da 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -21,6 +21,7 @@
 #define _LIBS_UTILS_RESOURCE_TYPES_H
 
 #include <android-base/expected.h>
+#include <android-base/unique_fd.h>
 
 #include <androidfw/Asset.h>
 #include <androidfw/Errors.h>
@@ -58,6 +59,8 @@
 
 // Returns whether or not the path represents a fabricated overlay.
 bool IsFabricatedOverlay(const std::string& path);
+bool IsFabricatedOverlay(const char* path);
+bool IsFabricatedOverlay(android::base::borrowed_fd fd);
 
 /**
  * In C++11, char16_t is defined as *at least* 16 bits. We do a lot of
@@ -1830,6 +1833,28 @@
   return first;
 }
 
+using ResourceId = uint32_t;  // 0xpptteeee
+
+using DataType = uint8_t;    // Res_value::dataType
+using DataValue = uint32_t;  // Res_value::data
+
+struct OverlayManifestInfo {
+  std::string package_name;     // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string name;             // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_package;   // NOLINT(misc-non-private-member-variables-in-classes)
+  std::string target_name;      // NOLINT(misc-non-private-member-variables-in-classes)
+  ResourceId resource_mapping;  // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+struct FabricatedOverlayEntryParameters {
+  std::string resource_name;
+  DataType data_type;
+  DataValue data_value;
+  std::string data_string_value;
+  std::optional<android::base::borrowed_fd> data_binary_value;
+  std::string configuration;
+};
+
 class AssetManager2;
 
 /**
@@ -1860,7 +1885,10 @@
 
     void addMapping(uint8_t buildPackageId, uint8_t runtimePackageId);
 
-    void addAlias(uint32_t stagedId, uint32_t finalizedId);
+    using AliasMap = std::vector<std::pair<uint32_t, uint32_t>>;
+    void setAliases(AliasMap aliases) {
+        mAliasId = std::move(aliases);
+    }
 
     // Returns whether or not the value must be looked up.
     bool requiresLookup(const Res_value* value) const;
@@ -1874,12 +1902,12 @@
         return mEntries;
     }
 
-private:
-    uint8_t                         mAssignedPackageId;
-    uint8_t                         mLookupTable[256];
-    KeyedVector<String16, uint8_t>  mEntries;
-    bool                            mAppAsLib;
-    std::map<uint32_t, uint32_t>    mAliasId;
+   private:
+    uint8_t mLookupTable[256];
+    uint8_t mAssignedPackageId;
+    bool mAppAsLib;
+    KeyedVector<String16, uint8_t> mEntries;
+    AliasMap mAliasId;
 };
 
 bool U16StringToInt(const char16_t* s, size_t len, Res_value* outValue);
diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h
index bd1c440..2d90a52 100644
--- a/libs/androidfw/include/androidfw/ResourceUtils.h
+++ b/libs/androidfw/include/androidfw/ResourceUtils.h
@@ -25,14 +25,14 @@
 // Extracts the package, type, and name from a string of the format: [[package:]type/]name
 // Validation must be performed on each extracted piece.
 // Returns false if there was a syntax error.
-bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type,
+bool ExtractResourceName(StringPiece str, StringPiece* out_package, StringPiece* out_type,
                          StringPiece* out_entry);
 
 // Convert a type_string_ref, entry_string_ref, and package to AssetManager2::ResourceName.
 // Useful for getting resource name without re-running AssetManager2::FindEntry searches.
 base::expected<AssetManager2::ResourceName, NullOrIOError> ToResourceName(
     const StringPoolRef& type_string_ref, const StringPoolRef& entry_string_ref,
-    const StringPiece& package_name);
+    StringPiece package_name);
 
 // Formats a ResourceName to "package:type/entry_name".
 std::string ToFormattedResourceString(const AssetManager2::ResourceName& resource_name);
diff --git a/libs/androidfw/include/androidfw/Source.h b/libs/androidfw/include/androidfw/Source.h
index 0421a91..ddc9ba4 100644
--- a/libs/androidfw/include/androidfw/Source.h
+++ b/libs/androidfw/include/androidfw/Source.h
@@ -34,15 +34,14 @@
 
   Source() = default;
 
-  inline Source(const android::StringPiece& path) : path(path.to_string()) {  // NOLINT(implicit)
+  inline Source(android::StringPiece path) : path(path) {  // NOLINT(implicit)
   }
 
-  inline Source(const android::StringPiece& path, const android::StringPiece& archive)
-      : path(path.to_string()), archive(archive.to_string()) {
+  inline Source(android::StringPiece path, android::StringPiece archive)
+      : path(path), archive(archive) {
   }
 
-  inline Source(const android::StringPiece& path, size_t line)
-      : path(path.to_string()), line(line) {
+  inline Source(android::StringPiece path, size_t line) : path(path), line(line) {
   }
 
   inline Source WithLine(size_t line) const {
diff --git a/libs/androidfw/include/androidfw/StringPiece.h b/libs/androidfw/include/androidfw/StringPiece.h
index fac2fa4..f6cc64e 100644
--- a/libs/androidfw/include/androidfw/StringPiece.h
+++ b/libs/androidfw/include/androidfw/StringPiece.h
@@ -19,307 +19,37 @@
 
 #include <ostream>
 #include <string>
+#include <string_view>
 
-#include "utils/JenkinsHash.h"
 #include "utils/Unicode.h"
 
 namespace android {
 
-// Read only wrapper around basic C strings. Prevents excessive copying.
-// StringPiece does not own the data it is wrapping. The lifetime of the underlying
-// data must outlive this StringPiece.
-//
-// WARNING: When creating from std::basic_string<>, moving the original
-// std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
-// BasicStringPiece<> should only be used transitively.
-//
-// NOTE: When creating an std::pair<StringPiece, T> using std::make_pair(),
-// passing an std::string will first copy the string, then create a StringPiece
-// on the copy, which is then immediately destroyed.
-// Instead, create a StringPiece explicitly:
-//
-// std::string my_string = "foo";
-// std::make_pair<StringPiece, T>(StringPiece(my_string), ...);
-template <typename TChar>
-class BasicStringPiece {
- public:
-  using const_iterator = const TChar*;
-  using difference_type = size_t;
-  using size_type = size_t;
-
-  // End of string marker.
-  constexpr static const size_t npos = static_cast<size_t>(-1);
-
-  BasicStringPiece();
-  BasicStringPiece(const BasicStringPiece<TChar>& str);
-  BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(google-explicit-constructor)
-  BasicStringPiece(const TChar* str);                     // NOLINT(google-explicit-constructor)
-  BasicStringPiece(const TChar* str, size_t len);
-
-  BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
-  BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
-
-  BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
-  BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
-                                 BasicStringPiece<TChar>::const_iterator end) const;
-
-  const TChar* data() const;
-  size_t length() const;
-  size_t size() const;
-  bool empty() const;
-  std::basic_string<TChar> to_string() const;
-
-  bool contains(const BasicStringPiece<TChar>& rhs) const;
-  int compare(const BasicStringPiece<TChar>& rhs) const;
-  bool operator<(const BasicStringPiece<TChar>& rhs) const;
-  bool operator>(const BasicStringPiece<TChar>& rhs) const;
-  bool operator==(const BasicStringPiece<TChar>& rhs) const;
-  bool operator!=(const BasicStringPiece<TChar>& rhs) const;
-
-  const_iterator begin() const;
-  const_iterator end() const;
-
- private:
-  const TChar* data_;
-  size_t length_;
-};
+template <class T>
+using BasicStringPiece = std::basic_string_view<T>;
 
 using StringPiece = BasicStringPiece<char>;
 using StringPiece16 = BasicStringPiece<char16_t>;
 
-//
-// BasicStringPiece implementation.
-//
-
-template <typename TChar>
-constexpr const size_t BasicStringPiece<TChar>::npos;
-
-template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {}
-
-template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str)
-    : data_(str.data_), length_(str.length_) {}
-
-template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str)
-    : data_(str.data()), length_(str.length()) {}
-
-template <>
-inline BasicStringPiece<char>::BasicStringPiece(const char* str)
-    : data_(str), length_(str != nullptr ? strlen(str) : 0) {}
-
-template <>
-inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str)
-    : data_(str), length_(str != nullptr ? strlen16(str) : 0) {}
-
-template <typename TChar>
-inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len)
-    : data_(str), length_(len) {}
-
-template <typename TChar>
-inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
-    const BasicStringPiece<TChar>& rhs) {
-  data_ = rhs.data_;
-  length_ = rhs.length_;
-  return *this;
-}
-
-template <typename TChar>
-inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
-  data_ = str;
-  length_ = len;
-  return *this;
-}
-
-template <typename TChar>
-inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
-  if (len == npos) {
-    len = length_ - start;
-  }
-
-  if (start > length_ || start + len > length_) {
-    return BasicStringPiece<TChar>();
-  }
-  return BasicStringPiece<TChar>(data_ + start, len);
-}
-
-template <typename TChar>
-inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
-    BasicStringPiece<TChar>::const_iterator begin,
-    BasicStringPiece<TChar>::const_iterator end) const {
-  return BasicStringPiece<TChar>(begin, end - begin);
-}
-
-template <typename TChar>
-inline const TChar* BasicStringPiece<TChar>::data() const {
-  return data_;
-}
-
-template <typename TChar>
-inline size_t BasicStringPiece<TChar>::length() const {
-  return length_;
-}
-
-template <typename TChar>
-inline size_t BasicStringPiece<TChar>::size() const {
-  return length_;
-}
-
-template <typename TChar>
-inline bool BasicStringPiece<TChar>::empty() const {
-  return length_ == 0;
-}
-
-template <typename TChar>
-inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const {
-  return std::basic_string<TChar>(data_, length_);
-}
-
-template <>
-inline bool BasicStringPiece<char>::contains(const BasicStringPiece<char>& rhs) const {
-  if (!data_ || !rhs.data_) {
-    return false;
-  }
-  if (rhs.length_ > length_) {
-    return false;
-  }
-  return strstr(data_, rhs.data_) != nullptr;
-}
-
-template <>
-inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
-  const char nullStr = '\0';
-  const char* b1 = data_ != nullptr ? data_ : &nullStr;
-  const char* e1 = b1 + length_;
-  const char* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
-  const char* e2 = b2 + rhs.length_;
-
-  while (b1 < e1 && b2 < e2) {
-    const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
-    if (d) {
-      return d;
-    }
-  }
-  return static_cast<int>(length_ - rhs.length_);
-}
-
-inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
-  const ssize_t result_len = utf16_to_utf8_length(str.data(), str.size());
-  if (result_len < 0) {
-    // Empty string.
-    return out;
-  }
-
-  std::string result;
-  result.resize(static_cast<size_t>(result_len));
-  utf16_to_utf8(str.data(), str.length(), &*result.begin(), static_cast<size_t>(result_len) + 1);
-  return out << result;
-}
-
-template <>
-inline bool BasicStringPiece<char16_t>::contains(const BasicStringPiece<char16_t>& rhs) const {
-  if (!data_ || !rhs.data_) {
-    return false;
-  }
-  if (rhs.length_ > length_) {
-    return false;
-  }
-  return strstr16(data_, rhs.data_) != nullptr;
-}
-
-template <>
-inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
-  const char16_t nullStr = u'\0';
-  const char16_t* b1 = data_ != nullptr ? data_ : &nullStr;
-  const char16_t* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
-  return strzcmp16(b1, length_, b2, rhs.length_);
-}
-
-template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
-  return compare(rhs) < 0;
-}
-
-template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
-  return compare(rhs) > 0;
-}
-
-template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
-  return compare(rhs) == 0;
-}
-
-template <typename TChar>
-inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
-  return compare(rhs) != 0;
-}
-
-template <typename TChar>
-inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
-  return data_;
-}
-
-template <typename TChar>
-inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
-  return data_ + length_;
-}
-
-template <typename TChar>
-inline bool operator==(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
-  return BasicStringPiece<TChar>(lhs) == rhs;
-}
-
-template <typename TChar>
-inline bool operator!=(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
-  return BasicStringPiece<TChar>(lhs) != rhs;
-}
-
-inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
-  return out.write(str.data(), str.size());
-}
-
-template <typename TChar>
-inline ::std::basic_string<TChar>& operator+=(::std::basic_string<TChar>& lhs,
-                                              const BasicStringPiece<TChar>& rhs) {
-  return lhs.append(rhs.data(), rhs.size());
-}
-
-template <typename TChar>
-inline bool operator==(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
-  return BasicStringPiece<TChar>(lhs) == rhs;
-}
-
-template <typename TChar>
-inline bool operator!=(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
-  return BasicStringPiece<TChar>(lhs) != rhs;
-}
-
 }  // namespace android
 
-inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
+namespace std {
+
+inline ::std::ostream& operator<<(::std::ostream& out, ::std::u16string_view str) {
   ssize_t utf8_len = utf16_to_utf8_length(str.data(), str.size());
   if (utf8_len < 0) {
-    return out << "???";
+    return out;  // empty
   }
 
   std::string utf8;
   utf8.resize(static_cast<size_t>(utf8_len));
-  utf16_to_utf8(str.data(), str.size(), &*utf8.begin(), utf8_len + 1);
+  utf16_to_utf8(str.data(), str.size(), utf8.data(), utf8_len + 1);
   return out << utf8;
 }
 
-namespace std {
-
-template <typename TChar>
-struct hash<android::BasicStringPiece<TChar>> {
-  size_t operator()(const android::BasicStringPiece<TChar>& str) const {
-    uint32_t hashCode = android::JenkinsHashMixBytes(
-        0, reinterpret_cast<const uint8_t*>(str.data()), sizeof(TChar) * str.size());
-    return static_cast<size_t>(hashCode);
-  }
-};
+inline ::std::ostream& operator<<(::std::ostream& out, const ::std::u16string& str) {
+  return out << std::u16string_view(str);
+}
 
 }  // namespace std
 
diff --git a/libs/androidfw/include/androidfw/StringPool.h b/libs/androidfw/include/androidfw/StringPool.h
index 25174d8..0190ab5 100644
--- a/libs/androidfw/include/androidfw/StringPool.h
+++ b/libs/androidfw/include/androidfw/StringPool.h
@@ -167,11 +167,11 @@
 
   // Adds a string to the pool, unless it already exists. Returns a reference to the string in the
   // pool.
-  Ref MakeRef(const android::StringPiece& str);
+  Ref MakeRef(android::StringPiece str);
 
   // Adds a string to the pool, unless it already exists, with a context object that can be used
   // when sorting the string pool. Returns a reference to the string in the pool.
-  Ref MakeRef(const android::StringPiece& str, const Context& context);
+  Ref MakeRef(android::StringPiece str, const Context& context);
 
   // Adds a string from another string pool. Returns a reference to the string in the string pool.
   Ref MakeRef(const Ref& ref);
@@ -215,7 +215,7 @@
 
   static bool Flatten(BigBuffer* out, const StringPool& pool, bool utf8, IDiagnostics* diag);
 
-  Ref MakeRefImpl(const android::StringPiece& str, const Context& context, bool unique);
+  Ref MakeRefImpl(android::StringPiece str, const Context& context, bool unique);
   void ReAssignIndices();
 
   std::vector<std::unique_ptr<Entry>> strings_;
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
index 1bbc7f5..a188abb 100644
--- a/libs/androidfw/include/androidfw/Util.h
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -22,7 +22,6 @@
 
 #include <cstdlib>
 #include <memory>
-#include <sstream>
 #include <vector>
 
 #include "androidfw/BigBuffer.h"
@@ -33,7 +32,14 @@
 #ifdef __ANDROID__
 #define ANDROID_LOG(x) LOG(x)
 #else
-#define ANDROID_LOG(x) std::stringstream()
+namespace android {
+// No default logging for aapt2, as it's too noisy for a command line dev tool.
+struct NullLogger {
+  template <class T>
+  friend const NullLogger& operator<<(const NullLogger& l, const T&) { return l; }
+};
+}
+#define ANDROID_LOG(x) (android::NullLogger{})
 #endif
 
 namespace android {
@@ -49,90 +55,28 @@
   return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
 }
 
-// Based on std::unique_ptr, but uses free() to release malloc'ed memory
-// without incurring the size increase of holding on to a custom deleter.
-template <typename T>
-class unique_cptr {
- public:
-  using pointer = typename std::add_pointer<T>::type;
-
-  constexpr unique_cptr() : ptr_(nullptr) {}
-  constexpr explicit unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
-  explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
-  unique_cptr(unique_cptr&& o) noexcept : ptr_(o.ptr_) { o.ptr_ = nullptr; }
-
-  ~unique_cptr() { std::free(reinterpret_cast<void*>(ptr_)); }
-
-  inline unique_cptr& operator=(unique_cptr&& o) noexcept {
-    if (&o == this) {
-      return *this;
-    }
-
-    std::free(reinterpret_cast<void*>(ptr_));
-    ptr_ = o.ptr_;
-    o.ptr_ = nullptr;
-    return *this;
+// Based on std::unique_ptr, but uses free() to release malloc'ed memory.
+struct FreeDeleter {
+  void operator()(void* ptr) const {
+    ::free(ptr);
   }
-
-  inline unique_cptr& operator=(std::nullptr_t) {
-    std::free(reinterpret_cast<void*>(ptr_));
-    ptr_ = nullptr;
-    return *this;
-  }
-
-  pointer release() {
-    pointer result = ptr_;
-    ptr_ = nullptr;
-    return result;
-  }
-
-  inline pointer get() const { return ptr_; }
-
-  void reset(pointer ptr = pointer()) {
-    if (ptr == ptr_) {
-      return;
-    }
-
-    pointer old_ptr = ptr_;
-    ptr_ = ptr;
-    std::free(reinterpret_cast<void*>(old_ptr));
-  }
-
-  inline void swap(unique_cptr& o) { std::swap(ptr_, o.ptr_); }
-
-  inline explicit operator bool() const { return ptr_ != nullptr; }
-
-  inline typename std::add_lvalue_reference<T>::type operator*() const { return *ptr_; }
-
-  inline pointer operator->() const { return ptr_; }
-
-  inline bool operator==(const unique_cptr& o) const { return ptr_ == o.ptr_; }
-
-  inline bool operator!=(const unique_cptr& o) const { return ptr_ != o.ptr_; }
-
-  inline bool operator==(std::nullptr_t) const { return ptr_ == nullptr; }
-
-  inline bool operator!=(std::nullptr_t) const { return ptr_ != nullptr; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(unique_cptr);
-
-  pointer ptr_;
 };
+template <typename T>
+using unique_cptr = std::unique_ptr<T, FreeDeleter>;
 
 void ReadUtf16StringFromDevice(const uint16_t* src, size_t len, std::string* out);
 
 // Converts a UTF-8 string to a UTF-16 string.
-std::u16string Utf8ToUtf16(const StringPiece& utf8);
+std::u16string Utf8ToUtf16(StringPiece utf8);
 
 // Converts a UTF-16 string to a UTF-8 string.
-std::string Utf16ToUtf8(const StringPiece16& utf16);
+std::string Utf16ToUtf8(StringPiece16 utf16);
 
 // Converts a UTF8 string into Modified UTF8
-std::string Utf8ToModifiedUtf8(const std::string& utf8);
+std::string Utf8ToModifiedUtf8(std::string_view utf8);
 
 // Converts a Modified UTF8 string into a UTF8 string
-std::string ModifiedUtf8ToUtf8(const std::string& modified_utf8);
+std::string ModifiedUtf8ToUtf8(std::string_view modified_utf8);
 
 inline uint16_t HostToDevice16(uint16_t value) {
   return htods(value);
@@ -150,15 +94,15 @@
   return dtohl(value);
 }
 
-std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+std::vector<std::string> SplitAndLowercase(android::StringPiece str, char sep);
+
+inline bool IsFourByteAligned(const void* data) {
+  return ((uintptr_t)data & 0x3U) == 0;
+}
 
 template <typename T>
 inline bool IsFourByteAligned(const incfs::map_ptr<T>& data) {
-  return ((size_t)data.unsafe_ptr() & 0x3U) == 0;
-}
-
-inline bool IsFourByteAligned(const void* data) {
-  return ((size_t)data & 0x3U) == 0;
+  return IsFourByteAligned(data.unsafe_ptr());
 }
 
 // Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
index 5a5a0e2..d40d24e 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -44,6 +44,10 @@
 /* get the file's modification date; returns -1 w/errno set on failure */
 time_t getFileModDate(const char* fileName);
 
+// Check if |path| or |fd| resides on a readonly filesystem.
+bool isReadonlyFilesystem(const char* path);
+bool isReadonlyFilesystem(int fd);
+
 }; // namespace android
 
 #endif // _LIBS_ANDROID_FW_MISC_H
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index 5285420..d3949e9 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -21,12 +21,17 @@
 //
 #include <androidfw/misc.h>
 
-#include <sys/stat.h>
-#include <cstring>
-#include <errno.h>
-#include <cstdio>
+#include "android-base/logging.h"
 
-using namespace android;
+#ifdef __linux__
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#endif  // __linux__
+
+#include <cstring>
+#include <cstdio>
+#include <errno.h>
+#include <sys/stat.h>
 
 namespace android {
 
@@ -41,8 +46,7 @@
         if (errno == ENOENT || errno == ENOTDIR)
             return kFileTypeNonexistent;
         else {
-            fprintf(stderr, "getFileType got errno=%d on '%s'\n",
-                errno, fileName);
+            PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed";
             return kFileTypeUnknown;
         }
     } else {
@@ -82,4 +86,32 @@
     return sb.st_mtime;
 }
 
+#ifndef __linux__
+// No need to implement these on the host, the functions only matter on a device.
+bool isReadonlyFilesystem(const char*) {
+    return false;
+}
+bool isReadonlyFilesystem(int) {
+    return false;
+}
+#else   // __linux__
+bool isReadonlyFilesystem(const char* path) {
+    struct statfs sfs;
+    if (::statfs(path, &sfs)) {
+        PLOG(ERROR) << "isReadonlyFilesystem(): statfs(" << path << ") failed";
+        return false;
+    }
+    return (sfs.f_flags & ST_RDONLY) != 0;
+}
+
+bool isReadonlyFilesystem(int fd) {
+    struct statfs sfs;
+    if (::fstatfs(fd, &sfs)) {
+        PLOG(ERROR) << "isReadonlyFilesystem(): fstatfs(" << fd << ") failed";
+        return false;
+    }
+    return (sfs.f_flags & ST_RDONLY) != 0;
+}
+#endif  // __linux__
+
 }; // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_bench.cpp b/libs/androidfw/tests/AttributeResolution_bench.cpp
index ddd8ab8..1c89c61 100644
--- a/libs/androidfw/tests/AttributeResolution_bench.cpp
+++ b/libs/androidfw/tests/AttributeResolution_bench.cpp
@@ -120,8 +120,8 @@
     return;
   }
 
-  std::unique_ptr<Asset> asset = assetmanager.OpenNonAsset(layout_path->to_string(), value->cookie,
-                                                           Asset::ACCESS_BUFFER);
+  std::unique_ptr<Asset> asset =
+      assetmanager.OpenNonAsset(std::string(*layout_path), value->cookie, Asset::ACCESS_BUFFER);
   if (asset == nullptr) {
     state.SkipWithError("failed to load layout");
     return;
diff --git a/libs/androidfw/tests/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp
index 5d464c7..9c36cfb 100644
--- a/libs/androidfw/tests/ByteBucketArray_test.cpp
+++ b/libs/androidfw/tests/ByteBucketArray_test.cpp
@@ -52,4 +52,57 @@
   }
 }
 
+TEST(ByteBucketArrayTest, TestForEach) {
+  ByteBucketArray<int> bba;
+  ASSERT_TRUE(bba.set(0, 1));
+  ASSERT_TRUE(bba.set(10, 2));
+  ASSERT_TRUE(bba.set(26, 3));
+  ASSERT_TRUE(bba.set(129, 4));
+  ASSERT_TRUE(bba.set(234, 5));
+
+  int count = 0;
+  bba.forEachItem([&count](auto i, auto val) {
+    ++count;
+    switch (i) {
+      case 0:
+        EXPECT_EQ(1, val);
+        break;
+      case 10:
+        EXPECT_EQ(2, val);
+        break;
+      case 26:
+        EXPECT_EQ(3, val);
+        break;
+      case 129:
+        EXPECT_EQ(4, val);
+        break;
+      case 234:
+        EXPECT_EQ(5, val);
+        break;
+      default:
+        EXPECT_EQ(0, val);
+        break;
+    }
+  });
+  ASSERT_EQ(4 * 16, count);
+}
+
+TEST(ByteBucketArrayTest, TestTrimBuckets) {
+  ByteBucketArray<int> bba;
+  ASSERT_TRUE(bba.set(0, 1));
+  ASSERT_TRUE(bba.set(255, 2));
+  {
+    bba.trimBuckets([](auto val) { return val < 2; });
+    int count = 0;
+    bba.forEachItem([&count](auto, auto) { ++count; });
+    ASSERT_EQ(1 * 16, count);
+  }
+  {
+    bba.trimBuckets([](auto val) { return val < 3; });
+    int count = 0;
+    bba.forEachItem([&count](auto, auto) { ++count; });
+    ASSERT_EQ(0, count);
+  }
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/ConfigDescription_test.cpp b/libs/androidfw/tests/ConfigDescription_test.cpp
index ce7f805..8fed0a4 100644
--- a/libs/androidfw/tests/ConfigDescription_test.cpp
+++ b/libs/androidfw/tests/ConfigDescription_test.cpp
@@ -25,8 +25,8 @@
 
 namespace android {
 
-static ::testing::AssertionResult TestParse(
-    const StringPiece& input, ConfigDescription* config = nullptr) {
+static ::testing::AssertionResult TestParse(StringPiece input,
+                                            ConfigDescription* config = nullptr) {
   if (ConfigDescription::Parse(input, config)) {
     return ::testing::AssertionSuccess() << input << " was successfully parsed";
   }
@@ -138,7 +138,7 @@
   EXPECT_EQ(std::string("vrheadset-v26"), config.toString().string());
 }
 
-static inline ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
+static inline ConfigDescription ParseConfigOrDie(android::StringPiece str) {
   ConfigDescription config;
   CHECK(ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
   return config;
diff --git a/libs/androidfw/tests/StringPiece_test.cpp b/libs/androidfw/tests/StringPiece_test.cpp
index 316a5c1..822e527 100644
--- a/libs/androidfw/tests/StringPiece_test.cpp
+++ b/libs/androidfw/tests/StringPiece_test.cpp
@@ -60,36 +60,4 @@
   EXPECT_TRUE(StringPiece(car) > banana);
 }
 
-TEST(StringPieceTest, ContainsOtherStringPiece) {
-  StringPiece text("I am a leaf on the wind.");
-  StringPiece start_needle("I am");
-  StringPiece end_needle("wind.");
-  StringPiece middle_needle("leaf");
-  StringPiece empty_needle("");
-  StringPiece missing_needle("soar");
-  StringPiece long_needle("This string is longer than the text.");
-
-  EXPECT_TRUE(text.contains(start_needle));
-  EXPECT_TRUE(text.contains(end_needle));
-  EXPECT_TRUE(text.contains(middle_needle));
-  EXPECT_TRUE(text.contains(empty_needle));
-  EXPECT_FALSE(text.contains(missing_needle));
-  EXPECT_FALSE(text.contains(long_needle));
-
-  StringPiece16 text16(u"I am a leaf on the wind.");
-  StringPiece16 start_needle16(u"I am");
-  StringPiece16 end_needle16(u"wind.");
-  StringPiece16 middle_needle16(u"leaf");
-  StringPiece16 empty_needle16(u"");
-  StringPiece16 missing_needle16(u"soar");
-  StringPiece16 long_needle16(u"This string is longer than the text.");
-
-  EXPECT_TRUE(text16.contains(start_needle16));
-  EXPECT_TRUE(text16.contains(end_needle16));
-  EXPECT_TRUE(text16.contains(middle_needle16));
-  EXPECT_TRUE(text16.contains(empty_needle16));
-  EXPECT_FALSE(text16.contains(missing_needle16));
-  EXPECT_FALSE(text16.contains(long_needle16));
-}
-
 }  // namespace android
diff --git a/libs/androidfw/tests/StringPool_test.cpp b/libs/androidfw/tests/StringPool_test.cpp
index 047d457..0e0acae 100644
--- a/libs/androidfw/tests/StringPool_test.cpp
+++ b/libs/androidfw/tests/StringPool_test.cpp
@@ -321,15 +321,15 @@
   ASSERT_EQ(test.setTo(data.get(), buffer.size()), NO_ERROR);
   auto str = test.string8At(0);
   ASSERT_TRUE(str.has_value());
-  EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80"));
+  EXPECT_THAT(*str, Eq("\xED\xA0\x81\xED\xB0\x80"));
 
   str = test.string8At(1);
   ASSERT_TRUE(str.has_value());
-  EXPECT_THAT(str->to_string(), Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
+  EXPECT_THAT(*str, Eq("foo \xED\xA0\x81\xED\xB0\xB7 bar"));
 
   str = test.string8At(2);
   ASSERT_TRUE(str.has_value());
-  EXPECT_THAT(str->to_string(), Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
+  EXPECT_THAT(*str, Eq("\xED\xA0\x81\xED\xB0\x80\xED\xA0\x81\xED\xB0\xB7"));
 
   // Check that retrieving the strings returns the original UTF-8 character bytes
   EXPECT_THAT(android::util::GetString(test, 0), Eq("\xF0\x90\x90\x80"));
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index c0a4fdf..3e3d77b 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -340,6 +340,8 @@
         "jni/Graphics.cpp",
         "jni/ImageDecoder.cpp",
         "jni/Interpolator.cpp",
+        "jni/MeshSpecification.cpp",
+        "jni/Mesh.cpp",
         "jni/MaskFilter.cpp",
         "jni/NinePatch.cpp",
         "jni/NinePatchPeeker.cpp",
@@ -570,6 +572,7 @@
                 "renderthread/VulkanSurface.cpp",
                 "renderthread/RenderProxy.cpp",
                 "renderthread/RenderThread.cpp",
+                "renderthread/HintSessionWrapper.cpp",
                 "service/GraphicsStatsService.cpp",
                 "thread/CommonPool.cpp",
                 "utils/GLUtils.cpp",
@@ -589,6 +592,7 @@
                 "ProfileData.cpp",
                 "ProfileDataContainer.cpp",
                 "Readback.cpp",
+                "Tonemapper.cpp",
                 "TreeInfo.cpp",
                 "WebViewFunctorManager.cpp",
                 "protos/graphicsstats.proto",
diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp
index 673041a..cd4fae8 100644
--- a/libs/hwui/CanvasTransform.cpp
+++ b/libs/hwui/CanvasTransform.cpp
@@ -17,6 +17,7 @@
 #include "CanvasTransform.h"
 
 #include <SkAndroidFrameworkUtils.h>
+#include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkGradientShader.h>
 #include <SkHighContrastFilter.h>
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9a4c550..a7f8f61 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkImage.h>
 #include <SkMatrix.h>
diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in
index 4ec782f..e2127ef 100644
--- a/libs/hwui/DisplayListOps.in
+++ b/libs/hwui/DisplayListOps.in
@@ -52,3 +52,4 @@
 X(DrawVectorDrawable)
 X(DrawRippleDrawable)
 X(DrawWebView)
+X(DrawMesh)
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index 564ee4f..b15b6cb 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -104,6 +104,7 @@
         set(FrameInfoIndex::AnimationStart) = vsyncTime;
         set(FrameInfoIndex::PerformTraversalsStart) = vsyncTime;
         set(FrameInfoIndex::DrawStart) = vsyncTime;
+        set(FrameInfoIndex::FrameStartTime) = vsyncTime;
         set(FrameInfoIndex::FrameDeadline) = frameDeadline;
         set(FrameInfoIndex::FrameInterval) = frameInterval;
         return *this;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 9053c12..fc3118a 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -20,6 +20,8 @@
 #include "utils/Color.h"
 #include "utils/MathUtils.h"
 
+#include <SkBlendMode.h>
+
 #include <log/log.h>
 
 namespace android {
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 02c2e67..8dcd6db 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -16,16 +16,6 @@
 
 #include "Readback.h"
 
-#include <sync/sync.h>
-#include <system/window.h>
-
-#include <gui/TraceUtils.h>
-#include "DeferredLayerUpdater.h"
-#include "Properties.h"
-#include "hwui/Bitmap.h"
-#include "pipeline/skia/LayerDrawable.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/VulkanManager.h"
 #include <SkBitmap.h>
 #include <SkBlendMode.h>
 #include <SkCanvas.h>
@@ -38,6 +28,19 @@
 #include <SkRefCnt.h>
 #include <SkSamplingOptions.h>
 #include <SkSurface.h>
+#include <gui/TraceUtils.h>
+#include <private/android/AHardwareBufferHelpers.h>
+#include <shaders/shaders.h>
+#include <sync/sync.h>
+#include <system/window.h>
+
+#include "DeferredLayerUpdater.h"
+#include "Properties.h"
+#include "Tonemapper.h"
+#include "hwui/Bitmap.h"
+#include "pipeline/skia/LayerDrawable.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/VulkanManager.h"
 #include "utils/Color.h"
 #include "utils/MathUtils.h"
 #include "utils/NdkUtils.h"
@@ -91,8 +94,18 @@
         }
     }
 
-    sk_sp<SkColorSpace> colorSpace = DataSpaceToColorSpace(
-            static_cast<android_dataspace>(ANativeWindow_getBuffersDataSpace(window)));
+    int32_t dataspace = ANativeWindow_getBuffersDataSpace(window);
+
+    // If the application is not updating the Surface themselves, e.g., another
+    // process is producing buffers for the application to display, then
+    // ANativeWindow_getBuffersDataSpace will return an unknown answer, so grab
+    // the dataspace from buffer metadata instead, if it exists.
+    if (dataspace == 0) {
+        dataspace = AHardwareBuffer_getDataSpace(sourceBuffer.get());
+    }
+
+    sk_sp<SkColorSpace> colorSpace =
+            DataSpaceToColorSpace(static_cast<android_dataspace>(dataspace));
     sk_sp<SkImage> image =
             SkImage::MakeFromAHardwareBuffer(sourceBuffer.get(), kPremul_SkAlphaType, colorSpace);
 
@@ -227,6 +240,10 @@
     const bool hasBufferCrop = cropRect.left < cropRect.right && cropRect.top < cropRect.bottom;
     auto constraint =
             hasBufferCrop ? SkCanvas::kStrict_SrcRectConstraint : SkCanvas::kFast_SrcRectConstraint;
+
+    static constexpr float kMaxLuminanceNits = 4000.f;
+    tonemapPaint(image->imageInfo(), canvas->imageInfo(), kMaxLuminanceNits, paint);
+
     canvas->drawImageRect(image, imageSrcRect, imageDstRect, sampling, &paint, constraint);
     canvas->restore();
 
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index f5ebfd5..3f21940 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -15,13 +15,16 @@
  */
 
 #include "RecordingCanvas.h"
-#include <hwui/Paint.h>
 
 #include <GrRecordingContext.h>
+#include <SkMesh.h>
+#include <hwui/Paint.h>
 
 #include <experimental/type_traits>
+#include <utility>
 
 #include "SkAndroidFrameworkUtils.h"
+#include "SkBlendMode.h"
 #include "SkCanvas.h"
 #include "SkCanvasPriv.h"
 #include "SkColor.h"
@@ -270,7 +273,6 @@
     SkPaint paint;
     void draw(SkCanvas* c, const SkMatrix&) const { c->drawDRRect(outer, inner, paint); }
 };
-
 struct DrawAnnotation final : Op {
     static const auto kType = Type::DrawAnnotation;
     DrawAnnotation(const SkRect& rect, SkData* value) : rect(rect), value(sk_ref_sp(value)) {}
@@ -452,6 +454,16 @@
         c->drawVertices(vertices, mode, paint);
     }
 };
+struct DrawMesh final : Op {
+    static const auto kType = Type::DrawMesh;
+    DrawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint)
+            : mesh(mesh), blender(std::move(blender)), paint(paint) {}
+
+    SkMesh mesh;
+    sk_sp<SkBlender> blender;
+    SkPaint paint;
+    void draw(SkCanvas* c, const SkMatrix&) const { c->drawMesh(mesh, blender, paint); }
+};
 struct DrawAtlas final : Op {
     static const auto kType = Type::DrawAtlas;
     DrawAtlas(const SkImage* atlas, int count, SkBlendMode mode, const SkSamplingOptions& sampling,
@@ -763,6 +775,10 @@
 void DisplayListData::drawVertices(const SkVertices* vert, SkBlendMode mode, const SkPaint& paint) {
     this->push<DrawVertices>(0, vert, mode, paint);
 }
+void DisplayListData::drawMesh(const SkMesh& mesh, const sk_sp<SkBlender>& blender,
+                               const SkPaint& paint) {
+    this->push<DrawMesh>(0, mesh, blender, paint);
+}
 void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[],
                                 const SkColor colors[], int count, SkBlendMode xfermode,
                                 const SkSamplingOptions& sampling, const SkRect* cull,
@@ -1105,6 +1121,10 @@
                                            SkBlendMode mode, const SkPaint& paint) {
     fDL->drawVertices(vertices, mode, paint);
 }
+void RecordingCanvas::onDrawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender,
+                                 const SkPaint& paint) {
+    fDL->drawMesh(mesh, blender, paint);
+}
 void RecordingCanvas::onDrawAtlas2(const SkImage* atlas, const SkRSXform xforms[],
                                    const SkRect texs[], const SkColor colors[], int count,
                                    SkBlendMode bmode, const SkSamplingOptions& sampling,
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 35bec93..2539694 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -34,6 +34,7 @@
 #include <SkRuntimeEffect.h>
 #include <vector>
 
+enum class SkBlendMode;
 class SkRRect;
 
 namespace android {
@@ -111,6 +112,8 @@
     void drawRRect(const SkRRect&, const SkPaint&);
     void drawDRRect(const SkRRect&, const SkRRect&, const SkPaint&);
 
+    void drawMesh(const SkMesh&, const sk_sp<SkBlender>&, const SkPaint&);
+
     void drawAnnotation(const SkRect&, const char*, SkData*);
     void drawDrawable(SkDrawable*, const SkMatrix*);
     void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
@@ -210,6 +213,7 @@
                      const SkPaint&) override;
     void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
     void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
+    void onDrawMesh(const SkMesh&, sk_sp<SkBlender>, const SkPaint&) override;
     void onDrawAtlas2(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int,
                      SkBlendMode, const SkSamplingOptions&, const SkRect*, const SkPaint*) override;
     void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override;
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 473afbd..d83d78f 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -570,6 +570,10 @@
     applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawVertices(vertices, mode, p); });
 }
 
+void SkiaCanvas::drawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender, const SkPaint& paint) {
+    mCanvas->drawMesh(mesh, blender, paint);
+}
+
 // ----------------------------------------------------------------------------
 // Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index 51007c5..31e3b4c 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -33,6 +33,7 @@
 #include <cassert>
 #include <optional>
 
+enum class SkBlendMode;
 class SkRRect;
 
 namespace android {
@@ -119,8 +120,8 @@
     virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
                                const Paint& paint) override;
 
-   virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
-                               const Paint& paint) override;
+    virtual void drawDoubleRoundRect(const SkRRect& outer, const SkRRect& inner,
+                                     const Paint& paint) override;
 
     virtual void drawCircle(float x, float y, float radius, const Paint& paint) override;
     virtual void drawOval(float left, float top, float right, float bottom,
@@ -129,6 +130,8 @@
                          float sweepAngle, bool useCenter, const Paint& paint) override;
     virtual void drawPath(const SkPath& path, const Paint& paint) override;
     virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) override;
+    virtual void drawMesh(const SkMesh& mesh, sk_sp<SkBlender> blender,
+                          const SkPaint& paint) override;
 
     virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) override;
     virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) override;
diff --git a/libs/hwui/SkiaInterpolator.cpp b/libs/hwui/SkiaInterpolator.cpp
index 0695dd1..153c3b6 100644
--- a/libs/hwui/SkiaInterpolator.cpp
+++ b/libs/hwui/SkiaInterpolator.cpp
@@ -17,6 +17,8 @@
 #include "SkiaInterpolator.h"
 
 #include "include/core/SkMath.h"
+#include "include/core/SkScalar.h"
+#include "include/core/SkTypes.h"
 #include "include/private/SkFixed.h"
 #include "include/private/SkMalloc.h"
 #include "include/private/SkTo.h"
diff --git a/libs/hwui/Tonemapper.cpp b/libs/hwui/Tonemapper.cpp
new file mode 100644
index 0000000..a7e76b6
--- /dev/null
+++ b/libs/hwui/Tonemapper.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Tonemapper.h"
+
+#include <SkRuntimeEffect.h>
+#include <log/log.h>
+#include <shaders/shaders.h>
+
+#include "utils/Color.h"
+
+namespace android::uirenderer {
+
+namespace {
+
+class ColorFilterRuntimeEffectBuilder : public SkRuntimeEffectBuilder {
+public:
+    explicit ColorFilterRuntimeEffectBuilder(sk_sp<SkRuntimeEffect> effect)
+            : SkRuntimeEffectBuilder(std::move(effect)) {}
+
+    sk_sp<SkColorFilter> makeColorFilter() {
+        return this->effect()->makeColorFilter(this->uniforms());
+    }
+};
+
+static sk_sp<SkColorFilter> createLinearEffectColorFilter(const shaders::LinearEffect& linearEffect,
+                                                          float maxDisplayLuminance,
+                                                          float currentDisplayLuminanceNits,
+                                                          float maxLuminance) {
+    auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect));
+    auto [runtimeEffect, error] = SkRuntimeEffect::MakeForColorFilter(std::move(shaderString));
+    if (!runtimeEffect) {
+        LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str());
+    }
+
+    ColorFilterRuntimeEffectBuilder effectBuilder(std::move(runtimeEffect));
+
+    const auto uniforms =
+            shaders::buildLinearEffectUniforms(linearEffect, android::mat4(), maxDisplayLuminance,
+                                               currentDisplayLuminanceNits, maxLuminance);
+
+    for (const auto& uniform : uniforms) {
+        effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
+    }
+
+    return effectBuilder.makeColorFilter();
+}
+
+static bool extractTransfer(ui::Dataspace dataspace) {
+    return dataspace & HAL_DATASPACE_TRANSFER_MASK;
+}
+
+static bool isHdrDataspace(ui::Dataspace dataspace) {
+    const auto transfer = extractTransfer(dataspace);
+
+    return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
+}
+
+static ui::Dataspace getDataspace(const SkImageInfo& image) {
+    return static_cast<ui::Dataspace>(
+            ColorSpaceToADataSpace(image.colorSpace(), image.colorType()));
+}
+
+}  // namespace
+
+// Given a source and destination image info, and the max content luminance, generate a tonemaping
+// shader and tag it on the supplied paint.
+void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, float maxLuminanceNits,
+                  SkPaint& paint) {
+    const auto sourceDataspace = getDataspace(source);
+    const auto destinationDataspace = getDataspace(destination);
+
+    if (extractTransfer(sourceDataspace) != extractTransfer(destinationDataspace) &&
+        (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace))) {
+        const auto effect = shaders::LinearEffect{
+                .inputDataspace = sourceDataspace,
+                .outputDataspace = destinationDataspace,
+                .undoPremultipliedAlpha = source.alphaType() == kPremul_SkAlphaType,
+                .fakeInputDataspace = destinationDataspace,
+                .type = shaders::LinearEffect::SkSLType::ColorFilter};
+        constexpr float kMaxDisplayBrightnessNits = 1000.f;
+        constexpr float kCurrentDisplayBrightnessNits = 500.f;
+        sk_sp<SkColorFilter> colorFilter = createLinearEffectColorFilter(
+                effect, kMaxDisplayBrightnessNits, kCurrentDisplayBrightnessNits, maxLuminanceNits);
+
+        if (paint.getColorFilter()) {
+            paint.setColorFilter(SkColorFilters::Compose(paint.refColorFilter(), colorFilter));
+        } else {
+            paint.setColorFilter(colorFilter);
+        }
+    }
+}
+
+}  // namespace android::uirenderer
diff --git a/libs/hwui/Tonemapper.h b/libs/hwui/Tonemapper.h
new file mode 100644
index 0000000..c0d5325
--- /dev/null
+++ b/libs/hwui/Tonemapper.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <SkCanvas.h>
+
+namespace android::uirenderer {
+
+// Given a source and destination image info, and the max content luminance, generate a tonemaping
+// shader and tag it on the supplied paint.
+void tonemapPaint(const SkImageInfo& source, const SkImageInfo& destination, float maxLuminanceNits,
+                  SkPaint& paint);
+
+}  // namespace android::uirenderer
diff --git a/libs/hwui/apex/android_paint.cpp b/libs/hwui/apex/android_paint.cpp
index 70bd085..cc79cba 100644
--- a/libs/hwui/apex/android_paint.cpp
+++ b/libs/hwui/apex/android_paint.cpp
@@ -19,6 +19,7 @@
 #include "TypeCast.h"
 
 #include <hwui/Paint.h>
+#include <SkBlendMode.h>
 
 using namespace android;
 
diff --git a/libs/hwui/apex/jni_runtime.cpp b/libs/hwui/apex/jni_runtime.cpp
index 39725a5..e6cfa7b 100644
--- a/libs/hwui/apex/jni_runtime.cpp
+++ b/libs/hwui/apex/jni_runtime.cpp
@@ -76,6 +76,8 @@
 extern int register_android_graphics_text_MeasuredText(JNIEnv* env);
 extern int register_android_graphics_text_LineBreaker(JNIEnv *env);
 extern int register_android_graphics_text_TextShaper(JNIEnv *env);
+extern int register_android_graphics_MeshSpecification(JNIEnv* env);
+extern int register_android_graphics_Mesh(JNIEnv* env);
 
 extern int register_android_util_PathParser(JNIEnv* env);
 extern int register_android_view_DisplayListCanvas(JNIEnv* env);
@@ -143,6 +145,8 @@
             REG_JNI(register_android_graphics_text_MeasuredText),
             REG_JNI(register_android_graphics_text_LineBreaker),
             REG_JNI(register_android_graphics_text_TextShaper),
+            REG_JNI(register_android_graphics_MeshSpecification),
+            REG_JNI(register_android_graphics_Mesh),
 
             REG_JNI(register_android_util_PathParser),
             REG_JNI(register_android_view_RenderNode),
diff --git a/libs/hwui/hwui/BlurDrawLooper.cpp b/libs/hwui/hwui/BlurDrawLooper.cpp
index d4b0198..8b52551 100644
--- a/libs/hwui/hwui/BlurDrawLooper.cpp
+++ b/libs/hwui/hwui/BlurDrawLooper.cpp
@@ -15,6 +15,7 @@
  */
 
 #include "BlurDrawLooper.h"
+#include <SkBlurTypes.h>
 #include <SkColorSpace.h>
 #include <SkMaskFilter.h>
 
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 82d23b5..2a20191 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -30,6 +30,7 @@
 #include <SkMatrix.h>
 
 class SkAnimatedImage;
+enum class SkBlendMode;
 class SkCanvasState;
 class SkRRect;
 class SkRuntimeShaderBuilder;
@@ -226,6 +227,7 @@
                          float sweepAngle, bool useCenter, const Paint& paint) = 0;
     virtual void drawPath(const SkPath& path, const Paint& paint) = 0;
     virtual void drawVertices(const SkVertices*, SkBlendMode, const Paint& paint) = 0;
+    virtual void drawMesh(const SkMesh& mesh, sk_sp<SkBlender>, const SkPaint& paint) = 0;
 
     // Bitmap-based
     virtual void drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) = 0;
diff --git a/libs/hwui/jni/ColorFilter.cpp b/libs/hwui/jni/ColorFilter.cpp
index cef21f9..4bd7ef4 100644
--- a/libs/hwui/jni/ColorFilter.cpp
+++ b/libs/hwui/jni/ColorFilter.cpp
@@ -17,6 +17,7 @@
 
 #include "GraphicsJNI.h"
 
+#include "SkBlendMode.h"
 #include "SkColorFilter.h"
 #include "SkColorMatrixFilter.h"
 
diff --git a/libs/hwui/jni/MaskFilter.cpp b/libs/hwui/jni/MaskFilter.cpp
index 5383032..048ce02 100644
--- a/libs/hwui/jni/MaskFilter.cpp
+++ b/libs/hwui/jni/MaskFilter.cpp
@@ -2,6 +2,7 @@
 #include "SkMaskFilter.h"
 #include "SkBlurMask.h"
 #include "SkBlurMaskFilter.h"
+#include "SkBlurTypes.h"
 #include "SkTableMaskFilter.h"
 
 static void ThrowIAE_IfNull(JNIEnv* env, void* ptr) {
diff --git a/libs/hwui/jni/Mesh.cpp b/libs/hwui/jni/Mesh.cpp
new file mode 100644
index 0000000..109aac3
--- /dev/null
+++ b/libs/hwui/jni/Mesh.cpp
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <GLES/gl.h>
+#include <Mesh.h>
+#include <SkMesh.h>
+
+#include "GraphicsJNI.h"
+#include "graphics_jni_helpers.h"
+
+namespace android {
+
+sk_sp<SkMesh::VertexBuffer> genVertexBuffer(JNIEnv* env, jobject buffer, int size,
+                                            jboolean isDirect) {
+    auto buff = ScopedJavaNioBuffer(env, buffer, size, isDirect);
+    auto vertexBuffer = SkMesh::MakeVertexBuffer(nullptr, buff.data(), size);
+    return vertexBuffer;
+}
+
+sk_sp<SkMesh::IndexBuffer> genIndexBuffer(JNIEnv* env, jobject buffer, int size,
+                                          jboolean isDirect) {
+    auto buff = ScopedJavaNioBuffer(env, buffer, size, isDirect);
+    auto indexBuffer = SkMesh::MakeIndexBuffer(nullptr, buff.data(), size);
+    return indexBuffer;
+}
+
+static jlong make(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject vertexBuffer,
+                  jboolean isDirect, jint vertexCount, jint vertexOffset, jint left, jint top,
+                  jint right, jint bottom) {
+    auto skMeshSpec = sk_ref_sp(reinterpret_cast<SkMeshSpecification*>(meshSpec));
+    sk_sp<SkMesh::VertexBuffer> skVertexBuffer =
+            genVertexBuffer(env, vertexBuffer, vertexCount * skMeshSpec->stride(), isDirect);
+    auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
+    auto mesh = SkMesh::Make(skMeshSpec, SkMesh::Mode(mode), skVertexBuffer, vertexCount,
+                             vertexOffset, nullptr, skRect);
+    auto meshPtr = std::make_unique<MeshWrapper>(MeshWrapper{mesh, MeshUniformBuilder(skMeshSpec)});
+    return reinterpret_cast<jlong>(meshPtr.release());
+}
+
+static jlong makeIndexed(JNIEnv* env, jobject, jlong meshSpec, jint mode, jobject vertexBuffer,
+                         jboolean isVertexDirect, jint vertexCount, jint vertexOffset,
+                         jobject indexBuffer, jboolean isIndexDirect, jint indexCount,
+                         jint indexOffset, jint left, jint top, jint right, jint bottom) {
+    auto skMeshSpec = sk_ref_sp(reinterpret_cast<SkMeshSpecification*>(meshSpec));
+    sk_sp<SkMesh::VertexBuffer> skVertexBuffer =
+            genVertexBuffer(env, vertexBuffer, vertexCount * skMeshSpec->stride(), isVertexDirect);
+    sk_sp<SkMesh::IndexBuffer> skIndexBuffer =
+            genIndexBuffer(env, indexBuffer, indexCount * gIndexByteSize, isIndexDirect);
+    auto skRect = SkRect::MakeLTRB(left, top, right, bottom);
+    auto mesh = SkMesh::MakeIndexed(skMeshSpec, SkMesh::Mode(mode), skVertexBuffer, vertexCount,
+                                    vertexOffset, skIndexBuffer, indexCount, indexOffset, nullptr,
+                                    skRect);
+    auto meshPtr = std::make_unique<MeshWrapper>(MeshWrapper{mesh, MeshUniformBuilder(skMeshSpec)});
+    return reinterpret_cast<jlong>(meshPtr.release());
+}
+
+static void updateMesh(JNIEnv* env, jobject, jlong meshWrapper, jboolean indexed) {
+    auto wrapper = reinterpret_cast<MeshWrapper*>(meshWrapper);
+    auto mesh = wrapper->mesh;
+    if (indexed) {
+        wrapper->mesh = SkMesh::MakeIndexed(
+                sk_ref_sp(mesh.spec()), mesh.mode(), sk_ref_sp(mesh.vertexBuffer()),
+                mesh.vertexCount(), mesh.vertexOffset(), sk_ref_sp(mesh.indexBuffer()),
+                mesh.indexCount(), mesh.indexOffset(), wrapper->builder.fUniforms, mesh.bounds());
+    } else {
+        wrapper->mesh = SkMesh::Make(
+                sk_ref_sp(mesh.spec()), mesh.mode(), sk_ref_sp(mesh.vertexBuffer()),
+                mesh.vertexCount(), mesh.vertexOffset(), wrapper->builder.fUniforms, mesh.bounds());
+    }
+}
+
+static inline int ThrowIAEFmt(JNIEnv* env, const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    int ret = jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", fmt, args);
+    va_end(args);
+    return ret;
+}
+
+static bool isIntUniformType(const SkRuntimeEffect::Uniform::Type& type) {
+    switch (type) {
+        case SkRuntimeEffect::Uniform::Type::kFloat:
+        case SkRuntimeEffect::Uniform::Type::kFloat2:
+        case SkRuntimeEffect::Uniform::Type::kFloat3:
+        case SkRuntimeEffect::Uniform::Type::kFloat4:
+        case SkRuntimeEffect::Uniform::Type::kFloat2x2:
+        case SkRuntimeEffect::Uniform::Type::kFloat3x3:
+        case SkRuntimeEffect::Uniform::Type::kFloat4x4:
+            return false;
+        case SkRuntimeEffect::Uniform::Type::kInt:
+        case SkRuntimeEffect::Uniform::Type::kInt2:
+        case SkRuntimeEffect::Uniform::Type::kInt3:
+        case SkRuntimeEffect::Uniform::Type::kInt4:
+            return true;
+    }
+}
+
+static void nativeUpdateFloatUniforms(JNIEnv* env, MeshUniformBuilder* builder,
+                                      const char* uniformName, const float values[], int count,
+                                      bool isColor) {
+    MeshUniformBuilder::MeshUniform uniform = builder->uniform(uniformName);
+    if (uniform.fVar == nullptr) {
+        ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
+    } else if (isColor != ((uniform.fVar->flags & SkRuntimeEffect::Uniform::kColor_Flag) != 0)) {
+        if (isColor) {
+            jniThrowExceptionFmt(
+                    env, "java/lang/IllegalArgumentException",
+                    "attempting to set a color uniform using the non-color specific APIs: %s %x",
+                    uniformName, uniform.fVar->flags);
+        } else {
+            ThrowIAEFmt(env,
+                        "attempting to set a non-color uniform using the setColorUniform APIs: %s",
+                        uniformName);
+        }
+    } else if (isIntUniformType(uniform.fVar->type)) {
+        ThrowIAEFmt(env, "attempting to set a int uniform using the setUniform APIs: %s",
+                    uniformName);
+    } else if (!uniform.set<float>(values, count)) {
+        ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
+                    uniform.fVar->sizeInBytes(), sizeof(float) * count);
+    }
+}
+
+static void updateFloatUniforms(JNIEnv* env, jobject, jlong uniBuilder, jstring uniformName,
+                                jfloat value1, jfloat value2, jfloat value3, jfloat value4,
+                                jint count) {
+    auto* builder = reinterpret_cast<MeshUniformBuilder*>(uniBuilder);
+    ScopedUtfChars name(env, uniformName);
+    const float values[4] = {value1, value2, value3, value4};
+    nativeUpdateFloatUniforms(env, builder, name.c_str(), values, count, false);
+}
+
+static void updateFloatArrayUniforms(JNIEnv* env, jobject, jlong uniBuilder, jstring jUniformName,
+                                     jfloatArray jvalues, jboolean isColor) {
+    auto builder = reinterpret_cast<MeshUniformBuilder*>(uniBuilder);
+    ScopedUtfChars name(env, jUniformName);
+    AutoJavaFloatArray autoValues(env, jvalues, 0, kRO_JNIAccess);
+    nativeUpdateFloatUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length(),
+                              isColor);
+}
+
+static void nativeUpdateIntUniforms(JNIEnv* env, MeshUniformBuilder* builder,
+                                    const char* uniformName, const int values[], int count) {
+    MeshUniformBuilder::MeshUniform uniform = builder->uniform(uniformName);
+    if (uniform.fVar == nullptr) {
+        ThrowIAEFmt(env, "unable to find uniform named %s", uniformName);
+    } else if (!isIntUniformType(uniform.fVar->type)) {
+        ThrowIAEFmt(env, "attempting to set a non-int uniform using the setIntUniform APIs: %s",
+                    uniformName);
+    } else if (!uniform.set<int>(values, count)) {
+        ThrowIAEFmt(env, "mismatch in byte size for uniform [expected: %zu actual: %zu]",
+                    uniform.fVar->sizeInBytes(), sizeof(float) * count);
+    }
+}
+
+static void updateIntUniforms(JNIEnv* env, jobject, jlong uniBuilder, jstring uniformName,
+                              jint value1, jint value2, jint value3, jint value4, jint count) {
+    auto builder = reinterpret_cast<MeshUniformBuilder*>(uniBuilder);
+    ScopedUtfChars name(env, uniformName);
+    const int values[4] = {value1, value2, value3, value4};
+    nativeUpdateIntUniforms(env, builder, name.c_str(), values, count);
+}
+
+static void updateIntArrayUniforms(JNIEnv* env, jobject, jlong uniBuilder, jstring uniformName,
+                                   jintArray values) {
+    auto builder = reinterpret_cast<MeshUniformBuilder*>(uniBuilder);
+    ScopedUtfChars name(env, uniformName);
+    AutoJavaIntArray autoValues(env, values, 0);
+    nativeUpdateIntUniforms(env, builder, name.c_str(), autoValues.ptr(), autoValues.length());
+}
+
+static void MeshWrapper_destroy(MeshWrapper* wrapper) {
+    delete wrapper;
+}
+
+static jlong getMeshFinalizer(JNIEnv*, jobject) {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&MeshWrapper_destroy));
+}
+
+static const JNINativeMethod gMeshMethods[] = {
+        {"nativeGetFinalizer", "()J", (void*)getMeshFinalizer},
+        {"nativeMake", "(JILjava/nio/Buffer;ZIIIIII)J", (void*)make},
+        {"nativeMakeIndexed", "(JILjava/nio/Buffer;ZIILjava/nio/ShortBuffer;ZIIIIII)J",
+         (void*)makeIndexed},
+        {"nativeUpdateMesh", "(JZ)V", (void*)updateMesh},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;[FZ)V", (void*)updateFloatArrayUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;FFFFI)V", (void*)updateFloatUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;[I)V", (void*)updateIntArrayUniforms},
+        {"nativeUpdateUniforms", "(JLjava/lang/String;IIIII)V", (void*)updateIntUniforms}};
+
+int register_android_graphics_Mesh(JNIEnv* env) {
+    android::RegisterMethodsOrDie(env, "android/graphics/Mesh", gMeshMethods, NELEM(gMeshMethods));
+    return 0;
+}
+
+}  // namespace android
diff --git a/libs/hwui/jni/Mesh.h b/libs/hwui/jni/Mesh.h
new file mode 100644
index 0000000..aa014a5
--- /dev/null
+++ b/libs/hwui/jni/Mesh.h
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 FRAMEWORKS_BASE_LIBS_HWUI_JNI_MESH_H_
+#define FRAMEWORKS_BASE_LIBS_HWUI_JNI_MESH_H_
+
+#include <SkMesh.h>
+#include <jni.h>
+
+#include <utility>
+
+#include "graphics_jni_helpers.h"
+
+#define gIndexByteSize 2
+
+// A smart pointer that provides read only access to Java.nio.Buffer. This handles both
+// direct and indrect buffers, allowing access to the underlying data in both
+// situations. If passed a null buffer, we will throw NullPointerException,
+// and c_data will return nullptr.
+//
+// This class draws from com_google_android_gles_jni_GLImpl.cpp for Buffer to void *
+// conversion.
+class ScopedJavaNioBuffer {
+public:
+    ScopedJavaNioBuffer(JNIEnv* env, jobject buffer, jint size, jboolean isDirect)
+            : mEnv(env), mBuffer(buffer) {
+        if (buffer == nullptr) {
+            mDataBase = nullptr;
+            mData = nullptr;
+            jniThrowNullPointerException(env);
+        } else {
+            mArray = (jarray) nullptr;
+            if (isDirect) {
+                mData = getDirectBufferPointer(mEnv, mBuffer);
+            } else {
+                mData = setIndirectData(size);
+            }
+        }
+    }
+
+    ScopedJavaNioBuffer(ScopedJavaNioBuffer&& rhs) noexcept { *this = std::move(rhs); }
+
+    ~ScopedJavaNioBuffer() { reset(); }
+
+    void reset() {
+        if (mDataBase) {
+            releasePointer(mEnv, mArray, mDataBase, JNI_FALSE);
+            mDataBase = nullptr;
+        }
+    }
+
+    ScopedJavaNioBuffer& operator=(ScopedJavaNioBuffer&& rhs) noexcept {
+        if (this != &rhs) {
+            reset();
+
+            mEnv = rhs.mEnv;
+            mBuffer = rhs.mBuffer;
+            mDataBase = rhs.mDataBase;
+            mData = rhs.mData;
+            mArray = rhs.mArray;
+            rhs.mEnv = nullptr;
+            rhs.mData = nullptr;
+            rhs.mBuffer = nullptr;
+            rhs.mArray = nullptr;
+            rhs.mDataBase = nullptr;
+        }
+        return *this;
+    }
+
+    const void* data() const { return mData; }
+
+private:
+    /**
+     * This code is taken and modified from com_google_android_gles_jni_GLImpl.cpp to extract data
+     * from a java.nio.Buffer.
+     */
+    void* getDirectBufferPointer(JNIEnv* env, jobject buffer) {
+        if (buffer == nullptr) {
+            return nullptr;
+        }
+
+        jint position;
+        jint limit;
+        jint elementSizeShift;
+        jlong pointer;
+        pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift);
+        if (pointer == 0) {
+            jniThrowException(mEnv, "java/lang/IllegalArgumentException",
+                              "Must use a native order direct Buffer");
+            return nullptr;
+        }
+        pointer += position << elementSizeShift;
+        return reinterpret_cast<void*>(pointer);
+    }
+
+    static void releasePointer(JNIEnv* env, jarray array, void* data, jboolean commit) {
+        env->ReleasePrimitiveArrayCritical(array, data, commit ? 0 : JNI_ABORT);
+    }
+
+    static void* getPointer(JNIEnv* env, jobject buffer, jarray* array, jint* remaining,
+                            jint* offset) {
+        jint position;
+        jint limit;
+        jint elementSizeShift;
+
+        jlong pointer;
+        pointer = jniGetNioBufferFields(env, buffer, &position, &limit, &elementSizeShift);
+        *remaining = (limit - position) << elementSizeShift;
+        if (pointer != 0L) {
+            *array = nullptr;
+            pointer += position << elementSizeShift;
+            return reinterpret_cast<void*>(pointer);
+        }
+
+        *array = jniGetNioBufferBaseArray(env, buffer);
+        *offset = jniGetNioBufferBaseArrayOffset(env, buffer);
+        return nullptr;
+    }
+
+    /**
+     * This is a copy of
+     * static void android_glBufferData__IILjava_nio_Buffer_2I
+     * from com_google_android_gles_jni_GLImpl.cpp
+     */
+    void* setIndirectData(jint size) {
+        jint exception;
+        const char* exceptionType;
+        const char* exceptionMessage;
+        jint bufferOffset = (jint)0;
+        jint remaining;
+        void* tempData;
+
+        if (mBuffer) {
+            tempData =
+                    (void*)getPointer(mEnv, mBuffer, (jarray*)&mArray, &remaining, &bufferOffset);
+            if (remaining < size) {
+                exception = 1;
+                exceptionType = "java/lang/IllegalArgumentException";
+                exceptionMessage = "remaining() < size < needed";
+                goto exit;
+            }
+        }
+        if (mBuffer && tempData == nullptr) {
+            mDataBase = (char*)mEnv->GetPrimitiveArrayCritical(mArray, (jboolean*)0);
+            tempData = (void*)(mDataBase + bufferOffset);
+        }
+        return tempData;
+    exit:
+        if (mArray) {
+            releasePointer(mEnv, mArray, (void*)(mDataBase), JNI_FALSE);
+        }
+        if (exception) {
+            jniThrowException(mEnv, exceptionType, exceptionMessage);
+        }
+        return nullptr;
+    }
+
+    JNIEnv* mEnv;
+
+    // Java Buffer data
+    void* mData;
+    jobject mBuffer;
+
+    // Indirect Buffer Data
+    jarray mArray;
+    char* mDataBase;
+};
+
+class MeshUniformBuilder {
+public:
+    struct MeshUniform {
+        template <typename T>
+        std::enable_if_t<std::is_trivially_copyable<T>::value, MeshUniform> operator=(
+                const T& val) {
+            if (!fVar) {
+                SkDEBUGFAIL("Assigning to missing variable");
+            } else if (sizeof(val) != fVar->sizeInBytes()) {
+                SkDEBUGFAIL("Incorrect value size");
+            } else {
+                memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), &val,
+                       szeof(val));
+            }
+        }
+
+        MeshUniform& operator=(const SkMatrix& val) {
+            if (!fVar) {
+                SkDEBUGFAIL("Assigning to missing variable");
+            } else if (fVar->sizeInBytes() != 9 * sizeof(float)) {
+                SkDEBUGFAIL("Incorrect value size");
+            } else {
+                float* data =
+                        SkTAddOffset<float>(fOwner->writableUniformData(), (ptrdiff_t)fVar->offset);
+                data[0] = val.get(0);
+                data[1] = val.get(3);
+                data[2] = val.get(6);
+                data[3] = val.get(1);
+                data[4] = val.get(4);
+                data[5] = val.get(7);
+                data[6] = val.get(2);
+                data[7] = val.get(5);
+                data[8] = val.get(8);
+            }
+            return *this;
+        }
+
+        template <typename T>
+        bool set(const T val[], const int count) {
+            static_assert(std::is_trivially_copyable<T>::value, "Value must be trivial copyable");
+            if (!fVar) {
+                SkDEBUGFAIL("Assigning to missing variable");
+                return false;
+            } else if (sizeof(T) * count != fVar->sizeInBytes()) {
+                SkDEBUGFAIL("Incorrect value size");
+                return false;
+            } else {
+                memcpy(SkTAddOffset<void>(fOwner->writableUniformData(), fVar->offset), val,
+                       sizeof(T) * count);
+            }
+            return true;
+        }
+
+        MeshUniformBuilder* fOwner;
+        const SkRuntimeEffect::Uniform* fVar;
+    };
+    MeshUniform uniform(std::string_view name) { return {this, fMeshSpec->findUniform(name)}; }
+
+    explicit MeshUniformBuilder(sk_sp<SkMeshSpecification> meshSpec) {
+        fMeshSpec = sk_sp(meshSpec);
+    }
+
+    sk_sp<SkData> fUniforms;
+
+private:
+    void* writableUniformData() {
+        if (!fUniforms->unique()) {
+            fUniforms = SkData::MakeWithCopy(fUniforms->data(), fUniforms->size());
+        }
+        return fUniforms->writable_data();
+    }
+
+    sk_sp<SkMeshSpecification> fMeshSpec;
+};
+
+struct MeshWrapper {
+    SkMesh mesh;
+    MeshUniformBuilder builder;
+};
+#endif  // FRAMEWORKS_BASE_LIBS_HWUI_JNI_MESH_H_
diff --git a/libs/hwui/jni/MeshSpecification.cpp b/libs/hwui/jni/MeshSpecification.cpp
new file mode 100644
index 0000000..619a3ed
--- /dev/null
+++ b/libs/hwui/jni/MeshSpecification.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <SkMesh.h>
+
+#include "GraphicsJNI.h"
+#include "graphics_jni_helpers.h"
+
+namespace android {
+
+using Attribute = SkMeshSpecification::Attribute;
+using Varying = SkMeshSpecification::Varying;
+
+static struct {
+    jclass clazz{};
+    jfieldID type{};
+    jfieldID offset{};
+    jfieldID name{};
+} gAttributeInfo;
+
+static struct {
+    jclass clazz{};
+    jfieldID type{};
+    jfieldID name{};
+} gVaryingInfo;
+
+std::vector<Attribute> extractAttributes(JNIEnv* env, jobjectArray attributes) {
+    int size = env->GetArrayLength(attributes);
+    std::vector<Attribute> attVector;
+    attVector.reserve(size);
+    for (int i = 0; i < size; i++) {
+        jobject attribute = env->GetObjectArrayElement(attributes, i);
+        auto name = (jstring)env->GetObjectField(attribute, gAttributeInfo.name);
+        auto attName = ScopedUtfChars(env, name);
+        Attribute temp{Attribute::Type(env->GetIntField(attribute, gAttributeInfo.type)),
+                       static_cast<size_t>(env->GetIntField(attribute, gAttributeInfo.offset)),
+                       SkString(attName.c_str())};
+        attVector.push_back(std::move(temp));
+    }
+    return attVector;
+}
+
+std::vector<Varying> extractVaryings(JNIEnv* env, jobjectArray varyings) {
+    int size = env->GetArrayLength(varyings);
+    std::vector<Varying> varyVector;
+    varyVector.reserve(size);
+    for (int i = 0; i < size; i++) {
+        jobject varying = env->GetObjectArrayElement(varyings, i);
+        auto name = (jstring)env->GetObjectField(varying, gVaryingInfo.name);
+        auto varyName = ScopedUtfChars(env, name);
+        Varying temp{Varying::Type(env->GetIntField(varying, gVaryingInfo.type)),
+                     SkString(varyName.c_str())};
+        varyVector.push_back(std::move(temp));
+    }
+
+    return varyVector;
+}
+
+static jlong Make(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride,
+                  jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpecResult = SkMeshSpecification::Make(attributes, vertexStride, varyings,
+                                                    SkString(skVertexShader.c_str()),
+                                                    SkString(skFragmentShader.c_str()));
+
+    if (meshSpecResult.specification.get() == nullptr) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str());
+    }
+
+    return reinterpret_cast<jlong>(meshSpecResult.specification.release());
+}
+
+static jlong MakeWithCS(JNIEnv* env, jobject thiz, jobjectArray attributeArray, jint vertexStride,
+                        jobjectArray varyingArray, jstring vertexShader, jstring fragmentShader,
+                        jlong colorSpace) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpecResult = SkMeshSpecification::Make(
+            attributes, vertexStride, varyings, SkString(skVertexShader.c_str()),
+            SkString(skFragmentShader.c_str()), GraphicsJNI::getNativeColorSpace(colorSpace));
+
+    if (meshSpecResult.specification.get() == nullptr) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str());
+    }
+
+    return reinterpret_cast<jlong>(meshSpecResult.specification.release());
+}
+
+static jlong MakeWithAlpha(JNIEnv* env, jobject thiz, jobjectArray attributeArray,
+                           jint vertexStride, jobjectArray varyingArray, jstring vertexShader,
+                           jstring fragmentShader, jlong colorSpace, jint alphaType) {
+    auto attributes = extractAttributes(env, attributeArray);
+    auto varyings = extractVaryings(env, varyingArray);
+    auto skVertexShader = ScopedUtfChars(env, vertexShader);
+    auto skFragmentShader = ScopedUtfChars(env, fragmentShader);
+    auto meshSpecResult = SkMeshSpecification::Make(
+            attributes, vertexStride, varyings, SkString(skVertexShader.c_str()),
+            SkString(skFragmentShader.c_str()), GraphicsJNI::getNativeColorSpace(colorSpace),
+            SkAlphaType(alphaType));
+
+    if (meshSpecResult.specification.get() == nullptr) {
+        jniThrowException(env, "java/lang/IllegalArgumentException", meshSpecResult.error.c_str());
+    }
+
+    return reinterpret_cast<jlong>(meshSpecResult.specification.release());
+}
+
+static void MeshSpecification_safeUnref(SkMeshSpecification* meshSpec) {
+    SkSafeUnref(meshSpec);
+}
+
+static jlong getMeshSpecificationFinalizer() {
+    return static_cast<jlong>(reinterpret_cast<uintptr_t>(&MeshSpecification_safeUnref));
+}
+
+static const JNINativeMethod gMeshSpecificationMethods[] = {
+        {"nativeGetFinalizer", "()J", (void*)getMeshSpecificationFinalizer},
+        {"nativeMake",
+         "([Landroid/graphics/MeshSpecification$Attribute;I[Landroid/graphics/"
+         "MeshSpecification$Varying;"
+         "Ljava/lang/String;Ljava/lang/String;)J",
+         (void*)Make},
+        {"nativeMakeWithCS",
+         "([Landroid/graphics/MeshSpecification$Attribute;I"
+         "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;J)J",
+         (void*)MakeWithCS},
+        {"nativeMakeWithAlpha",
+         "([Landroid/graphics/MeshSpecification$Attribute;I"
+         "[Landroid/graphics/MeshSpecification$Varying;Ljava/lang/String;Ljava/lang/String;JI)J",
+         (void*)MakeWithAlpha}};
+
+int register_android_graphics_MeshSpecification(JNIEnv* env) {
+    android::RegisterMethodsOrDie(env, "android/graphics/MeshSpecification",
+                                  gMeshSpecificationMethods, NELEM(gMeshSpecificationMethods));
+
+    gAttributeInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Attribute");
+    gAttributeInfo.type = env->GetFieldID(gAttributeInfo.clazz, "mType", "I");
+    gAttributeInfo.offset = env->GetFieldID(gAttributeInfo.clazz, "mOffset", "I");
+    gAttributeInfo.name = env->GetFieldID(gAttributeInfo.clazz, "mName", "Ljava/lang/String;");
+
+    gVaryingInfo.clazz = env->FindClass("android/graphics/MeshSpecification$Varying");
+    gVaryingInfo.type = env->GetFieldID(gVaryingInfo.clazz, "mType", "I");
+    gVaryingInfo.name = env->GetFieldID(gVaryingInfo.clazz, "mName", "Ljava/lang/String;");
+    return 0;
+}
+
+}  // namespace android
diff --git a/libs/hwui/jni/RenderEffect.cpp b/libs/hwui/jni/RenderEffect.cpp
index 213f35a..f3db170 100644
--- a/libs/hwui/jni/RenderEffect.cpp
+++ b/libs/hwui/jni/RenderEffect.cpp
@@ -15,6 +15,7 @@
  */
 #include "Bitmap.h"
 #include "GraphicsJNI.h"
+#include "SkBlendMode.h"
 #include "SkImageFilter.h"
 #include "SkImageFilters.h"
 #include "graphics_jni_helpers.h"
diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp
index 0513447..8a4d4e1 100644
--- a/libs/hwui/jni/android_graphics_Canvas.cpp
+++ b/libs/hwui/jni/android_graphics_Canvas.cpp
@@ -21,6 +21,7 @@
 #else
 #define __ANDROID_API_P__ 28
 #endif
+#include <Mesh.h>
 #include <androidfw/ResourceTypes.h>
 #include <hwui/Canvas.h>
 #include <hwui/Paint.h>
@@ -30,8 +31,8 @@
 #include <nativehelper/ScopedPrimitiveArray.h>
 #include <nativehelper/ScopedStringChars.h>
 
-#include "FontUtils.h"
 #include "Bitmap.h"
+#include "FontUtils.h"
 #include "SkBitmap.h"
 #include "SkBlendMode.h"
 #include "SkClipOp.h"
@@ -42,10 +43,10 @@
 #include "SkMatrix.h"
 #include "SkPath.h"
 #include "SkPoint.h"
+#include "SkRRect.h"
 #include "SkRect.h"
 #include "SkRefCnt.h"
 #include "SkRegion.h"
-#include "SkRRect.h"
 #include "SkScalar.h"
 #include "SkVertices.h"
 
@@ -443,6 +444,14 @@
                            blendMode, *paint);
 }
 
+static void drawMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong meshHandle, jint modeHandle,
+                     jlong paintHandle) {
+    const SkMesh mesh = reinterpret_cast<MeshWrapper*>(meshHandle)->mesh;
+    SkBlendMode blendMode = static_cast<SkBlendMode>(modeHandle);
+    SkPaint* paint = reinterpret_cast<Paint*>(paintHandle);
+    get_canvas(canvasHandle)->drawMesh(mesh, SkBlender::Mode(blendMode), *paint);
+}
+
 static void drawNinePatch(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
         jlong chunkHandle, jfloat left, jfloat top, jfloat right, jfloat bottom,
         jlong paintHandle, jint dstDensity, jint srcDensity) {
@@ -761,38 +770,38 @@
 // If called from Canvas these are regular JNI
 // If called from DisplayListCanvas they are @FastNative
 static const JNINativeMethod gDrawMethods[] = {
-    {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor},
-    {"nDrawColor","(JJJI)V", (void*) CanvasJNI::drawColorLong},
-    {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint},
-    {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint},
-    {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints},
-    {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
-    {"nDrawLines", "(J[FIIJ)V", (void*) CanvasJNI::drawLines},
-    {"nDrawRect","(JFFFFJ)V", (void*) CanvasJNI::drawRect},
-    {"nDrawRegion", "(JJJ)V", (void*) CanvasJNI::drawRegion },
-    {"nDrawRoundRect","(JFFFFFFJ)V", (void*) CanvasJNI::drawRoundRect},
-    {"nDrawDoubleRoundRect", "(JFFFFFFFFFFFFJ)V", (void*) CanvasJNI::drawDoubleRoundRectXY},
-    {"nDrawDoubleRoundRect", "(JFFFF[FFFFF[FJ)V", (void*) CanvasJNI::drawDoubleRoundRectRadii},
-    {"nDrawCircle","(JFFFJ)V", (void*) CanvasJNI::drawCircle},
-    {"nDrawOval","(JFFFFJ)V", (void*) CanvasJNI::drawOval},
-    {"nDrawArc","(JFFFFFFZJ)V", (void*) CanvasJNI::drawArc},
-    {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
-    {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
-    {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
-    {"nDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
-    {"nDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
-    {"nDrawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
-    {"nDrawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
-    {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
-    {"nDrawGlyphs", "(J[I[FIIIJJ)V", (void*)CanvasJNI::drawGlyphs},
-    {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
-    {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
-    {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
-    {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
-    {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
-    {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
-    {"nPunchHole", "(JFFFFFFF)V", (void*) CanvasJNI::punchHole}
-};
+        {"nDrawColor", "(JII)V", (void*)CanvasJNI::drawColor},
+        {"nDrawColor", "(JJJI)V", (void*)CanvasJNI::drawColorLong},
+        {"nDrawPaint", "(JJ)V", (void*)CanvasJNI::drawPaint},
+        {"nDrawPoint", "(JFFJ)V", (void*)CanvasJNI::drawPoint},
+        {"nDrawPoints", "(J[FIIJ)V", (void*)CanvasJNI::drawPoints},
+        {"nDrawLine", "(JFFFFJ)V", (void*)CanvasJNI::drawLine},
+        {"nDrawLines", "(J[FIIJ)V", (void*)CanvasJNI::drawLines},
+        {"nDrawRect", "(JFFFFJ)V", (void*)CanvasJNI::drawRect},
+        {"nDrawRegion", "(JJJ)V", (void*)CanvasJNI::drawRegion},
+        {"nDrawRoundRect", "(JFFFFFFJ)V", (void*)CanvasJNI::drawRoundRect},
+        {"nDrawDoubleRoundRect", "(JFFFFFFFFFFFFJ)V", (void*)CanvasJNI::drawDoubleRoundRectXY},
+        {"nDrawDoubleRoundRect", "(JFFFF[FFFFF[FJ)V", (void*)CanvasJNI::drawDoubleRoundRectRadii},
+        {"nDrawCircle", "(JFFFJ)V", (void*)CanvasJNI::drawCircle},
+        {"nDrawOval", "(JFFFFJ)V", (void*)CanvasJNI::drawOval},
+        {"nDrawArc", "(JFFFFFFZJ)V", (void*)CanvasJNI::drawArc},
+        {"nDrawPath", "(JJJ)V", (void*)CanvasJNI::drawPath},
+        {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
+        {"nDrawMesh", "(JJIJ)V", (void*)CanvasJNI::drawMesh},
+        {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
+        {"nDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
+        {"nDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
+        {"nDrawBitmap", "(JJFFJIII)V", (void*)CanvasJNI::drawBitmap},
+        {"nDrawBitmap", "(JJFFFFFFFFJII)V", (void*)CanvasJNI::drawBitmapRect},
+        {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
+        {"nDrawGlyphs", "(J[I[FIIIJJ)V", (void*)CanvasJNI::drawGlyphs},
+        {"nDrawText", "(J[CIIFFIJ)V", (void*)CanvasJNI::drawTextChars},
+        {"nDrawText", "(JLjava/lang/String;IIFFIJ)V", (void*)CanvasJNI::drawTextString},
+        {"nDrawTextRun", "(J[CIIIIFFZJJ)V", (void*)CanvasJNI::drawTextRunChars},
+        {"nDrawTextRun", "(JLjava/lang/String;IIIIFFZJ)V", (void*)CanvasJNI::drawTextRunString},
+        {"nDrawTextOnPath", "(J[CIIJFFIJ)V", (void*)CanvasJNI::drawTextOnPathChars},
+        {"nDrawTextOnPath", "(JLjava/lang/String;JFFIJ)V", (void*)CanvasJNI::drawTextOnPathString},
+        {"nPunchHole", "(JFFFFFFF)V", (void*)CanvasJNI::punchHole}};
 
 int register_android_graphics_Canvas(JNIEnv* env) {
     int ret = 0;
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 3ba5409..99f54c1 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -25,6 +25,7 @@
 #include "SkColorFilter.h"
 #include "SkRuntimeEffect.h"
 #include "SkSurface.h"
+#include "Tonemapper.h"
 #include "gl/GrGLTypes.h"
 #include "math/mat4.h"
 #include "system/graphics-base-v1.0.h"
@@ -76,37 +77,6 @@
              isIntegerAligned(dstDevRect.y()));
 }
 
-static sk_sp<SkShader> createLinearEffectShader(sk_sp<SkShader> shader,
-                                                const shaders::LinearEffect& linearEffect,
-                                                float maxDisplayLuminance,
-                                                float currentDisplayLuminanceNits,
-                                                float maxLuminance) {
-    auto shaderString = SkString(shaders::buildLinearEffectSkSL(linearEffect));
-    auto [runtimeEffect, error] = SkRuntimeEffect::MakeForShader(std::move(shaderString));
-    if (!runtimeEffect) {
-        LOG_ALWAYS_FATAL("LinearColorFilter construction error: %s", error.c_str());
-    }
-
-    SkRuntimeShaderBuilder effectBuilder(std::move(runtimeEffect));
-
-    effectBuilder.child("child") = std::move(shader);
-
-    const auto uniforms = shaders::buildLinearEffectUniforms(
-            linearEffect, mat4(), maxDisplayLuminance, currentDisplayLuminanceNits, maxLuminance);
-
-    for (const auto& uniform : uniforms) {
-        effectBuilder.uniform(uniform.name.c_str()).set(uniform.value.data(), uniform.value.size());
-    }
-
-    return effectBuilder.makeShader();
-}
-
-static bool isHdrDataspace(ui::Dataspace dataspace) {
-    const auto transfer = dataspace & HAL_DATASPACE_TRANSFER_MASK;
-
-    return transfer == HAL_DATASPACE_TRANSFER_ST2084 || transfer == HAL_DATASPACE_TRANSFER_HLG;
-}
-
 static void adjustCropForYUV(uint32_t format, int bufferWidth, int bufferHeight, SkRect* cropRect) {
     // Chroma channels of YUV420 images are subsampled we may need to shrink the crop region by
     // a whole texel on each side. Since skia still adds its own 0.5 inset, we apply an
@@ -215,31 +185,10 @@
             sampling = SkSamplingOptions(SkFilterMode::kLinear);
         }
 
-        const auto sourceDataspace = static_cast<ui::Dataspace>(
-                ColorSpaceToADataSpace(layerImage->colorSpace(), layerImage->colorType()));
-        const SkImageInfo& imageInfo = canvas->imageInfo();
-        const auto destinationDataspace = static_cast<ui::Dataspace>(
-                ColorSpaceToADataSpace(imageInfo.colorSpace(), imageInfo.colorType()));
-
-        if (isHdrDataspace(sourceDataspace) || isHdrDataspace(destinationDataspace)) {
-            const auto effect = shaders::LinearEffect{
-                    .inputDataspace = sourceDataspace,
-                    .outputDataspace = destinationDataspace,
-                    .undoPremultipliedAlpha = layerImage->alphaType() == kPremul_SkAlphaType,
-                    .fakeInputDataspace = destinationDataspace};
-            auto shader = layerImage->makeShader(sampling,
-                                                 SkMatrix::RectToRect(skiaSrcRect, skiaDestRect));
-            constexpr float kMaxDisplayBrightess = 1000.f;
-            constexpr float kCurrentDisplayBrightness = 500.f;
-            shader = createLinearEffectShader(std::move(shader), effect, kMaxDisplayBrightess,
-                                              kCurrentDisplayBrightness,
-                                              layer->getMaxLuminanceNits());
-            paint.setShader(shader);
-            canvas->drawRect(skiaDestRect, paint);
-        } else {
-            canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
-                                  constraint);
-        }
+        tonemapPaint(layerImage->imageInfo(), canvas->imageInfo(), layer->getMaxLuminanceNits(),
+                     paint);
+        canvas->drawImageRect(layerImage.get(), skiaSrcRect, skiaDestRect, sampling, &paint,
+                              constraint);
 
         canvas->restore();
         // restore the original matrix
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 6c390c3..c7582e7 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -18,6 +18,7 @@
 
 #include "SkiaUtils.h"
 
+#include <SkBlendMode.h>
 #include <SkCanvas.h>
 #include <SkDrawable.h>
 #include <SkMatrix.h>
diff --git a/libs/hwui/pipeline/skia/StretchMask.cpp b/libs/hwui/pipeline/skia/StretchMask.cpp
index 2dbeb3a..b169c92 100644
--- a/libs/hwui/pipeline/skia/StretchMask.cpp
+++ b/libs/hwui/pipeline/skia/StretchMask.cpp
@@ -14,8 +14,10 @@
  * limitations under the License.
  */
 #include "StretchMask.h"
-#include "SkSurface.h"
+
+#include "SkBlendMode.h"
 #include "SkCanvas.h"
+#include "SkSurface.h"
 #include "TransformCanvas.h"
 #include "SkiaDisplayList.h"
 
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index 3c7617d..e168a7b 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -33,6 +33,8 @@
 #include "thread/ThreadBase.h"
 #include "utils/TimeUtils.h"
 
+#include <SkBlendMode.h>
+
 namespace android {
 namespace uirenderer {
 namespace skiapipeline {
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 1d24e71..1c76884 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -98,7 +98,6 @@
     auto& cache = skiapipeline::ShaderCache::get();
     cache.initShaderDiskCache(identity, size);
     contextOptions->fPersistentCache = &cache;
-    contextOptions->fGpuPathRenderers &= ~GpuPathRenderers::kCoverageCounting;
 }
 
 void CacheManager::trimMemory(TrimLevel mode) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index d09bc47..64839d0 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -71,16 +71,19 @@
 } /* namespace */
 
 CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
-                                     RenderNode* rootRenderNode, IContextFactory* contextFactory) {
+                                     RenderNode* rootRenderNode, IContextFactory* contextFactory,
+                                     int32_t uiThreadId, int32_t renderThreadId) {
     auto renderType = Properties::getRenderPipelineType();
 
     switch (renderType) {
         case RenderPipelineType::SkiaGL:
             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
-                                     std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
+                                     std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread),
+                                     uiThreadId, renderThreadId);
         case RenderPipelineType::SkiaVulkan:
             return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
-                                     std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
+                                     std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread),
+                                     uiThreadId, renderThreadId);
         default:
             LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
             break;
@@ -110,7 +113,8 @@
 
 CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
                              IContextFactory* contextFactory,
-                             std::unique_ptr<IRenderPipeline> renderPipeline)
+                             std::unique_ptr<IRenderPipeline> renderPipeline, pid_t uiThreadId,
+                             pid_t renderThreadId)
         : mRenderThread(thread)
         , mGenerationID(0)
         , mOpaque(!translucent)
@@ -118,7 +122,8 @@
         , mJankTracker(&thread.globalProfileData())
         , mProfiler(mJankTracker.frames(), thread.timeLord().frameIntervalNanos())
         , mContentDrawBounds(0, 0, 0, 0)
-        , mRenderPipeline(std::move(renderPipeline)) {
+        , mRenderPipeline(std::move(renderPipeline))
+        , mHintSessionWrapper(uiThreadId, renderThreadId) {
     mRenderThread.cacheManager().registerCanvasContext(this);
     rootRenderNode->makeRoot();
     mRenderNodes.emplace_back(rootRenderNode);
@@ -472,16 +477,22 @@
     mRenderThread.pushBackFrameCallback(this);
 }
 
-std::optional<nsecs_t> CanvasContext::draw() {
+void CanvasContext::draw() {
     if (auto grContext = getGrContext()) {
         if (grContext->abandoned()) {
             LOG_ALWAYS_FATAL("GrContext is abandoned/device lost at start of CanvasContext::draw");
-            return std::nullopt;
+            return;
         }
     }
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
 
+    // reset syncDelayDuration each time we draw
+    nsecs_t syncDelayDuration = mSyncDelayDuration;
+    nsecs_t idleDuration = mIdleDuration;
+    mSyncDelayDuration = 0;
+    mIdleDuration = 0;
+
     if (!Properties::isDrawingEnabled() ||
         (dirty.isEmpty() && Properties::skipEmptyFrames && !surfaceRequiresRedraw())) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
@@ -498,7 +509,7 @@
             std::invoke(func, false /* didProduceBuffer */);
         }
         mFrameCommitCallbacks.clear();
-        return std::nullopt;
+        return;
     }
 
     ScopedActiveContext activeContext(this);
@@ -650,10 +661,25 @@
         }
     }
 
+    int64_t intendedVsync = mCurrentFrameInfo->get(FrameInfoIndex::IntendedVsync);
+    int64_t frameDeadline = mCurrentFrameInfo->get(FrameInfoIndex::FrameDeadline);
+    int64_t dequeueBufferDuration = mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration);
+
+    mHintSessionWrapper.updateTargetWorkDuration(frameDeadline - intendedVsync);
+
+    if (didDraw) {
+        int64_t frameStartTime = mCurrentFrameInfo->get(FrameInfoIndex::FrameStartTime);
+        int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
+        int64_t actualDuration = frameDuration -
+                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
+                                 dequeueBufferDuration - idleDuration;
+        mHintSessionWrapper.reportActualWorkDuration(actualDuration);
+    }
+
+    mLastDequeueBufferDuration = dequeueBufferDuration;
+
     mRenderThread.cacheManager().onFrameCompleted();
-    return didDraw ? std::make_optional(
-                             mCurrentFrameInfo->get(FrameInfoIndex::DequeueBufferDuration))
-                   : std::nullopt;
+    return;
 }
 
 void CanvasContext::reportMetricsWithPresentTime() {
@@ -766,6 +792,8 @@
 // Called by choreographer to do an RT-driven animation
 void CanvasContext::doFrame() {
     if (!mRenderPipeline->isSurfaceReady()) return;
+    mIdleDuration =
+            systemTime(SYSTEM_TIME_MONOTONIC) - mRenderThread.timeLord().computeFrameTimeNanos();
     prepareAndDraw(nullptr);
 }
 
@@ -974,6 +1002,14 @@
     }
 }
 
+void CanvasContext::sendLoadResetHint() {
+    mHintSessionWrapper.sendLoadResetHint();
+}
+
+void CanvasContext::setSyncDelayDuration(nsecs_t duration) {
+    mSyncDelayDuration = duration;
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index db96cfb..e875c42 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -16,22 +16,6 @@
 
 #pragma once
 
-#include "DamageAccumulator.h"
-#include "FrameInfo.h"
-#include "FrameInfoVisualizer.h"
-#include "FrameMetricsReporter.h"
-#include "IContextFactory.h"
-#include "IRenderPipeline.h"
-#include "JankTracker.h"
-#include "LayerUpdateQueue.h"
-#include "Lighting.h"
-#include "ReliableSurface.h"
-#include "RenderNode.h"
-#include "renderthread/RenderTask.h"
-#include "renderthread/RenderThread.h"
-#include "utils/RingBuffer.h"
-#include "ColorMode.h"
-
 #include <SkBitmap.h>
 #include <SkRect.h>
 #include <SkSize.h>
@@ -46,6 +30,23 @@
 #include <utility>
 #include <vector>
 
+#include "ColorMode.h"
+#include "DamageAccumulator.h"
+#include "FrameInfo.h"
+#include "FrameInfoVisualizer.h"
+#include "FrameMetricsReporter.h"
+#include "HintSessionWrapper.h"
+#include "IContextFactory.h"
+#include "IRenderPipeline.h"
+#include "JankTracker.h"
+#include "LayerUpdateQueue.h"
+#include "Lighting.h"
+#include "ReliableSurface.h"
+#include "RenderNode.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
+#include "utils/RingBuffer.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -66,7 +67,8 @@
 class CanvasContext : public IFrameCallback {
 public:
     static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
-                                 IContextFactory* contextFactory);
+                                 IContextFactory* contextFactory, pid_t uiThreadId,
+                                 pid_t renderThreadId);
     virtual ~CanvasContext();
 
     /**
@@ -138,7 +140,7 @@
     bool makeCurrent();
     void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
     // Returns the DequeueBufferDuration.
-    std::optional<nsecs_t> draw();
+    void draw();
     void destroy();
 
     // IFrameCallback, Choreographer-driven frame callback entry point
@@ -214,9 +216,14 @@
 
     static CanvasContext* getActiveContext();
 
+    void sendLoadResetHint();
+
+    void setSyncDelayDuration(nsecs_t duration);
+
 private:
     CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
-                  IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
+                  IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline,
+                  pid_t uiThreadId, pid_t renderThreadId);
 
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -330,6 +337,11 @@
 
     std::function<bool(int64_t, int64_t, int64_t)> mASurfaceTransactionCallback;
     std::function<void()> mPrepareSurfaceControlForWebviewCallback;
+
+    HintSessionWrapper mHintSessionWrapper;
+    nsecs_t mLastDequeueBufferDuration = 0;
+    nsecs_t mSyncDelayDuration = 0;
+    nsecs_t mIdleDuration = 0;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index cb30614..1cc82fd 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,7 +16,6 @@
 
 #include "DrawFrameTask.h"
 
-#include <dlfcn.h>
 #include <gui/TraceUtils.h>
 #include <utils/Log.h>
 
@@ -28,70 +27,11 @@
 #include "../RenderNode.h"
 #include "CanvasContext.h"
 #include "RenderThread.h"
-#include "thread/CommonPool.h"
-#include "utils/TimeUtils.h"
 
 namespace android {
 namespace uirenderer {
 namespace renderthread {
 
-namespace {
-
-typedef APerformanceHintManager* (*APH_getManager)();
-typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
-                                                      size_t, int64_t);
-typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
-typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
-typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);
-typedef void (*APH_closeSession)(APerformanceHintSession* session);
-
-bool gAPerformanceHintBindingInitialized = false;
-APH_getManager gAPH_getManagerFn = nullptr;
-APH_createSession gAPH_createSessionFn = nullptr;
-APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
-APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
-APH_sendHint gAPH_sendHintFn = nullptr;
-APH_closeSession gAPH_closeSessionFn = nullptr;
-
-void ensureAPerformanceHintBindingInitialized() {
-    if (gAPerformanceHintBindingInitialized) return;
-
-    void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
-    LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
-
-    gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
-    LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_getManager!");
-
-    gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
-    LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_createSession!");
-
-    gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
-            handle_, "APerformanceHint_updateTargetWorkDuration");
-    LOG_ALWAYS_FATAL_IF(
-            gAPH_updateTargetWorkDurationFn == nullptr,
-            "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
-
-    gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
-            handle_, "APerformanceHint_reportActualWorkDuration");
-    LOG_ALWAYS_FATAL_IF(
-            gAPH_reportActualWorkDurationFn == nullptr,
-            "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
-
-    gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
-    LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_sendHint!");
-
-    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
-    LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
-                        "Failed to find required symbol APerformanceHint_closeSession!");
-
-    gAPerformanceHintBindingInitialized = true;
-}
-
-}  // namespace
-
 DrawFrameTask::DrawFrameTask()
         : mRenderThread(nullptr)
         , mContext(nullptr)
@@ -100,13 +40,11 @@
 
 DrawFrameTask::~DrawFrameTask() {}
 
-void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
-                               int32_t uiThreadId, int32_t renderThreadId) {
+void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
+                               RenderNode* targetNode) {
     mRenderThread = thread;
     mContext = context;
     mTargetNode = targetNode;
-    mUiThreadId = uiThreadId;
-    mRenderThreadId = renderThreadId;
 }
 
 void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -150,11 +88,11 @@
 void DrawFrameTask::run() {
     const int64_t vsyncId = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameTimelineVsyncId)];
     ATRACE_FORMAT("DrawFrames %" PRId64, vsyncId);
-    nsecs_t syncDelayDuration = systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued;
+
+    mContext->setSyncDelayDuration(systemTime(SYSTEM_TIME_MONOTONIC) - mSyncQueued);
 
     bool canUnblockUiThread;
     bool canDrawThisFrame;
-    bool didDraw = false;
     {
         TreeInfo info(TreeInfo::MODE_FULL, *mContext);
         info.forceDrawFrame = mForceDrawFrame;
@@ -175,9 +113,6 @@
     std::function<void()> frameCompleteCallback = std::move(mFrameCompleteCallback);
     mFrameCallback = nullptr;
     mFrameCompleteCallback = nullptr;
-    int64_t intendedVsync = mFrameInfo[static_cast<int>(FrameInfoIndex::IntendedVsync)];
-    int64_t frameDeadline = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameDeadline)];
-    int64_t frameStartTime = mFrameInfo[static_cast<int>(FrameInfoIndex::FrameStartTime)];
 
     // From this point on anything in "this" is *UNSAFE TO ACCESS*
     if (canUnblockUiThread) {
@@ -188,18 +123,15 @@
     if (CC_UNLIKELY(frameCallback)) {
         context->enqueueFrameWork([frameCallback, context, syncResult = mSyncResult,
                                    frameNr = context->getFrameNumber()]() {
-            auto frameCommitCallback = std::move(frameCallback(syncResult, frameNr));
+            auto frameCommitCallback = frameCallback(syncResult, frameNr);
             if (frameCommitCallback) {
                 context->addFrameCommitListener(std::move(frameCommitCallback));
             }
         });
     }
 
-    nsecs_t dequeueBufferDuration = 0;
     if (CC_LIKELY(canDrawThisFrame)) {
-        std::optional<nsecs_t> drawResult = context->draw();
-        didDraw = drawResult.has_value();
-        dequeueBufferDuration = drawResult.value_or(0);
+        context->draw();
     } else {
         // Do a flush in case syncFrameState performed any texture uploads. Since we skipped
         // the draw() call, those uploads (or deletes) will end up sitting in the queue.
@@ -218,41 +150,6 @@
     if (!canUnblockUiThread) {
         unblockUiThread();
     }
-
-    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
-
-    constexpr int64_t kSanityCheckLowerBound = 100_us;
-    constexpr int64_t kSanityCheckUpperBound = 10_s;
-    int64_t targetWorkDuration = frameDeadline - intendedVsync;
-    targetWorkDuration = targetWorkDuration * Properties::targetCpuTimePercentage / 100;
-    if (targetWorkDuration > kSanityCheckLowerBound &&
-        targetWorkDuration < kSanityCheckUpperBound &&
-        targetWorkDuration != mLastTargetWorkDuration) {
-        mLastTargetWorkDuration = targetWorkDuration;
-        mHintSessionWrapper->updateTargetWorkDuration(targetWorkDuration);
-    }
-
-    if (didDraw) {
-        int64_t frameDuration = systemTime(SYSTEM_TIME_MONOTONIC) - frameStartTime;
-        int64_t actualDuration = frameDuration -
-                                 (std::min(syncDelayDuration, mLastDequeueBufferDuration)) -
-                                 dequeueBufferDuration;
-        if (actualDuration > kSanityCheckLowerBound && actualDuration < kSanityCheckUpperBound) {
-            mHintSessionWrapper->reportActualWorkDuration(actualDuration);
-        }
-    }
-
-    mLastDequeueBufferDuration = dequeueBufferDuration;
-}
-
-void DrawFrameTask::sendLoadResetHint() {
-    if (!(Properties::useHintManager && Properties::isDrawingEnabled())) return;
-    if (!mHintSessionWrapper) mHintSessionWrapper.emplace(mUiThreadId, mRenderThreadId);
-    nsecs_t now = systemTime();
-    if (now - mLastFrameNotification > kResetHintTimeout) {
-        mHintSessionWrapper->sendHint(SessionHint::CPU_LOAD_RESET);
-    }
-    mLastFrameNotification = now;
 }
 
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
@@ -305,50 +202,6 @@
     mSignal.signal();
 }
 
-DrawFrameTask::HintSessionWrapper::HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId) {
-    if (!Properties::useHintManager) return;
-    if (uiThreadId < 0 || renderThreadId < 0) return;
-
-    ensureAPerformanceHintBindingInitialized();
-
-    APerformanceHintManager* manager = gAPH_getManagerFn();
-    if (!manager) return;
-
-    std::vector<int32_t> tids = CommonPool::getThreadIds();
-    tids.push_back(uiThreadId);
-    tids.push_back(renderThreadId);
-
-    // DrawFrameTask code will always set a target duration before reporting actual durations.
-    // So this is just a placeholder value that's never used.
-    int64_t dummyTargetDurationNanos = 16666667;
-    mHintSession =
-            gAPH_createSessionFn(manager, tids.data(), tids.size(), dummyTargetDurationNanos);
-}
-
-DrawFrameTask::HintSessionWrapper::~HintSessionWrapper() {
-    if (mHintSession) {
-        gAPH_closeSessionFn(mHintSession);
-    }
-}
-
-void DrawFrameTask::HintSessionWrapper::updateTargetWorkDuration(long targetDurationNanos) {
-    if (mHintSession) {
-        gAPH_updateTargetWorkDurationFn(mHintSession, targetDurationNanos);
-    }
-}
-
-void DrawFrameTask::HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
-    if (mHintSession) {
-        gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
-    }
-}
-
-void DrawFrameTask::HintSessionWrapper::sendHint(SessionHint hint) {
-    if (mHintSession && Properties::isDrawingEnabled()) {
-        gAPH_sendHintFn(mHintSession, static_cast<int>(hint));
-    }
-}
-
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 7eae41c..fafab24 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -16,7 +16,6 @@
 #ifndef DRAWFRAMETASK_H
 #define DRAWFRAMETASK_H
 
-#include <android/performance_hint.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
@@ -28,7 +27,6 @@
 #include "../Rect.h"
 #include "../TreeInfo.h"
 #include "RenderTask.h"
-#include "utils/TimeUtils.h"
 
 namespace android {
 namespace uirenderer {
@@ -62,8 +60,7 @@
     DrawFrameTask();
     virtual ~DrawFrameTask();
 
-    void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode,
-                    int32_t uiThreadId, int32_t renderThreadId);
+    void setContext(RenderThread* thread, CanvasContext* context, RenderNode* targetNode);
     void setContentDrawBounds(int left, int top, int right, int bottom) {
         mContentDrawBounds.set(left, top, right, bottom);
     }
@@ -91,22 +88,7 @@
 
     void forceDrawNextFrame() { mForceDrawFrame = true; }
 
-    void sendLoadResetHint();
-
 private:
-    class HintSessionWrapper {
-    public:
-        HintSessionWrapper(int32_t uiThreadId, int32_t renderThreadId);
-        ~HintSessionWrapper();
-
-        void updateTargetWorkDuration(long targetDurationNanos);
-        void reportActualWorkDuration(long actualDurationNanos);
-        void sendHint(SessionHint hint);
-
-    private:
-        APerformanceHintSession* mHintSession = nullptr;
-    };
-
     void postAndWait();
     bool syncFrameState(TreeInfo& info);
     void unblockUiThread();
@@ -117,8 +99,6 @@
     RenderThread* mRenderThread;
     CanvasContext* mContext;
     RenderNode* mTargetNode = nullptr;
-    int32_t mUiThreadId = -1;
-    int32_t mRenderThreadId = -1;
     Rect mContentDrawBounds;
 
     /*********************************************
@@ -135,13 +115,6 @@
     std::function<void(bool)> mFrameCommitCallback;
     std::function<void()> mFrameCompleteCallback;
 
-    nsecs_t mLastDequeueBufferDuration = 0;
-    nsecs_t mLastTargetWorkDuration = 0;
-    std::optional<HintSessionWrapper> mHintSessionWrapper;
-
-    nsecs_t mLastFrameNotification = 0;
-    nsecs_t kResetHintTimeout = 100_ms;
-
     bool mForceDrawFrame = false;
 };
 
diff --git a/libs/hwui/renderthread/HintSessionWrapper.cpp b/libs/hwui/renderthread/HintSessionWrapper.cpp
new file mode 100644
index 0000000..edacef0
--- /dev/null
+++ b/libs/hwui/renderthread/HintSessionWrapper.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "HintSessionWrapper.h"
+
+#include <dlfcn.h>
+#include <utils/Log.h>
+
+#include <vector>
+
+#include "../Properties.h"
+#include "thread/CommonPool.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+namespace {
+
+typedef APerformanceHintManager* (*APH_getManager)();
+typedef APerformanceHintSession* (*APH_createSession)(APerformanceHintManager*, const int32_t*,
+                                                      size_t, int64_t);
+typedef void (*APH_closeSession)(APerformanceHintSession* session);
+typedef void (*APH_updateTargetWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_reportActualWorkDuration)(APerformanceHintSession*, int64_t);
+typedef void (*APH_sendHint)(APerformanceHintSession* session, int32_t);
+
+bool gAPerformanceHintBindingInitialized = false;
+APH_getManager gAPH_getManagerFn = nullptr;
+APH_createSession gAPH_createSessionFn = nullptr;
+APH_closeSession gAPH_closeSessionFn = nullptr;
+APH_updateTargetWorkDuration gAPH_updateTargetWorkDurationFn = nullptr;
+APH_reportActualWorkDuration gAPH_reportActualWorkDurationFn = nullptr;
+APH_sendHint gAPH_sendHintFn = nullptr;
+
+void ensureAPerformanceHintBindingInitialized() {
+    if (gAPerformanceHintBindingInitialized) return;
+
+    void* handle_ = dlopen("libandroid.so", RTLD_NOW | RTLD_NODELETE);
+    LOG_ALWAYS_FATAL_IF(handle_ == nullptr, "Failed to dlopen libandroid.so!");
+
+    gAPH_getManagerFn = (APH_getManager)dlsym(handle_, "APerformanceHint_getManager");
+    LOG_ALWAYS_FATAL_IF(gAPH_getManagerFn == nullptr,
+                        "Failed to find required symbol APerformanceHint_getManager!");
+
+    gAPH_createSessionFn = (APH_createSession)dlsym(handle_, "APerformanceHint_createSession");
+    LOG_ALWAYS_FATAL_IF(gAPH_createSessionFn == nullptr,
+                        "Failed to find required symbol APerformanceHint_createSession!");
+
+    gAPH_closeSessionFn = (APH_closeSession)dlsym(handle_, "APerformanceHint_closeSession");
+    LOG_ALWAYS_FATAL_IF(gAPH_closeSessionFn == nullptr,
+                        "Failed to find required symbol APerformanceHint_closeSession!");
+
+    gAPH_updateTargetWorkDurationFn = (APH_updateTargetWorkDuration)dlsym(
+            handle_, "APerformanceHint_updateTargetWorkDuration");
+    LOG_ALWAYS_FATAL_IF(
+            gAPH_updateTargetWorkDurationFn == nullptr,
+            "Failed to find required symbol APerformanceHint_updateTargetWorkDuration!");
+
+    gAPH_reportActualWorkDurationFn = (APH_reportActualWorkDuration)dlsym(
+            handle_, "APerformanceHint_reportActualWorkDuration");
+    LOG_ALWAYS_FATAL_IF(
+            gAPH_reportActualWorkDurationFn == nullptr,
+            "Failed to find required symbol APerformanceHint_reportActualWorkDuration!");
+
+    gAPH_sendHintFn = (APH_sendHint)dlsym(handle_, "APerformanceHint_sendHint");
+    LOG_ALWAYS_FATAL_IF(gAPH_sendHintFn == nullptr,
+                        "Failed to find required symbol APerformanceHint_sendHint!");
+
+    gAPerformanceHintBindingInitialized = true;
+}
+
+}  // namespace
+
+HintSessionWrapper::HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId)
+        : mUiThreadId(uiThreadId), mRenderThreadId(renderThreadId) {}
+
+HintSessionWrapper::~HintSessionWrapper() {
+    if (mHintSession) {
+        gAPH_closeSessionFn(mHintSession);
+    }
+}
+
+bool HintSessionWrapper::useHintSession() {
+    if (!Properties::useHintManager || !Properties::isDrawingEnabled()) return false;
+    if (mHintSession) return true;
+    // If session does not exist, create it;
+    // this defers session creation until we try to actually use it.
+    if (!mSessionValid) return false;
+    return init();
+}
+
+bool HintSessionWrapper::init() {
+    if (mUiThreadId < 0 || mRenderThreadId < 0) return false;
+
+    // Assume that if we return before the end, it broke
+    mSessionValid = false;
+
+    ensureAPerformanceHintBindingInitialized();
+
+    APerformanceHintManager* manager = gAPH_getManagerFn();
+    if (!manager) return false;
+
+    std::vector<pid_t> tids = CommonPool::getThreadIds();
+    tids.push_back(mUiThreadId);
+    tids.push_back(mRenderThreadId);
+
+    // Use a placeholder target value to initialize,
+    // this will always be replaced elsewhere before it gets used
+    int64_t defaultTargetDurationNanos = 16666667;
+    mHintSession =
+            gAPH_createSessionFn(manager, tids.data(), tids.size(), defaultTargetDurationNanos);
+
+    mSessionValid = !!mHintSession;
+    return mSessionValid;
+}
+
+void HintSessionWrapper::updateTargetWorkDuration(long targetWorkDurationNanos) {
+    if (!useHintSession()) return;
+    targetWorkDurationNanos = targetWorkDurationNanos * Properties::targetCpuTimePercentage / 100;
+    if (targetWorkDurationNanos != mLastTargetWorkDuration &&
+        targetWorkDurationNanos > kSanityCheckLowerBound &&
+        targetWorkDurationNanos < kSanityCheckUpperBound) {
+        mLastTargetWorkDuration = targetWorkDurationNanos;
+        gAPH_updateTargetWorkDurationFn(mHintSession, targetWorkDurationNanos);
+    }
+    mLastFrameNotification = systemTime();
+}
+
+void HintSessionWrapper::reportActualWorkDuration(long actualDurationNanos) {
+    if (!useHintSession()) return;
+    if (actualDurationNanos > kSanityCheckLowerBound &&
+        actualDurationNanos < kSanityCheckUpperBound) {
+        gAPH_reportActualWorkDurationFn(mHintSession, actualDurationNanos);
+    }
+}
+
+void HintSessionWrapper::sendLoadResetHint() {
+    if (!useHintSession()) return;
+    nsecs_t now = systemTime();
+    if (now - mLastFrameNotification > kResetHintTimeout) {
+        gAPH_sendHintFn(mHintSession, static_cast<int>(SessionHint::CPU_LOAD_RESET));
+    }
+    mLastFrameNotification = now;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/HintSessionWrapper.h b/libs/hwui/renderthread/HintSessionWrapper.h
new file mode 100644
index 0000000..fcbc101
--- /dev/null
+++ b/libs/hwui/renderthread/HintSessionWrapper.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 <android/performance_hint.h>
+
+#include "utils/TimeUtils.h"
+
+namespace android {
+namespace uirenderer {
+
+namespace renderthread {
+
+class HintSessionWrapper {
+public:
+    HintSessionWrapper(pid_t uiThreadId, pid_t renderThreadId);
+    ~HintSessionWrapper();
+
+    void updateTargetWorkDuration(long targetDurationNanos);
+    void reportActualWorkDuration(long actualDurationNanos);
+    void sendLoadResetHint();
+
+private:
+    bool useHintSession();
+    bool init();
+    APerformanceHintSession* mHintSession = nullptr;
+
+    nsecs_t mLastFrameNotification = 0;
+    nsecs_t mLastTargetWorkDuration = 0;
+
+    pid_t mUiThreadId;
+    pid_t mRenderThreadId;
+
+    bool mSessionValid = true;
+
+    static constexpr nsecs_t kResetHintTimeout = 100_ms;
+    static constexpr int64_t kSanityCheckLowerBound = 100_us;
+    static constexpr int64_t kSanityCheckUpperBound = 10_s;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 03a2bc9..07f5a78 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -42,11 +42,13 @@
 RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
                          IContextFactory* contextFactory)
         : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
-    mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
-        return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
+    pid_t uiThreadId = pthread_gettid_np(pthread_self());
+    pid_t renderThreadId = getRenderThreadTid();
+    mContext = mRenderThread.queue().runSync([=, this]() -> CanvasContext* {
+        return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory,
+                                     uiThreadId, renderThreadId);
     });
-    mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode,
-                              pthread_gettid_np(pthread_self()), getRenderThreadTid());
+    mDrawFrameTask.setContext(&mRenderThread, mContext, rootRenderNode);
 }
 
 RenderProxy::~RenderProxy() {
@@ -55,7 +57,7 @@
 
 void RenderProxy::destroyContext() {
     if (mContext) {
-        mDrawFrameTask.setContext(nullptr, nullptr, nullptr, -1, -1);
+        mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
         // This is also a fence as we need to be certain that there are no
         // outstanding mDrawFrame tasks posted before it is destroyed
         mRenderThread.queue().runSync([this]() { delete mContext; });
@@ -237,7 +239,7 @@
 }
 
 void RenderProxy::notifyCallbackPending() {
-    mDrawFrameTask.sendLoadResetHint();
+    mRenderThread.queue().post([this]() { mContext->sendLoadResetHint(); });
 }
 
 void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
diff --git a/libs/hwui/tests/common/CallCountingCanvas.h b/libs/hwui/tests/common/CallCountingCanvas.h
index d3c41191..dc36a2e 100644
--- a/libs/hwui/tests/common/CallCountingCanvas.h
+++ b/libs/hwui/tests/common/CallCountingCanvas.h
@@ -19,6 +19,8 @@
 #include <SkCanvasVirtualEnforcer.h>
 #include <SkNoDrawCanvas.h>
 
+enum class SkBlendMode;
+
 namespace android {
 namespace uirenderer {
 namespace test {
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
index 43df4a0..e70d44c 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.cpp
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -19,6 +19,8 @@
 #include "TestContext.h"
 #include "TestUtils.h"
 
+#include <SkBlendMode.h>
+
 #include <utils/Color.h>
 
 namespace android {
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index 5af7d43..19e87f8 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -19,6 +19,7 @@
 #include "utils/Color.h"
 
 #include <SkBitmap.h>
+#include <SkBlendMode.h>
 
 using namespace android;
 using namespace android::uirenderer;
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
index 2a016ac..3a1ea8c 100644
--- a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class ClippingAnimation;
 
 static TestScene::Registrar _RectGrid(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index 4271d2f..484289a 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -20,6 +20,8 @@
 #include <hwui/Paint.h>
 #include <minikin/Layout.h>
 
+#include <SkBlendMode.h>
+
 #include <cstdio>
 
 class GlyphStressAnimation;
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 0d5ca6d..dfdd0d8 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -17,6 +17,7 @@
 #include "TestSceneBase.h"
 #include "utils/Color.h"
 
+#include <SkBlendMode.h>
 #include <SkColorSpace.h>
 #include <SkGradientShader.h>
 #include <SkImagePriv.h>
diff --git a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
index cac2fb3..2955fb2 100644
--- a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class HwLayerAnimation;
 
 static TestScene::Registrar _HwLayer(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
index 77a59df..8c9a614 100644
--- a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class HwLayerSizeAnimation;
 
 static TestScene::Registrar _HwLayerSize(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/JankyScene.cpp b/libs/hwui/tests/common/scenes/JankyScene.cpp
index f5e6b31..250b986 100644
--- a/libs/hwui/tests/common/scenes/JankyScene.cpp
+++ b/libs/hwui/tests/common/scenes/JankyScene.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 #include <unistd.h>
 
 class JankyScene;
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index 5eaf185..f669dbc 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -17,6 +17,7 @@
 #include "TestSceneBase.h"
 #include "tests/common/TestListViewSceneBase.h"
 #include "hwui/Paint.h"
+#include <SkBlendMode.h>
 #include <SkGradientShader.h>
 
 class ListOfFadedTextAnimation;
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index 402c1ec..1a2af83 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -17,6 +17,8 @@
 #include "TestSceneBase.h"
 #include "utils/Color.h"
 
+#include <SkBlendMode.h>
+
 class OvalAnimation;
 
 static TestScene::Registrar _Oval(TestScene::Info{"oval", "Draws 1 oval.",
diff --git a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
index fb1b000..25cf4d6 100644
--- a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class PartialDamageAnimation;
 
 static TestScene::Registrar _PartialDamage(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
index 1e343c1..969514c 100644
--- a/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/PathClippingAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include <vector>
 
+#include <SkBlendMode.h>
+
 #include "TestSceneBase.h"
 
 class PathClippingAnimation : public TestScene {
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index f37bcbc..99e7858 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class RectGridAnimation;
 
 static TestScene::Registrar _RectGrid(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index e9f353d..2c27969 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 #include <vector>
 
 class RoundRectClippingAnimation : public TestScene {
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index 252f539..ee30c13 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -16,6 +16,7 @@
 
 #include <hwui/Paint.h>
 #include <minikin/Layout.h>
+#include <SkBlendMode.h>
 #include <string>
 #include "TestSceneBase.h"
 
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 31a8ae1..d5060c7 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class SaveLayerAnimation;
 
 static TestScene::Registrar _SaveLayer(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
index c13e80e..827ddab 100644
--- a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class ShadowGrid2Animation;
 
 static TestScene::Registrar _ShadowGrid2(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
index 772b98e..a4fb10c 100644
--- a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class ShadowGridAnimation;
 
 static TestScene::Registrar _ShadowGrid(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
index 0019da5..58c0372 100644
--- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -16,6 +16,8 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
+
 class ShadowShaderAnimation;
 
 static TestScene::Registrar _ShadowShader(TestScene::Info{
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 70a1557d..c0c3dfd 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -17,6 +17,8 @@
 #include "TestSceneBase.h"
 #include "utils/Color.h"
 
+#include <SkBlendMode.h>
+
 #include <cstdio>
 
 class ShapeAnimation;
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index 2aeb42c..40f2ed0 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -16,6 +16,7 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkColorMatrix.h>
 #include <SkGradientShader.h>
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 57a260c..a9e7a34 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -16,6 +16,7 @@
 
 #include "TestSceneBase.h"
 
+#include <SkBlendMode.h>
 #include <SkGradientShader.h>
 
 class SimpleGradientAnimation;
diff --git a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
index 7d3ca96..bb95490 100644
--- a/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/StretchyListViewAnimation.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <SkBitmap.h>
+#include <SkBlendMode.h>
 #include <SkCanvas.h>
 #include <SkColor.h>
 #include <SkFont.h>
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index d3090367..78146b8 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -17,6 +17,8 @@
 #include "TestSceneBase.h"
 #include "hwui/Paint.h"
 
+#include <SkBlendMode.h>
+
 class TextAnimation;
 
 static TestScene::Registrar _Text(TestScene::Info{"text", "Draws a bunch of text.",
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 9cd1075..a55b725 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -22,6 +22,8 @@
 #include "pipeline/skia/SkiaDisplayList.h"
 #include "tests/common/TestUtils.h"
 
+#include <SkBlendMode.h>
+
 using namespace android;
 using namespace android::uirenderer;
 using namespace android::uirenderer::skiapipeline;
diff --git a/libs/hwui/tests/microbench/RenderNodeBench.cpp b/libs/hwui/tests/microbench/RenderNodeBench.cpp
index 6aed251..72946c4 100644
--- a/libs/hwui/tests/microbench/RenderNodeBench.cpp
+++ b/libs/hwui/tests/microbench/RenderNodeBench.cpp
@@ -19,6 +19,8 @@
 #include "hwui/Canvas.h"
 #include "RenderNode.h"
 
+#include <SkBlendMode.h>
+
 using namespace android;
 using namespace android::uirenderer;
 
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index 1771c35..88420a5 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -36,7 +36,7 @@
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory, 0, 0));
 
     ASSERT_FALSE(canvasContext->hasSurface());
 
diff --git a/libs/hwui/tests/unit/CanvasOpTests.cpp b/libs/hwui/tests/unit/CanvasOpTests.cpp
index d2b1ef9..1f6edf3 100644
--- a/libs/hwui/tests/unit/CanvasOpTests.cpp
+++ b/libs/hwui/tests/unit/CanvasOpTests.cpp
@@ -23,6 +23,7 @@
 
 #include <tests/common/CallCountingCanvas.h>
 
+#include "SkBlendMode.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
 #include "SkColor.h"
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index ec949b8..596bd37 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -17,6 +17,7 @@
 #include <VectorDrawable.h>
 #include <gtest/gtest.h>
 
+#include <SkBlendMode.h>
 #include <SkClipStack.h>
 #include <SkSurface_Base.h>
 #include <string.h>
@@ -334,7 +335,7 @@
             "A");
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, parent.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -398,7 +399,7 @@
                                       "A");
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, parent.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -518,7 +519,7 @@
     // prepareTree is required to find, which receivers have backward projected nodes
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, parent.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -618,7 +619,7 @@
     // prepareTree is required to find, which receivers have backward projected nodes
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, parent.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -634,7 +635,7 @@
 static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 61bd646..80796f4 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -274,7 +274,7 @@
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -310,7 +310,7 @@
             });
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory, 0, 0));
     canvasContext->setSurface(nullptr);
     TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
     DamageAccumulator damageAccumulator;
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 50d9f56..87c5216 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -17,10 +17,19 @@
 #include "tests/common/TestUtils.h"
 
 #include <hwui/Paint.h>
+#include <SkAlphaType.h>
+#include <SkBitmap.h>
+#include <SkBlendMode.h>
+#include <SkCanvas.h>
 #include <SkCanvasStateUtils.h>
+#include <SkColor.h>
 #include <SkColorSpace.h>
+#include <SkColorType.h>
+#include <SkImageInfo.h>
 #include <SkPicture.h>
 #include <SkPictureRecorder.h>
+#include <SkRefCnt.h>
+#include <SkSurface.h>
 #include <gtest/gtest.h>
 
 using namespace android;
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 3d5aca4..f825d7c 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -142,7 +142,7 @@
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory, 0, 0));
     TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
     DamageAccumulator damageAccumulator;
     info.damageAccumulator = &damageAccumulator;
@@ -201,7 +201,7 @@
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(
-            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
+            CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory, 0, 0));
 
     // Set up a Surface so that we can position the VectorDrawable offscreen.
     test::TestContext testContext;
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 7419f8f..4d0595e 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -17,6 +17,7 @@
 #include <VectorDrawable.h>
 #include <gtest/gtest.h>
 
+#include <SkBlendMode.h>
 #include <SkClipStack.h>
 #include <SkSurface_Base.h>
 #include <string.h>
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index 94bcb11..f44f9d0 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -19,6 +19,7 @@
 #include <GLES2/gl2.h>
 #include <utils/Blur.h>
 
+#include <SkBlendMode.h>
 #include <SkColorFilter.h>
 #include <SkPaint.h>
 #include <SkShader.h>
diff --git a/libs/input/MouseCursorController.cpp b/libs/input/MouseCursorController.cpp
index 0e7b7ff..a835167 100644
--- a/libs/input/MouseCursorController.cpp
+++ b/libs/input/MouseCursorController.cpp
@@ -199,8 +199,7 @@
     width = viewport.deviceWidth;
     height = viewport.deviceHeight;
 
-    if (viewport.orientation == DISPLAY_ORIENTATION_90 ||
-        viewport.orientation == DISPLAY_ORIENTATION_270) {
+    if (viewport.orientation == ui::ROTATION_90 || viewport.orientation == ui::ROTATION_270) {
         std::swap(width, height);
     }
 }
@@ -244,38 +243,42 @@
 
         // Undo the previous rotation.
         switch (oldViewport.orientation) {
-            case DISPLAY_ORIENTATION_90:
+            case ui::ROTATION_90:
                 temp = x;
                 x = oldViewport.deviceHeight - y;
                 y = temp;
                 break;
-            case DISPLAY_ORIENTATION_180:
+            case ui::ROTATION_180:
                 x = oldViewport.deviceWidth - x;
                 y = oldViewport.deviceHeight - y;
                 break;
-            case DISPLAY_ORIENTATION_270:
+            case ui::ROTATION_270:
                 temp = x;
                 x = y;
                 y = oldViewport.deviceWidth - temp;
                 break;
+            case ui::ROTATION_0:
+                break;
         }
 
         // Perform the new rotation.
         switch (viewport.orientation) {
-            case DISPLAY_ORIENTATION_90:
+            case ui::ROTATION_90:
                 temp = x;
                 x = y;
                 y = viewport.deviceHeight - temp;
                 break;
-            case DISPLAY_ORIENTATION_180:
+            case ui::ROTATION_180:
                 x = viewport.deviceWidth - x;
                 y = viewport.deviceHeight - y;
                 break;
-            case DISPLAY_ORIENTATION_270:
+            case ui::ROTATION_270:
                 temp = x;
                 x = viewport.deviceWidth - y;
                 y = temp;
                 break;
+            case ui::ROTATION_0:
+                break;
         }
 
         // Apply offsets to convert from the pixel center to the pixel top-left corner position
diff --git a/location/java/android/location/provider/LocationProviderBase.java b/location/java/android/location/provider/LocationProviderBase.java
index 529eddd..5acec79 100644
--- a/location/java/android/location/provider/LocationProviderBase.java
+++ b/location/java/android/location/provider/LocationProviderBase.java
@@ -101,6 +101,15 @@
     public static final String ACTION_FUSED_PROVIDER =
             "com.android.location.service.FusedLocationProvider";
 
+    /**
+     * The action the wrapping service should have in its intent filter to implement the
+     * {@link android.location.LocationManager#GPS_PROVIDER}.
+     *
+     * @hide
+     */
+    public static final String ACTION_GNSS_PROVIDER =
+            "android.location.provider.action.GNSS_PROVIDER";
+
     final String mTag;
     final @Nullable String mAttributionTag;
     final IBinder mBinder;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f3931df..9c5313a 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -7670,8 +7670,10 @@
      * or video calls. This method can be used by voice or video chat applications to select a
      * different audio device than the one selected by default by the platform.
      * <p>The device selection is expressed as an {@link AudioDeviceInfo} among devices returned by
-     * {@link #getAvailableCommunicationDevices()}.
-     * The selection is active as long as the requesting application process lives, until
+     * {@link #getAvailableCommunicationDevices()}. Note that only devices in a sink role
+     * (AKA output devices, see {@link AudioDeviceInfo#isSink()}) can be specified. The matching
+     * source device is selected automatically by the platform.
+     * <p>The selection is active as long as the requesting application process lives, until
      * {@link #clearCommunicationDevice} is called or until the device is disconnected.
      * It is therefore important for applications to clear the request when a call ends or the
      * the requesting activity or service is stopped or destroyed.
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index 980f63b..59a0f7b 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -221,13 +221,6 @@
 
     /**
      * @hide
-     * Mute state used for the initial state and when API is accessed without permission.
-     */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
-    public static final int MUTED_BY_UNKNOWN = -1;
-    /**
-     * @hide
      * Flag used when muted by master volume.
      */
     @SystemApi
@@ -317,7 +310,7 @@
         mPlayerType = pic.mPlayerType;
         mClientUid = uid;
         mClientPid = pid;
-        mMutedState = MUTED_BY_UNKNOWN;
+        mMutedState = 0;
         mDeviceId = PLAYER_DEVICEID_INVALID;
         mPlayerState = PLAYER_STATE_IDLE;
         mPlayerAttr = pic.mAttributes;
@@ -366,7 +359,7 @@
         anonymCopy.mPlayerAttr = builder.build();
         anonymCopy.mDeviceId = in.mDeviceId;
         // anonymized data
-        anonymCopy.mMutedState = MUTED_BY_UNKNOWN;
+        anonymCopy.mMutedState = 0;
         anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
         anonymCopy.mClientUid = PLAYER_UPID_INVALID;
         anonymCopy.mClientPid = PLAYER_UPID_INVALID;
@@ -435,14 +428,13 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
     public boolean isMuted() {
-        return mMutedState != 0 && mMutedState != MUTED_BY_UNKNOWN;
+        return mMutedState != 0;
     }
 
     /**
      * @hide
      * Returns a bitmask expressing the mute state as a combination of MUTED_BY_* flags.
-     * <br>Note that if the mute state is not set the result will be {@link #MUTED_BY_UNKNOWN}. A
-     * value of 0 represents a player which is not muted.
+     * <br>A value of 0 corresponds to an unmuted player.
      * @return the mute state.
      */
     @SystemApi
@@ -602,11 +594,6 @@
     }
 
     private boolean isMuteAffectingActiveState() {
-        if (mMutedState == MUTED_BY_UNKNOWN) {
-            // mute state is not set, therefore it will not affect the active state
-            return false;
-        }
-
         return (mMutedState & MUTED_BY_CLIENT_VOLUME) != 0
                 || (mMutedState & MUTED_BY_VOLUME_SHAPER) != 0
                 || (mMutedState & MUTED_BY_APP_OPS) != 0;
@@ -726,9 +713,7 @@
                 "/").append(mClientPid).append(" state:").append(
                 toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(mPlayerAttr).append(
                 " sessionId:").append(mSessionId).append(" mutedState:");
-        if (mMutedState == MUTED_BY_UNKNOWN) {
-            apcToString.append("unknown ");
-        } else if (mMutedState == 0) {
+        if (mMutedState == 0) {
             apcToString.append("none ");
         } else {
             if ((mMutedState & MUTED_BY_MASTER) != 0) {
diff --git a/media/java/android/media/AudioPresentation.java b/media/java/android/media/AudioPresentation.java
index 47358be..05f3c5a 100644
--- a/media/java/android/media/AudioPresentation.java
+++ b/media/java/android/media/AudioPresentation.java
@@ -54,7 +54,11 @@
     private final int mProgramId;
     private final ULocale mLanguage;
 
-    /** @hide */
+    /**
+     * The ContentClassifier int definitions represent the AudioPresentation content
+     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
+     * @hide
+     */
     @IntDef(
         value = {
         CONTENT_UNKNOWN,
@@ -67,11 +71,6 @@
         CONTENT_EMERGENCY,
         CONTENT_VOICEOVER,
     })
-
-    /**
-     * The ContentClassifier int definitions represent the AudioPresentation content
-     * classifier (as per TS 103 190-1 v1.2.1 4.3.3.8.1)
-    */
     @Retention(RetentionPolicy.SOURCE)
     public @interface ContentClassifier {}
 
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index d51f1e1..c2c752e 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1233,18 +1233,6 @@
         }
 
         /**
-         * Sets the tuner configuration for the {@code AudioTrack}.
-         *
-         * The {@link AudioTrack.TunerConfiguration} consists of parameters obtained from
-         * the Android TV tuner API which indicate the audio content stream id and the
-         * synchronization id for the {@code AudioTrack}.
-         *
-         * @param tunerConfiguration obtained by {@link AudioTrack.TunerConfiguration.Builder}.
-         * @return the same Builder instance.
-         * @hide
-         */
-
-        /**
          * @hide
          * Sets the {@link AudioTrack} call redirection mode.
          * Used when creating an AudioTrack to inject audio to call uplink path. The mode
diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl
index 9f3c3ff..bb31859 100644
--- a/media/java/android/media/IMediaRouter2Manager.aidl
+++ b/media/java/android/media/IMediaRouter2Manager.aidl
@@ -19,6 +19,7 @@
 import android.media.MediaRoute2ProviderInfo;
 import android.media.MediaRoute2Info;
 import android.media.RouteDiscoveryPreference;
+import android.media.RouteListingPreference;
 import android.media.RoutingSessionInfo;
 
 /**
@@ -30,6 +31,8 @@
     void notifySessionReleased(in RoutingSessionInfo session);
     void notifyDiscoveryPreferenceChanged(String packageName,
             in RouteDiscoveryPreference discoveryPreference);
+    void notifyRouteListingPreferenceChange(String packageName,
+            in @nullable RouteListingPreference routeListingPreference);
     void notifyRoutesUpdated(in List<MediaRoute2Info> routes);
     void notifyRequestFailed(int requestId, int reason);
 }
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index 742207b..bddda4a 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -23,6 +23,7 @@
 import android.media.MediaRoute2Info;
 import android.media.MediaRouterClientState;
 import android.media.RouteDiscoveryPreference;
+import android.media.RouteListingPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Bundle;
 
@@ -57,6 +58,8 @@
     void unregisterRouter2(IMediaRouter2 router);
     void setDiscoveryRequestWithRouter2(IMediaRouter2 router,
             in RouteDiscoveryPreference preference);
+    void setRouteListingPreference(IMediaRouter2 router,
+            in @nullable RouteListingPreference routeListingPreference);
     void setRouteVolumeWithRouter2(IMediaRouter2 router, in MediaRoute2Info route, int volume);
 
     void requestCreateSessionWithRouter2(IMediaRouter2 router, int requestId, long managerRequestId,
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 8a03afb..d6fe6825 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -86,8 +86,10 @@
      *
      * <p>
      * The format is one of the values from
-     * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
-     * formats and the planes is as follows:
+     * {@link android.graphics.ImageFormat ImageFormat},
+     * {@link android.graphics.PixelFormat PixelFormat}, or
+     * {@link android.hardware.HardwareBuffer HardwareBuffer}. The mapping between the
+     * formats and the planes is as follows (any formats not listed will have 1 plane):
      * </p>
      *
      * <table>
@@ -171,15 +173,18 @@
      * </tr>
      * <tr>
      *   <td>{@link android.graphics.ImageFormat#YCBCR_P010 YCBCR_P010}</td>
-     *   <td>1</td>
+     *   <td>3</td>
      *   <td>P010 is a 4:2:0 YCbCr semiplanar format comprised of a WxH Y plane
-     *     followed by a Wx(H/2) CbCr plane. Each sample is represented by a 16-bit
-     *     little-endian value, with the lower 6 bits set to zero.
+     *     followed by a Wx(H/2) Cb and Cr planes. Each sample is represented by a 16-bit
+     *     little-endian value, with the lower 6 bits set to zero. Since this is guaranteed to be
+     *     a semi-planar format, the Cb plane can also be treated as an interleaved Cb/Cr plane.
      *   </td>
      * </tr>
      * </table>
      *
      * @see android.graphics.ImageFormat
+     * @see android.graphics.PixelFormat
+     * @see android.hardware.HardwareBuffer
      */
     public abstract int getFormat();
 
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index bf30c50..30d90a8 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -4106,6 +4106,22 @@
         public static final int AV1Level72      = 0x400000;
         public static final int AV1Level73      = 0x800000;
 
+        /** DTS codec profile for DTS HRA. */
+        @SuppressLint("AllUpper")
+        public static final int DTS_HDProfileHRA = 0x1;
+        /** DTS codec profile for DTS Express. */
+        @SuppressLint("AllUpper")
+        public static final int DTS_HDProfileLBR = 0x2;
+        /** DTS codec profile for DTS-HD Master Audio */
+        @SuppressLint("AllUpper")
+        public static final int DTS_HDProfileMA = 0x4;
+        /** DTS codec profile for DTS:X Profile 1 */
+        @SuppressLint("AllUpper")
+        public static final int DTS_UHDProfileP1 = 0x1;
+        /** DTS codec profile for DTS:X Profile 2 */
+        @SuppressLint("AllUpper")
+        public static final int DTS_UHDProfileP2 = 0x2;
+
         /**
          * The profile of the media content. Depending on the type of media this can be
          * one of the profile values defined in this class.
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index 681e112..e8648cc 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -28,6 +28,8 @@
 import android.os.Parcelable;
 import android.text.TextUtils;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -374,6 +376,7 @@
 
     MediaRoute2Info(@NonNull Parcel in) {
         mId = in.readString();
+        Preconditions.checkArgument(!TextUtils.isEmpty(mId));
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
         mFeatures = in.createStringArrayList();
         mType = in.readInt();
@@ -403,7 +406,7 @@
      */
     @NonNull
     public String getId() {
-        if (mProviderId != null) {
+        if (!TextUtils.isEmpty(mProviderId)) {
             return toUniqueId(mProviderId, mId);
         } else {
             return mId;
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index a28ea32..d57a56a 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -112,6 +112,10 @@
     @GuardedBy("mLock")
     final Map<String, MediaRoute2Info> mRoutes = new ArrayMap<>();
 
+    @GuardedBy("mLock")
+    @Nullable
+    private RouteListingPreference mRouteListingPreference;
+
     final RoutingController mSystemController;
 
     @GuardedBy("mLock")
@@ -461,6 +465,52 @@
         }
     }
 
+    /**
+     * Sets the {@link RouteListingPreference} of the app associated to this media router.
+     *
+     * <p>Use this method to inform the system UI of the routes that you would like to list for
+     * media routing, via the Output Switcher.
+     *
+     * <p>You should call this method before {@link #registerRouteCallback registering any route
+     * callbacks} and immediately after receiving any {@link RouteCallback#onRoutesUpdated route
+     * updates} in order to keep the system UI in a consistent state. You can also call this method
+     * at any other point to update the listing preference dynamically.
+     *
+     * <p>Notes:
+     *
+     * <ol>
+     *   <li>You should not include the ids of two or more routes with a match in their {@link
+     *       MediaRoute2Info#getDeduplicationIds() deduplication ids}. If you do, the system will
+     *       deduplicate them using its own criteria.
+     *   <li>You can use this method to rank routes in the output switcher, placing the more
+     *       important routes first. The system might override the proposed ranking.
+     *   <li>You can use this method to avoid listing routes using dynamic criteria. For example,
+     *       you can limit access to a specific type of device according to runtime criteria.
+     * </ol>
+     *
+     * @param routeListingPreference The {@link RouteListingPreference} for the system to use for
+     *     route listing. When null, the system uses its default listing criteria.
+     */
+    public void setRouteListingPreference(@Nullable RouteListingPreference routeListingPreference) {
+        synchronized (mLock) {
+            if (Objects.equals(mRouteListingPreference, routeListingPreference)) {
+                // Nothing changed. We return early to save a call to the system server.
+                return;
+            }
+            mRouteListingPreference = routeListingPreference;
+            try {
+                if (mStub == null) {
+                    MediaRouter2Stub stub = new MediaRouter2Stub();
+                    mMediaRouterService.registerRouter2(stub, mPackageName);
+                    mStub = stub;
+                }
+                mMediaRouterService.setRouteListingPreference(mStub, mRouteListingPreference);
+            } catch (RemoteException ex) {
+                ex.rethrowFromSystemServer();
+            }
+        }
+    }
+
     @GuardedBy("mLock")
     private boolean updateDiscoveryPreferenceIfNeededLocked() {
         RouteDiscoveryPreference newDiscoveryPreference = new RouteDiscoveryPreference.Builder(
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index e403e24..7786f61 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -35,6 +35,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -93,6 +94,11 @@
     @NonNull
     final ConcurrentMap<String, RouteDiscoveryPreference> mDiscoveryPreferenceMap =
             new ConcurrentHashMap<>();
+    // TODO(b/241888071): Merge mDiscoveryPreferenceMap and mPackageToRouteListingPreferenceMap into
+    //     a single record object maintained by a single package-to-record map.
+    @NonNull
+    private final ConcurrentMap<String, RouteListingPreference>
+            mPackageToRouteListingPreferenceMap = new ConcurrentHashMap<>();
 
     private final AtomicInteger mNextRequestId = new AtomicInteger(1);
     private final CopyOnWriteArrayList<TransferRequest> mTransferRequests =
@@ -355,6 +361,16 @@
     }
 
     /**
+     * Returns the {@link RouteListingPreference} of the app with the given {@code packageName}, or
+     * null if the app has not set any.
+     */
+    @Nullable
+    public RouteListingPreference getRouteListingPreference(@NonNull String packageName) {
+        Preconditions.checkArgument(!TextUtils.isEmpty(packageName));
+        return mPackageToRouteListingPreferenceMap.get(packageName);
+    }
+
+    /**
      * Gets the system routing session for the given {@code packageName}.
      * Apps can select a route that is not the global route. (e.g. an app can select the device
      * route while BT route is available.)
@@ -686,6 +702,24 @@
         }
     }
 
+    private void updateRouteListingPreference(
+            @NonNull String packageName, @Nullable RouteListingPreference routeListingPreference) {
+        RouteListingPreference oldRouteListingPreference =
+                routeListingPreference == null
+                        ? mPackageToRouteListingPreferenceMap.remove(packageName)
+                        : mPackageToRouteListingPreferenceMap.put(
+                                packageName, routeListingPreference);
+        if (Objects.equals(oldRouteListingPreference, routeListingPreference)) {
+            return;
+        }
+        for (CallbackRecord record : mCallbackRecords) {
+            record.mExecutor.execute(
+                    () ->
+                            record.mCallback.onRouteListingPreferenceUpdated(
+                                    packageName, routeListingPreference));
+        }
+    }
+
     /**
      * Gets the unmodifiable list of selected routes for the session.
      */
@@ -971,6 +1005,19 @@
         }
 
         /**
+         * Called when the app with the given {@code packageName} updates its {@link
+         * MediaRouter2#setRouteListingPreference route listing preference}.
+         *
+         * @param packageName The package name of the app that changed its listing preference.
+         * @param routeListingPreference The new {@link RouteListingPreference} set by the app with
+         *     the given {@code packageName}. Maybe null if an app has unset its preference (by
+         *     passing null to {@link MediaRouter2#setRouteListingPreference}).
+         */
+        default void onRouteListingPreferenceUpdated(
+                @NonNull String packageName,
+                @Nullable RouteListingPreference routeListingPreference) {}
+
+        /**
          * Called when a previous request has failed.
          *
          * @param reason the reason that the request has failed. Can be one of followings:
@@ -1056,6 +1103,17 @@
         }
 
         @Override
+        public void notifyRouteListingPreferenceChange(
+                String packageName, @Nullable RouteListingPreference routeListingPreference) {
+            mHandler.sendMessage(
+                    obtainMessage(
+                            MediaRouter2Manager::updateRouteListingPreference,
+                            MediaRouter2Manager.this,
+                            packageName,
+                            routeListingPreference));
+        }
+
+        @Override
         public void notifyRoutesUpdated(List<MediaRoute2Info> routes) {
             mHandler.sendMessage(
                     obtainMessage(
diff --git a/media/java/android/media/MediaRouter2Utils.java b/media/java/android/media/MediaRouter2Utils.java
index c15972d..6f946ee 100644
--- a/media/java/android/media/MediaRouter2Utils.java
+++ b/media/java/android/media/MediaRouter2Utils.java
@@ -21,6 +21,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 /**
  * @hide
  */
@@ -31,14 +33,8 @@
 
     @NonNull
     public static String toUniqueId(@NonNull String providerId, @NonNull String id) {
-        if (TextUtils.isEmpty(providerId)) {
-            Log.w(TAG, "toUniqueId: providerId shouldn't be empty");
-            return null;
-        }
-        if (TextUtils.isEmpty(id)) {
-            Log.w(TAG, "toUniqueId: id shouldn't be null");
-            return null;
-        }
+        Preconditions.checkArgument(!TextUtils.isEmpty(providerId)
+                && !TextUtils.isEmpty(id));
 
         return providerId + SEPARATOR + id;
     }
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 538e64c..e78dc31 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -89,6 +89,7 @@
             .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
             .build();
+    private boolean mPreferBuiltinDevice;
     // playback properties, use synchronized with mPlaybackSettingsLock
     private boolean mIsLooping = false;
     private float mVolume = 1.0f;
@@ -157,6 +158,37 @@
     }
 
     /**
+     * Finds the output device of type {@link AudioDeviceInfo#TYPE_BUILTIN_SPEAKER}. This device is
+     * the one on which outgoing audio for SIM calls is played.
+     *
+     * @param audioManager the audio manage.
+     * @return the {@link AudioDeviceInfo} corresponding to the builtin device, or {@code null} if
+     *     none can be found.
+     */
+    private AudioDeviceInfo getBuiltinDevice(AudioManager audioManager) {
+        AudioDeviceInfo[] deviceList = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS);
+        for (AudioDeviceInfo device : deviceList) {
+            if (device.getType() == AudioDeviceInfo.TYPE_BUILTIN_SPEAKER) {
+                return device;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the preferred device of the ringtong playback to the built-in device.
+     *
+     * @hide
+     */
+    public boolean preferBuiltinDevice(boolean enable) {
+        mPreferBuiltinDevice = enable;
+        if (mLocalPlayer == null) {
+            return true;
+        }
+        return mLocalPlayer.setPreferredDevice(getBuiltinDevice(mAudioManager));
+    }
+
+    /**
      * Creates a local media player for the ringtone using currently set attributes.
      * @return true if media player creation succeeded or is deferred,
      * false if it did not succeed and can't be tried remotely.
@@ -174,6 +206,8 @@
         try {
             mLocalPlayer.setDataSource(mContext, mUri);
             mLocalPlayer.setAudioAttributes(mAudioAttributes);
+            mLocalPlayer.setPreferredDevice(
+                    mPreferBuiltinDevice ? getBuiltinDevice(mAudioManager) : null);
             synchronized (mPlaybackSettingsLock) {
                 applyPlaybackProperties_sync();
             }
diff --git a/media/java/android/media/RouteListingPreference.aidl b/media/java/android/media/RouteListingPreference.aidl
new file mode 100644
index 0000000..844dc8f
--- /dev/null
+++ b/media/java/android/media/RouteListingPreference.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+parcelable RouteListingPreference;
diff --git a/media/java/android/media/RouteListingPreference.java b/media/java/android/media/RouteListingPreference.java
new file mode 100644
index 0000000..62f233e
--- /dev/null
+++ b/media/java/android/media/RouteListingPreference.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Allows applications to customize the list of routes used for media routing (for example, in the
+ * System UI Output Switcher).
+ *
+ * @see MediaRouter2#setRouteListingPreference
+ */
+public final class RouteListingPreference implements Parcelable {
+
+    @NonNull
+    public static final Creator<RouteListingPreference> CREATOR =
+            new Creator<>() {
+                @Override
+                public RouteListingPreference createFromParcel(Parcel in) {
+                    return new RouteListingPreference(in);
+                }
+
+                @Override
+                public RouteListingPreference[] newArray(int size) {
+                    return new RouteListingPreference[size];
+                }
+            };
+
+    @NonNull private final List<Item> mItems;
+
+    /**
+     * Creates an instance with the given values.
+     *
+     * @param items See {@link #getItems()}.
+     */
+    public RouteListingPreference(@NonNull List<Item> items) {
+        mItems = List.copyOf(Objects.requireNonNull(items));
+    }
+
+    private RouteListingPreference(Parcel in) {
+        List<Item> items =
+                in.readParcelableList(new ArrayList<>(), Item.class.getClassLoader(), Item.class);
+        mItems = List.copyOf(items);
+    }
+
+    /**
+     * Returns an unmodifiable list containing the items that the app wants to be listed for media
+     * routing.
+     */
+    @NonNull
+    public List<Item> getItems() {
+        return mItems;
+    }
+
+    // RouteListingPreference Parcelable implementation.
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        dest.writeParcelableList(mItems, flags);
+    }
+
+    // Equals and hashCode.
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+        if (!(other instanceof RouteListingPreference)) {
+            return false;
+        }
+        RouteListingPreference that = (RouteListingPreference) other;
+        return mItems.equals(that.mItems);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mItems);
+    }
+
+    // Internal classes.
+
+    /** Holds preference information for a specific route in a media routing listing. */
+    public static final class Item implements Parcelable {
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                flag = true,
+                prefix = {"FLAG_"},
+                value = {FLAG_ONGOING_SESSION, FLAG_SUGGESTED_ROUTE})
+        public @interface Flags {}
+
+        /**
+         * The corresponding route is already hosting a session with the app that owns this listing
+         * preference.
+         */
+        public static final int FLAG_ONGOING_SESSION = 1;
+
+        /**
+         * The corresponding route is specially likely to be selected by the user.
+         *
+         * <p>A UI reflecting this preference may reserve a specific space for suggested routes,
+         * making it more accessible to the user. If the number of suggested routes exceeds the
+         * number supported by the UI, the routes listed first in {@link
+         * RouteListingPreference#getItems()} will take priority.
+         */
+        public static final int FLAG_SUGGESTED_ROUTE = 1 << 1;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(
+                prefix = {"DISABLE_REASON_"},
+                value = {DISABLE_REASON_NONE, DISABLE_REASON_SUBSCRIPTION_REQUIRED})
+        public @interface DisableReason {}
+
+        /** The corresponding route is available for routing. */
+        public static final int DISABLE_REASON_NONE = 0;
+        /**
+         * The corresponding route requires a special subscription in order to be available for
+         * routing.
+         */
+        public static final int DISABLE_REASON_SUBSCRIPTION_REQUIRED = 1;
+
+        @NonNull
+        public static final Creator<Item> CREATOR =
+                new Creator<>() {
+                    @Override
+                    public Item createFromParcel(Parcel in) {
+                        return new Item(in);
+                    }
+
+                    @Override
+                    public Item[] newArray(int size) {
+                        return new Item[size];
+                    }
+                };
+
+        @NonNull private final String mRouteId;
+        @Flags private final int mFlags;
+        @DisableReason private final int mDisableReason;
+
+        /**
+         * Creates an instance with the given value.
+         *
+         * @param routeId See {@link #getRouteId()}. Must not be empty.
+         * @param flags See {@link #getFlags()}.
+         * @param disableReason See {@link #getDisableReason()}.
+         */
+        public Item(@NonNull String routeId, @Flags int flags, @DisableReason int disableReason) {
+            Preconditions.checkArgument(!TextUtils.isEmpty(routeId));
+            mRouteId = routeId;
+            mFlags = flags;
+            mDisableReason = disableReason;
+        }
+
+        private Item(Parcel in) {
+            String routeId = in.readString();
+            Preconditions.checkArgument(!TextUtils.isEmpty(routeId));
+            mRouteId = routeId;
+            mFlags = in.readInt();
+            mDisableReason = in.readInt();
+        }
+
+        /** Returns the id of the route that corresponds to this route listing preference item. */
+        @NonNull
+        public String getRouteId() {
+            return mRouteId;
+        }
+
+        /**
+         * Returns the flags associated to the route that corresponds to this item.
+         *
+         * @see #FLAG_ONGOING_SESSION
+         * @see #FLAG_SUGGESTED_ROUTE
+         */
+        @Flags
+        public int getFlags() {
+            return mFlags;
+        }
+
+        /**
+         * Returns the reason for the corresponding route to be disabled, or {@link
+         * #DISABLE_REASON_NONE} if the route is not disabled.
+         *
+         * @see #DISABLE_REASON_NONE
+         * @see #DISABLE_REASON_SUBSCRIPTION_REQUIRED
+         */
+        @DisableReason
+        public int getDisableReason() {
+            return mDisableReason;
+        }
+
+        // Item Parcelable implementation.
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(@NonNull Parcel dest, int flags) {
+            dest.writeString(mRouteId);
+            dest.writeInt(mFlags);
+            dest.writeInt(mDisableReason);
+        }
+
+        // Equals and hashCode.
+
+        @Override
+        public boolean equals(Object other) {
+            if (this == other) {
+                return true;
+            }
+            if (!(other instanceof Item)) {
+                return false;
+            }
+            Item item = (Item) other;
+            return mRouteId.equals(item.mRouteId)
+                    && mFlags == item.mFlags
+                    && mDisableReason == item.mDisableReason;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(mRouteId, mFlags, mDisableReason);
+        }
+    }
+}
diff --git a/media/java/android/media/RoutingSessionInfo.java b/media/java/android/media/RoutingSessionInfo.java
index 10973ab..0982132 100644
--- a/media/java/android/media/RoutingSessionInfo.java
+++ b/media/java/android/media/RoutingSessionInfo.java
@@ -25,6 +25,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -106,9 +108,9 @@
     }
 
     RoutingSessionInfo(@NonNull Parcel src) {
-        Objects.requireNonNull(src, "src must not be null.");
+        mId = src.readString();
+        Preconditions.checkArgument(!TextUtils.isEmpty(mId));
 
-        mId = ensureString(src.readString());
         mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
         mOwnerPackageName = src.readString();
         mClientPackageName = ensureString(src.readString());
@@ -177,7 +179,7 @@
      */
     @NonNull
     public String getId() {
-        if (mProviderId != null) {
+        if (!TextUtils.isEmpty(mProviderId)) {
             return MediaRouter2Utils.toUniqueId(mProviderId, mId);
         } else {
             return mId;
@@ -421,7 +423,7 @@
         }
 
         // mProviderId can be null if not set. Return the original list for this case.
-        if (mProviderId == null) {
+        if (TextUtils.isEmpty(mProviderId)) {
             return routeIds;
         }
 
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java
index fab63aa..7039a3e 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -998,6 +998,7 @@
     private native int nativeScan(int settingsType, FrontendSettings settings, int scanType);
     private native int nativeStopScan();
     private native int nativeSetLnb(Lnb lnb);
+    private native boolean nativeIsLnaSupported();
     private native int nativeSetLna(boolean enable);
     private native FrontendStatus nativeGetFrontendStatus(int[] statusTypes);
     private native Integer nativeGetAvSyncHwId(Filter filter);
@@ -1382,11 +1383,32 @@
     }
 
     /**
+     * Is Low Noise Amplifier (LNA) supported by the Tuner.
+     *
+     * <p>This API is only supported by Tuner HAL 3.0 or higher.
+     * Unsupported version would throw UnsupportedOperationException. Use
+     * {@link TunerVersionChecker#getTunerVersion()} to check the version.
+     *
+     * @return {@code true} if supported, otherwise {@code false}.
+     * @throws UnsupportedOperationException if the Tuner HAL version is lower than 3.0
+     * @see android.media.tv.tuner.TunerVersionChecker#TUNER_VERSION_3_0
+     */
+    public boolean isLnaSupported() {
+        if (!TunerVersionChecker.checkHigherOrEqualVersionTo(
+                TunerVersionChecker.TUNER_VERSION_3_0, "isLnaSupported")) {
+            throw new UnsupportedOperationException("Tuner HAL version "
+                    + TunerVersionChecker.getTunerVersion() + " doesn't support this method.");
+        }
+        return nativeIsLnaSupported();
+    }
+
+    /**
      * Enable or Disable Low Noise Amplifier (LNA).
      *
      * @param enable {@code true} to activate LNA module; {@code false} to deactivate LNA.
      *
-     * @return result status of the operation.
+     * @return result status of the operation. {@link #RESULT_UNAVAILABLE} if the device doesn't
+     *         support LNA.
      */
     @Result
     public int setLnaEnabled(boolean enable) {
diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java
index 15811d2..9144087 100644
--- a/media/java/android/media/tv/tuner/filter/AvSettings.java
+++ b/media/java/android/media/tv/tuner/filter/AvSettings.java
@@ -38,7 +38,8 @@
                     VIDEO_STREAM_TYPE_MPEG1, VIDEO_STREAM_TYPE_MPEG2,
                     VIDEO_STREAM_TYPE_MPEG4P2, VIDEO_STREAM_TYPE_AVC, VIDEO_STREAM_TYPE_HEVC,
                     VIDEO_STREAM_TYPE_VC1, VIDEO_STREAM_TYPE_VP8, VIDEO_STREAM_TYPE_VP9,
-                    VIDEO_STREAM_TYPE_AV1, VIDEO_STREAM_TYPE_AVS, VIDEO_STREAM_TYPE_AVS2})
+                    VIDEO_STREAM_TYPE_AV1, VIDEO_STREAM_TYPE_AVS, VIDEO_STREAM_TYPE_AVS2,
+                    VIDEO_STREAM_TYPE_VVC})
     @Retention(RetentionPolicy.SOURCE)
     public @interface VideoStreamType {}
 
@@ -76,6 +77,10 @@
      */
     public static final int VIDEO_STREAM_TYPE_HEVC = android.hardware.tv.tuner.VideoStreamType.HEVC;
     /*
+     * ITU-T Rec. H.266 and ISO/IEC 23090-3
+     */
+    public static final int VIDEO_STREAM_TYPE_VVC = android.hardware.tv.tuner.VideoStreamType.VVC;
+    /*
      * Microsoft VC.1
      */
     public static final int VIDEO_STREAM_TYPE_VC1 = android.hardware.tv.tuner.VideoStreamType.VC1;
diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java
index d0973f4..8568c43 100644
--- a/media/java/android/media/tv/tuner/filter/Filter.java
+++ b/media/java/android/media/tv/tuner/filter/Filter.java
@@ -349,6 +349,15 @@
                         + mMainType + ", filter subtype=" + mSubtype + ". config main type="
                         + config.getType() + ", config subtype=" + subType);
             }
+            // Tuner only support VVC after tuner 3.0
+            if (s instanceof RecordSettings
+                    && ((RecordSettings) s).getScIndexType() == RecordSettings.INDEX_TYPE_SC_VVC
+                    && !TunerVersionChecker.isHigherOrEqualVersionTo(
+                            TunerVersionChecker.TUNER_VERSION_3_0)) {
+                Log.e(TAG, "Tuner version " + TunerVersionChecker.getTunerVersion()
+                        + " does not support VVC");
+                return Tuner.RESULT_UNAVAILABLE;
+            }
             return nativeConfigureFilter(config.getType(), subType, config);
         }
     }
diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java
index b16d9fb..698bbba 100644
--- a/media/java/android/media/tv/tuner/filter/RecordSettings.java
+++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java
@@ -23,8 +23,10 @@
 import android.hardware.tv.tuner.DemuxScAvcIndex;
 import android.hardware.tv.tuner.DemuxScHevcIndex;
 import android.hardware.tv.tuner.DemuxScIndex;
+import android.hardware.tv.tuner.DemuxScVvcIndex;
 import android.hardware.tv.tuner.DemuxTsIndex;
 import android.media.tv.tuner.TunerUtils;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 
@@ -138,7 +140,8 @@
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = "INDEX_TYPE_", value =
-            {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC, INDEX_TYPE_SC_AVC})
+            {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC, INDEX_TYPE_SC_AVC,
+             INDEX_TYPE_SC_VVC})
     public @interface ScIndexType {}
 
     /**
@@ -157,6 +160,10 @@
      * Start Code index for AVC.
      */
     public static final int INDEX_TYPE_SC_AVC = DemuxRecordScIndexType.SC_AVC;
+    /**
+     * Start Code index for VVC.
+     */
+    public static final int INDEX_TYPE_SC_VVC = DemuxRecordScIndexType.SC_VVC;
 
     /**
      * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
@@ -253,6 +260,46 @@
     public static final int SC_HEVC_INDEX_SLICE_TRAIL_CRA = DemuxScHevcIndex.SLICE_TRAIL_CRA;
 
     /**
+     * Indexes can be tagged by NAL unit group in VVC according to ISO/IEC 23090-3.
+     *
+     * @hide
+     */
+    @IntDef(value = {SC_VVC_INDEX_SLICE_IDR_W_RADL, SC_VVC_INDEX_SLICE_IDR_N_LP,
+            SC_VVC_INDEX_SLICE_CRA, SC_VVC_INDEX_SLICE_GDR, SC_VVC_INDEX_VPS, SC_VVC_INDEX_SPS,
+            SC_VVC_INDEX_AUD})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScVvcIndex{}
+
+    /**
+     * SC VVC index SLICE_IDR_W_RADL (nal_unit_type=IDR_W_RADL) for random access key frame.
+     */
+    public static final int SC_VVC_INDEX_SLICE_IDR_W_RADL = DemuxScVvcIndex.SLICE_IDR_W_RADL;
+    /**
+     * SC VVC index SLICE_IDR_N_LP (nal_unit_type=IDR_N_LP) for random access key frame.
+     */
+    public static final int SC_VVC_INDEX_SLICE_IDR_N_LP = DemuxScVvcIndex.SLICE_IDR_N_LP;
+    /**
+     * SC VVC index SLICE_CRA (nal_unit_type=CRA_NUT) for random access key frame.
+     */
+    public static final int SC_VVC_INDEX_SLICE_CRA = DemuxScVvcIndex.SLICE_CRA;
+    /**
+     * SC VVC index SLICE_GDR (nal_unit_type=GDR_NUT) for random access point.
+     */
+    public static final int SC_VVC_INDEX_SLICE_GDR = DemuxScVvcIndex.SLICE_GDR;
+    /**
+     * Optional SC VVC index VPS (nal_unit_type=VPS_NUT) for sequence level info.
+     */
+    public static final int SC_VVC_INDEX_VPS = DemuxScVvcIndex.VPS;
+    /**
+     * SC VVC index SPS (nal_unit_type=SPS_NUT) for sequence level info.
+     */
+    public static final int SC_VVC_INDEX_SPS = DemuxScVvcIndex.SPS;
+    /**
+     * SC VVC index AUD (nal_unit_type=AUD_NUT) for AU (frame) boundary.
+     */
+    public static final int SC_VVC_INDEX_AUD = DemuxScVvcIndex.AUD;
+
+    /**
      * @hide
      */
     @IntDef(prefix = "SC_",
@@ -261,6 +308,11 @@
                 SC_INDEX_P_FRAME,
                 SC_INDEX_B_FRAME,
                 SC_INDEX_SEQUENCE,
+                SC_INDEX_I_SLICE,
+                SC_INDEX_P_SLICE,
+                SC_INDEX_B_SLICE,
+                SC_INDEX_SI_SLICE,
+                SC_INDEX_SP_SLICE,
                 SC_HEVC_INDEX_SPS,
                 SC_HEVC_INDEX_AUD,
                 SC_HEVC_INDEX_SLICE_CE_BLA_W_LP,
@@ -269,6 +321,13 @@
                 SC_HEVC_INDEX_SLICE_IDR_W_RADL,
                 SC_HEVC_INDEX_SLICE_IDR_N_LP,
                 SC_HEVC_INDEX_SLICE_TRAIL_CRA,
+                SC_VVC_INDEX_SLICE_IDR_W_RADL,
+                SC_VVC_INDEX_SLICE_IDR_N_LP,
+                SC_VVC_INDEX_SLICE_CRA,
+                SC_VVC_INDEX_SLICE_GDR,
+                SC_VVC_INDEX_VPS,
+                SC_VVC_INDEX_SPS,
+                SC_VVC_INDEX_AUD
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ScIndexMask {}
diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp
index a028c04..58078cf 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -661,6 +661,8 @@
         sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scAvc>();
         // Java uses the values defined by HIDL HAL. Left shift 4 bits.
         sc = sc << 4;
+    } else if (mediaEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scVvc) {
+        sc = mediaEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scVvc>();
     }
 
     jobject obj = env->NewObject(eventClazz, eventInit, streamId, isPtsPresent, pts, isDtsPresent,
@@ -726,6 +728,8 @@
         sc = tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scAvc>();
         // Java uses the values defined by HIDL HAL. Left shift 4 bits.
         sc = sc << 4;
+    } else if (tsRecordEvent.scIndexMask.getTag() == DemuxFilterScIndexMask::Tag::scVvc) {
+        sc = tsRecordEvent.scIndexMask.get<DemuxFilterScIndexMask::Tag::scVvc>();
     }
 
     jint ts = tsRecordEvent.tsIndexMask;
@@ -1819,6 +1823,13 @@
     return (int)result;
 }
 
+bool JTuner::isLnaSupported() {
+    if (sTunerClient == nullptr) {
+        return (int)Result::NOT_INITIALIZED;
+    }
+    return sTunerClient->isLnaSupported();
+}
+
 int JTuner::setLna(bool enable) {
     if (sTunerClient == nullptr) {
         return (int)Result::NOT_INITIALIZED;
@@ -3562,6 +3573,11 @@
     return tuner->setLnb(lnbClient);
 }
 
+static bool android_media_tv_Tuner_is_lna_supported(JNIEnv *env, jobject thiz) {
+    sp<JTuner> tuner = getTuner(env, thiz);
+    return tuner->isLnaSupported();
+}
+
 static int android_media_tv_Tuner_set_lna(JNIEnv *env, jobject thiz, jboolean enable) {
     sp<JTuner> tuner = getTuner(env, thiz);
     return tuner->setLna(enable);
@@ -3807,6 +3823,8 @@
     } else if (scIndexType == DemuxRecordScIndexType::SC_AVC) {
         // Java uses the values defined by HIDL HAL. Right shift 4 bits.
         filterRecordSettings.scIndexMask.set<DemuxFilterScIndexMask::Tag::scAvc>(scIndexMask >> 4);
+    } else if (scIndexType == DemuxRecordScIndexType::SC_VVC) {
+        filterRecordSettings.scIndexMask.set<DemuxFilterScIndexMask::Tag::scVvc>(scIndexMask);
     }
     return filterRecordSettings;
 }
@@ -4810,6 +4828,7 @@
             (void *)android_media_tv_Tuner_scan },
     { "nativeStopScan", "()I", (void *)android_media_tv_Tuner_stop_scan },
     { "nativeSetLnb", "(Landroid/media/tv/tuner/Lnb;)I", (void *)android_media_tv_Tuner_set_lnb },
+    { "nativeIsLnaSupported", "()Z", (void *)android_media_tv_Tuner_is_lna_supported },
     { "nativeSetLna", "(Z)I", (void *)android_media_tv_Tuner_set_lna },
     { "nativeGetFrontendStatus", "([I)Landroid/media/tv/tuner/frontend/FrontendStatus;",
             (void *)android_media_tv_Tuner_get_frontend_status },
diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h
index c74b2df..2b69e89 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -189,6 +189,7 @@
     int scan(const FrontendSettings& settings, FrontendScanType scanType);
     int stopScan();
     int setLnb(sp<LnbClient> lnbClient);
+    bool isLnaSupported();
     int setLna(bool enable);
     jobject openLnbByHandle(int handle);
     jobject openLnbByName(jstring name);
diff --git a/media/jni/tuner/TunerClient.cpp b/media/jni/tuner/TunerClient.cpp
index 8515874..ab28fb4 100644
--- a/media/jni/tuner/TunerClient.cpp
+++ b/media/jni/tuner/TunerClient.cpp
@@ -210,4 +210,17 @@
     return -1;
 }
 
+bool TunerClient::isLnaSupported() {
+    if (mTunerService != nullptr) {
+        bool lnaSupported;
+        Status s = mTunerService->isLnaSupported(&lnaSupported);
+        if (!s.isOk()) {
+            return false;
+        }
+        return lnaSupported;
+    }
+
+    return false;
+}
+
 }  // namespace android
diff --git a/media/jni/tuner/TunerClient.h b/media/jni/tuner/TunerClient.h
index 5410c1b..3f8b21c 100644
--- a/media/jni/tuner/TunerClient.h
+++ b/media/jni/tuner/TunerClient.h
@@ -148,6 +148,11 @@
      */
     int getMaxNumberOfFrontends(FrontendType frontendType);
 
+    /**
+     * Is Low Noise Amplifier (LNA) supported.
+     */
+    bool isLnaSupported();
+
 private:
     /**
      * An AIDL Tuner Service assigned at the first time the Tuner Client connects with
diff --git a/native/android/Android.bp b/native/android/Android.bp
index 8594ba5..254eb44 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -34,6 +34,7 @@
 
 cc_defaults {
     name: "libandroid_defaults",
+    cpp_std: "gnu++20",
     cflags: [
         "-Wall",
         "-Werror",
@@ -94,6 +95,7 @@
         "libpowermanager",
         "android.hardware.configstore@1.0",
         "android.hardware.configstore-utils",
+        "android.hardware.power-V4-ndk",
         "libnativedisplay",
     ],
 
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 7863a7d..9e97bd3 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "perf_hint"
 
+#include <aidl/android/hardware/power/SessionHint.h>
 #include <android/os/IHintManager.h>
 #include <android/os/IHintSession.h>
 #include <android/performance_hint.h>
@@ -25,14 +26,21 @@
 #include <performance_hint_private.h>
 #include <utils/SystemClock.h>
 
+#include <chrono>
 #include <utility>
 #include <vector>
 
 using namespace android;
 using namespace android::os;
 
+using namespace std::chrono_literals;
+
+using AidlSessionHint = aidl::android::hardware::power::SessionHint;
+
 struct APerformanceHintSession;
 
+constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
+
 struct APerformanceHintManager {
 public:
     static APerformanceHintManager* getInstance();
@@ -71,8 +79,12 @@
     const int64_t mPreferredRateNanos;
     // Target duration for choosing update rate
     int64_t mTargetDurationNanos;
-    // Last update timestamp
-    int64_t mLastUpdateTimestamp;
+    // First target hit timestamp
+    int64_t mFirstTargetMetTimestamp;
+    // Last target hit timestamp
+    int64_t mLastTargetMetTimestamp;
+    // Last hint reported from sendHint indexed by hint value
+    std::vector<int64_t> mLastHintSentTimestamp;
     // Cached samples
     std::vector<int64_t> mActualDurationsNanos;
     std::vector<int64_t> mTimestampsNanos;
@@ -144,7 +156,13 @@
       : mHintSession(std::move(session)),
         mPreferredRateNanos(preferredRateNanos),
         mTargetDurationNanos(targetDurationNanos),
-        mLastUpdateTimestamp(elapsedRealtimeNano()) {}
+        mFirstTargetMetTimestamp(0),
+        mLastTargetMetTimestamp(0) {
+    const std::vector<AidlSessionHint> sessionHintRange{ndk::enum_range<AidlSessionHint>().begin(),
+                                                        ndk::enum_range<AidlSessionHint>().end()};
+
+    mLastHintSentTimestamp = std::vector<int64_t>(sessionHintRange.size(), 0);
+}
 
 APerformanceHintSession::~APerformanceHintSession() {
     binder::Status ret = mHintSession->close();
@@ -171,7 +189,8 @@
      */
     mActualDurationsNanos.clear();
     mTimestampsNanos.clear();
-    mLastUpdateTimestamp = elapsedRealtimeNano();
+    mFirstTargetMetTimestamp = 0;
+    mLastTargetMetTimestamp = 0;
     return 0;
 }
 
@@ -184,33 +203,52 @@
     mActualDurationsNanos.push_back(actualDurationNanos);
     mTimestampsNanos.push_back(now);
 
-    /**
-     * Cache the hint if the hint is not overtime and the mLastUpdateTimestamp is
-     * still in the mPreferredRateNanos duration.
-     */
-    if (actualDurationNanos < mTargetDurationNanos &&
-        now - mLastUpdateTimestamp <= mPreferredRateNanos) {
-        return 0;
+    if (actualDurationNanos >= mTargetDurationNanos) {
+        // Reset timestamps if we are equal or over the target.
+        mFirstTargetMetTimestamp = 0;
+    } else {
+        // Set mFirstTargetMetTimestamp for first time meeting target.
+        if (!mFirstTargetMetTimestamp || !mLastTargetMetTimestamp ||
+            (now - mLastTargetMetTimestamp > 2 * mPreferredRateNanos)) {
+            mFirstTargetMetTimestamp = now;
+        }
+        /**
+         * Rate limit the change if the update is over mPreferredRateNanos since first
+         * meeting target and less than mPreferredRateNanos since last meeting target.
+         */
+        if (now - mFirstTargetMetTimestamp > mPreferredRateNanos &&
+            now - mLastTargetMetTimestamp <= mPreferredRateNanos) {
+            return 0;
+        }
+        mLastTargetMetTimestamp = now;
     }
 
     binder::Status ret =
             mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
-    mActualDurationsNanos.clear();
-    mTimestampsNanos.clear();
     if (!ret.isOk()) {
         ALOGE("%s: HintSession reportActualWorkDuration failed: %s", __FUNCTION__,
               ret.exceptionMessage().c_str());
+        mFirstTargetMetTimestamp = 0;
+        mLastTargetMetTimestamp = 0;
         return EPIPE;
     }
-    mLastUpdateTimestamp = now;
+    mActualDurationsNanos.clear();
+    mTimestampsNanos.clear();
+
     return 0;
 }
 
 int APerformanceHintSession::sendHint(int32_t hint) {
-    if (hint < 0) {
-        ALOGE("%s: session hint value must be greater than zero", __FUNCTION__);
+    if (hint < 0 || hint >= static_cast<int32_t>(mLastHintSentTimestamp.size())) {
+        ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
         return EINVAL;
     }
+    int64_t now = elapsedRealtimeNano();
+
+    // Limit sendHint to a pre-detemined rate for safety
+    if (now < (mLastHintSentTimestamp[hint] + SEND_HINT_TIMEOUT)) {
+        return 0;
+    }
 
     binder::Status ret = mHintSession->sendHint(hint);
 
@@ -218,6 +256,7 @@
         ALOGE("%s: HintSession sendHint failed: %s", __FUNCTION__, ret.exceptionMessage().c_str());
         return EPIPE;
     }
+    mLastHintSentTimestamp[hint] = now;
     return 0;
 }
 
diff --git a/native/android/system_fonts.cpp b/native/android/system_fonts.cpp
index 30d0c35..fe3132e 100644
--- a/native/android/system_fonts.cpp
+++ b/native/android/system_fonts.cpp
@@ -66,9 +66,6 @@
         return mFilePath == o.mFilePath && mLocale == o.mLocale && mWeight == o.mWeight &&
                 mItalic == o.mItalic && mCollectionIndex == o.mCollectionIndex && mAxes == o.mAxes;
     }
-
-    AFont() = default;
-    AFont(const AFont&) = default;
 };
 
 struct FontHasher {
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index 1881e60..0c2d3b6 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -122,9 +122,16 @@
     result = APerformanceHint_reportActualWorkDuration(session, -1L);
     EXPECT_EQ(EINVAL, result);
 
-    // Send both valid and invalid session hints
     int hintId = 2;
-    EXPECT_CALL(*iSession, sendHint(Eq(2))).Times(Exactly(1));
+    EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1));
+    result = APerformanceHint_sendHint(session, hintId);
+    EXPECT_EQ(0, result);
+    usleep(110000); // Sleep for longer than the update timeout.
+    EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(1));
+    result = APerformanceHint_sendHint(session, hintId);
+    EXPECT_EQ(0, result);
+    // Expect to get rate limited if we try to send faster than the limiter allows
+    EXPECT_CALL(*iSession, sendHint(Eq(hintId))).Times(Exactly(0));
     result = APerformanceHint_sendHint(session, hintId);
     EXPECT_EQ(0, result);
 
diff --git a/packages/CarrierDefaultApp/res/values-af/strings.xml b/packages/CarrierDefaultApp/res/values-af/strings.xml
index 51cb6c8..3bc18ce 100644
--- a/packages/CarrierDefaultApp/res/values-af/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-af/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Die netwerk waarby jy probeer aansluit, het sekuriteitkwessies."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Byvoorbeeld, die aanmeldbladsy behoort dalk nie aan die organisasie wat gewys word nie."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Gaan in elk geval deur blaaier voort"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-am/strings.xml b/packages/CarrierDefaultApp/res/values-am/strings.xml
index d5d50ac..0efdbc4 100644
--- a/packages/CarrierDefaultApp/res/values-am/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-am/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ለመቀላቀል እየሞከሩ ያሉት አውታረ መረብ የደህንነት ችግሮች አሉበት።"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ለምሳሌ፣ የመግቢያ ገጹ የሚታየው ድርጅት ላይሆን ይችላል።"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ለማንኛውም በአሳሽ በኩል ይቀጥሉ"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ar/strings.xml b/packages/CarrierDefaultApp/res/values-ar/strings.xml
index 0c67de7..cd979b2 100644
--- a/packages/CarrierDefaultApp/res/values-ar/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ar/strings.xml
@@ -16,4 +16,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"الشبكة التي تحاول الانضمام إليها بها مشاكل أمنية."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"على سبيل المثال، قد لا تنتمي صفحة تسجيل الدخول إلى المؤسسة المعروضة."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"المتابعة على أي حال عبر المتصفح"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-as/strings.xml b/packages/CarrierDefaultApp/res/values-as/strings.xml
index 4b36b06..fdafe2b 100644
--- a/packages/CarrierDefaultApp/res/values-as/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-as/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"আপুনি সংযোগ কৰিবলৈ বিচৰা নেটৱৰ্কটোত সুৰক্ষাজনিত সমস্যা আছে।"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"উদাহৰণস্বৰূপে, আপোনাক দেখুওৱা লগ ইনৰ পৃষ্ঠাটো প্ৰতিষ্ঠানটোৰ নিজা নহ\'বও পাৰে।"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"তথাপিও ব্ৰাউজাৰৰ জৰিয়তে অব্যাহত ৰাখক"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-az/strings.xml b/packages/CarrierDefaultApp/res/values-az/strings.xml
index d1af3c9..32c3c1c 100644
--- a/packages/CarrierDefaultApp/res/values-az/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-az/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Qoşulmaq istədiyiniz şəbəkənin təhlükəsizlik problemləri var."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Məsələn, giriş səhifəsi göstərilən təşkilata aid olmaya bilər."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Hər bir halda brazuer ilə davam edin"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
index 5d55790..932fc03 100644
--- a/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-b+sr+Latn/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate da se pridružite ima bezbednosnih problema."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Na primer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko pregledača"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-be/strings.xml b/packages/CarrierDefaultApp/res/values-be/strings.xml
index 3ad85f2..20606f6 100644
--- a/packages/CarrierDefaultApp/res/values-be/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-be/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"У сеткі, да якой вы спрабуеце далучыцца, ёсць праблемы з бяспекай."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Напрыклад, старонка ўваходу можа не належаць указанай арганізацыі."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Усё роўна працягнуць праз браўзер"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-bg/strings.xml b/packages/CarrierDefaultApp/res/values-bg/strings.xml
index f5308f0..46a9db5 100644
--- a/packages/CarrierDefaultApp/res/values-bg/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bg/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Мрежата, към която опитвате да се присъедините, има проблеми със сигурността."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Например страницата за вход може да не принадлежи на показаната организация."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Продължаване през браузър въпреки това"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-bn/strings.xml b/packages/CarrierDefaultApp/res/values-bn/strings.xml
index 448c42b3..0826ae1 100644
--- a/packages/CarrierDefaultApp/res/values-bn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bn/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"আপনি যে নেটওয়ার্কে যোগ দেওয়ার চেষ্টা করছেন সেটিতে নিরাপত্তাজনিত সমস্যা আছে।"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"যেমন, লগ-ইন পৃষ্ঠাটি যে প্রতিষ্ঠানের পৃষ্ঠা বলে দেখানো আছে, আসলে তা নাও হতে পারে৷"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"যাই হোক, ব্রাউজারের মাধ্যমে চালিয়ে যান"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-bs/strings.xml b/packages/CarrierDefaultApp/res/values-bs/strings.xml
index bc1ff33..e2bc342 100644
--- a/packages/CarrierDefaultApp/res/values-bs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-bs/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj pokušavate pristupiti ima sigurnosnih problema."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Naprimjer, stranica za prijavljivanje možda ne pripada prikazanoj organizaciji."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi preko preglednika"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ca/strings.xml b/packages/CarrierDefaultApp/res/values-ca/strings.xml
index 66a8f37..bdde567 100644
--- a/packages/CarrierDefaultApp/res/values-ca/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ca/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"La xarxa a què et vols connectar té problemes de seguretat."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Per exemple, la pàgina d\'inici de sessió podria no pertànyer a l\'organització que es mostra."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continua igualment mitjançant el navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-cs/strings.xml b/packages/CarrierDefaultApp/res/values-cs/strings.xml
index 5431836..d5fdac9 100644
--- a/packages/CarrierDefaultApp/res/values-cs/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-cs/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Síť, ke které se pokoušíte připojit, má bezpečnostní problémy."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Přihlašovací stránka například nemusí patřit zobrazované organizaci."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Přesto pokračovat prostřednictvím prohlížeče"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-da/strings.xml b/packages/CarrierDefaultApp/res/values-da/strings.xml
index b212117..8b2bb7c 100644
--- a/packages/CarrierDefaultApp/res/values-da/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-da/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Der er sikkerhedsproblemer på det netværk, du forsøger at logge ind på."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Det er f.eks. ikke sikkert, at loginsiden tilhører den anførte organisation."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsæt alligevel via browseren"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-de/strings.xml b/packages/CarrierDefaultApp/res/values-de/strings.xml
index 95639ad..21af41c 100644
--- a/packages/CarrierDefaultApp/res/values-de/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-de/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Im Netzwerk, zu dem du eine Verbindung herstellen möchtest, liegen Sicherheitsprobleme vor."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Beispiel: Die Log-in-Seite gehört eventuell nicht zur angezeigten Organisation."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Trotzdem in einem Browser fortfahren"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-el/strings.xml b/packages/CarrierDefaultApp/res/values-el/strings.xml
index 016e68f..7514314 100644
--- a/packages/CarrierDefaultApp/res/values-el/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-el/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Παρουσιάζονται προβλήματα ασφάλειας στο δίκτυο στο οποίο προσπαθείτε να συνδεθείτε."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Για παράδειγμα, η σελίδα σύνδεσης ενδέχεται να μην ανήκει στον οργανισμό που εμφανίζεται."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Συνέχεια ούτως ή άλλως μέσω του προγράμματος περιήγησης"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
index a925a30..11d9437 100644
--- a/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rAU/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"The network that you’re trying to join has security issues."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Network boost"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommends a data boost"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Buy a network boost for better performance"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Not now"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Manage"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Purchase a network boost."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
index a925a30..b5e53ae 100644
--- a/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rCA/strings.xml
@@ -2,7 +2,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
-    <string name="android_system_label" msgid="2797790869522345065">"Mobile Operator"</string>
+    <string name="android_system_label" msgid="2797790869522345065">"Mobile Carrier"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Mobile data has run out"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"Your mobile data has been deactivated"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"Tap to visit the %s website"</string>
@@ -11,7 +11,13 @@
     <string name="no_mobile_data_connection" msgid="544980465184147010">"Add data or roaming plan through %s"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobile data status"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Sign in to mobile network"</string>
-    <string name="ssl_error_warning" msgid="3127935140338254180">"The network that you’re trying to join has security issues."</string>
-    <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
+    <string name="ssl_error_warning" msgid="3127935140338254180">"The network you’re trying to join has security issues."</string>
+    <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page may not belong to the organization shown."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Network boost"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommends a data boost"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Buy a network boost for better performance"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Not now"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Manage"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Purchase a network boost."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
index a925a30..11d9437 100644
--- a/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rGB/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"The network that you’re trying to join has security issues."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Network boost"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommends a data boost"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Buy a network boost for better performance"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Not now"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Manage"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Purchase a network boost."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
index a925a30..11d9437 100644
--- a/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rIN/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"The network that you’re trying to join has security issues."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"For example, the login page might not belong to the organisation shown."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continue anyway via browser"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Network boost"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recommends a data boost"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Buy a network boost for better performance"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Not now"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Manage"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Purchase a network boost."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
index d7ae1ce..f8a50e4 100644
--- a/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-en-rXC/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‎‏‎‏‎‎‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‎‎‎The network you’re trying to join has security issues.‎‏‎‎‏‎"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‏‏‎‎‎For example, the login page may not belong to the organization shown.‎‏‎‎‏‎"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‏‏‏‎‎‎‎‎‎Continue anyway via browser‎‏‎‎‏‎"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‎Network boost‎‏‎‎‏‎"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‏‎‎‎‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎%s recommends a data boost‎‏‎‎‏‎"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‎‎‏‏‎‎‎‎‎‎Buy a network boost for better performance‎‏‎‎‏‎"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‎‏‎‎‏‏‎‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‎Not now‎‏‎‎‏‎"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‎‏‏‏‏‏‎‏‎‎‎‎‏‏‏‎‏‎‎‏‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎Manage‎‏‎‎‏‎"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎‎‏‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‎‏‏‏‎‏‎‏‎‎‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‎‎Purchase a network boost.‎‏‎‎‏‎"</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
index 0455603..bddae48 100644
--- a/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es-rUS/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"La red a la que intentas conectarte tiene problemas de seguridad."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de acceso no pertenezca a la organización que aparece."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos desde el navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-es/strings.xml b/packages/CarrierDefaultApp/res/values-es/strings.xml
index b5d038c..dd56770 100644
--- a/packages/CarrierDefaultApp/res/values-es/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-es/strings.xml
@@ -8,10 +8,22 @@
     <string name="portal_notification_detail" msgid="2295729385924660881">"Toca para acceder al sitio web de %s"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Ponte en contacto con tu proveedor de servicios (%s)"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Sin conexión de datos móviles"</string>
-    <string name="no_mobile_data_connection" msgid="544980465184147010">"Añade un plan de datos o de itinerancia a través de %s"</string>
+    <string name="no_mobile_data_connection" msgid="544980465184147010">"Añade un plan de datos o de roaming a través de %s"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Estado de la conexión de datos móviles"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Iniciar sesión en una red móvil"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"La red a la que intentas unirte tiene problemas de seguridad."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por ejemplo, es posible que la página de inicio de sesión no pertenezca a la organización mostrada."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar de todos modos a través del navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-et/strings.xml b/packages/CarrierDefaultApp/res/values-et/strings.xml
index 28cc9a9..8cdc291 100644
--- a/packages/CarrierDefaultApp/res/values-et/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-et/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Võrgul, millega üritate ühenduse luua, on turvaprobleeme."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Näiteks ei pruugi sisselogimisleht kuuluda kuvatavale organisatsioonile."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Jätka siiski brauseris"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-eu/strings.xml b/packages/CarrierDefaultApp/res/values-eu/strings.xml
index 04e641f..22565dc 100644
--- a/packages/CarrierDefaultApp/res/values-eu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-eu/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Erabili nahi duzun sareak segurtasun-arazoak ditu."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Adibidez, baliteke saioa hasteko orria adierazitako erakundearena ez izatea."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Jarraitu arakatzailearen bidez, halere"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-fa/strings.xml b/packages/CarrierDefaultApp/res/values-fa/strings.xml
index 5328a03..ecb9930 100644
--- a/packages/CarrierDefaultApp/res/values-fa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fa/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"شبکه‌ای که می‌خواهید به آن بپیوندید مشکلات امنیتی دارد."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"به عنوان مثال، صفحه ورود به سیستم ممکن است متعلق به سازمان نشان داده شده نباشد."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"درهر صورت ازطریق مرورگر ادامه یابد"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-fi/strings.xml b/packages/CarrierDefaultApp/res/values-fi/strings.xml
index d416c1d..850f9db 100644
--- a/packages/CarrierDefaultApp/res/values-fi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fi/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Verkossa, johon yrität muodostaa yhteyttä, havaittiin turvallisuusongelmia."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Kirjautumissivu ei välttämättä kuulu näytetylle organisaatiolle."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Jatka selaimen kautta"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
index 1b8c262..61fc2e4 100644
--- a/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr-rCA/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Le réseau que vous essayez de joindre présente des problèmes de sécurité."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion pourrait ne pas appartenir à l\'organisation représentée."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans un navigateur"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-fr/strings.xml b/packages/CarrierDefaultApp/res/values-fr/strings.xml
index 3ae9570..ef1857d 100644
--- a/packages/CarrierDefaultApp/res/values-fr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-fr/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Le réseau auquel vous essayez de vous connecter présente des problèmes de sécurité."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Par exemple, la page de connexion peut ne pas appartenir à l\'organisation représentée."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuer quand même dans le navigateur"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-gl/strings.xml b/packages/CarrierDefaultApp/res/values-gl/strings.xml
index 4f199ca..6dde8a8 100644
--- a/packages/CarrierDefaultApp/res/values-gl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gl/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"A rede á que tentas unirte ten problemas de seguranza."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, é posible que a páxina de inicio de sesión non pertenza á organización que se mostra."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar igualmente co navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-gu/strings.xml b/packages/CarrierDefaultApp/res/values-gu/strings.xml
index 57710d0..473a035 100644
--- a/packages/CarrierDefaultApp/res/values-gu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-gu/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"તમે જોડાવાનો પ્રયાસ કરી રહ્યા છો તે નેટવર્કમાં સુરક્ષા સંબંધી સમસ્યાઓ છે."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ઉદાહરણ તરીકે, લોગિન પૃષ્ઠ બતાવવામાં આવેલી સંસ્થાનું ન પણ હોય."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"તો પણ બ્રાઉઝર મારફતે ચાલુ રાખો"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-hi/strings.xml b/packages/CarrierDefaultApp/res/values-hi/strings.xml
index b9d6f42..d878c1c 100644
--- a/packages/CarrierDefaultApp/res/values-hi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hi/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"आप जिस नेटवर्क में शामिल होने की कोशिश कर रहे हैं उसमें सुरक्षा से जुड़ी समस्‍याएं हैं."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरण के लिए, हो सकता है कि लॉगिन पेज दिखाए गए संगठन का ना हो."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ब्राउज़र के ज़रिए किसी भी तरह जारी रखें"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-hr/strings.xml b/packages/CarrierDefaultApp/res/values-hr/strings.xml
index 66531a7..0da2280 100644
--- a/packages/CarrierDefaultApp/res/values-hr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hr/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mreža kojoj se pokušavate pridružiti ima sigurnosne poteškoće."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Na primjer, stranica za prijavu možda ne pripada prikazanoj organizaciji."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Ipak nastavi putem preglednika"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml
index 4ae6ea6..95c1db8 100644
--- a/packages/CarrierDefaultApp/res/values-hu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml
@@ -8,10 +8,22 @@
     <string name="portal_notification_detail" msgid="2295729385924660881">"Koppintson a(z) %s webhely meglátogatásához"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Vegye fel a kapcsolatot szolgáltatójával (%s)"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nincs mobiladat-kapcsolat"</string>
-    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy barangolási csomagot a következőn keresztül: %s"</string>
+    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy roamingcsomagot a következőn keresztül: %s"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobiladat-állapot"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Bejelentkezés a mobilhálózatra"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Például lehetséges, hogy a bejelentkezési oldal nem a megjelenített szervezethez tartozik."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Folytatás ennek ellenére böngészőn keresztül"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-hy/strings.xml b/packages/CarrierDefaultApp/res/values-hy/strings.xml
index 99398bc..a846e04 100644
--- a/packages/CarrierDefaultApp/res/values-hy/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-hy/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Ցանցը, որին փորձում եք միանալ, անվտանգության խնդիրներ ունի:"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Օրինակ՝ մուտքի էջը կարող է ցուցադրված կազմակերպության էջը չլինել:"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Շարունակել դիտարկիչի միջոցով"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-in/strings.xml b/packages/CarrierDefaultApp/res/values-in/strings.xml
index f48d31f..488ad09 100644
--- a/packages/CarrierDefaultApp/res/values-in/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-in/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Jaringan yang ingin Anda masuki memiliki masalah keamanan."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Misalnya, halaman login mungkin bukan milik organisasi yang ditampilkan."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Tetap lanjutkan melalui browser"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-is/strings.xml b/packages/CarrierDefaultApp/res/values-is/strings.xml
index cdba5be..ab4981d 100644
--- a/packages/CarrierDefaultApp/res/values-is/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-is/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Öryggisvandamál eru á netinu sem þú ert að reyna að tengjast."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Til dæmis getur verið að innskráningarsíðan tilheyri ekki fyrirtækinu sem birtist."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Halda samt áfram í vafra"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-it/strings.xml b/packages/CarrierDefaultApp/res/values-it/strings.xml
index a62ae86..95ea060 100644
--- a/packages/CarrierDefaultApp/res/values-it/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-it/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"La rete a cui stai tentando di accedere presenta problemi di sicurezza."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Ad esempio, la pagina di accesso potrebbe non appartenere all\'organizzazione indicata."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continua comunque dal browser"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-iw/strings.xml b/packages/CarrierDefaultApp/res/values-iw/strings.xml
index 550936c..263ed1a 100644
--- a/packages/CarrierDefaultApp/res/values-iw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-iw/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"יש בעיות אבטחה ברשת שאליה אתה מנסה להתחבר."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"לדוגמה, ייתכן שדף ההתחברות אינו שייך לארגון המוצג."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"המשך בכל זאת באמצעות דפדפן"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ja/strings.xml b/packages/CarrierDefaultApp/res/values-ja/strings.xml
index e5977ae..3b22ae1 100644
--- a/packages/CarrierDefaultApp/res/values-ja/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ja/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"接続しようとしているネットワークにセキュリティの問題があります。"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"たとえば、ログインページが表示されている組織に属していない可能性があります。"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ブラウザから続行"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ka/strings.xml b/packages/CarrierDefaultApp/res/values-ka/strings.xml
index 91ae46d..4b9cd38 100644
--- a/packages/CarrierDefaultApp/res/values-ka/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ka/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ქსელს, რომელთან დაკავშრებასაც ცდილობთ, უსაფრთხოების პრობლემები აქვს."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"მაგალითად, სისტემაში შესვლის გვერდი შეიძლება არ ეკუთვნოდეს ნაჩვენებ ორგანიზაციას."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"მაინც ბრაუზერში გაგრძელება"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-kk/strings.xml b/packages/CarrierDefaultApp/res/values-kk/strings.xml
index 0fb57bc..fce8dd2 100644
--- a/packages/CarrierDefaultApp/res/values-kk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kk/strings.xml
@@ -3,15 +3,27 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
     <string name="android_system_label" msgid="2797790869522345065">"Мобильдік байланыс операторы"</string>
-    <string name="portal_notification_id" msgid="5155057562457079297">"Мобильдік деректер бітті"</string>
-    <string name="no_data_notification_id" msgid="668400731803969521">"Мобильдік деректер өшірілді"</string>
+    <string name="portal_notification_id" msgid="5155057562457079297">"Мобильдік интернет бітті"</string>
+    <string name="no_data_notification_id" msgid="668400731803969521">"Мобильдік интернет өшірілді"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"%s вебсайтына кіру үшін түртіңіз"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Қызмет көрсетушіге (%s) хабарласыңыз"</string>
-    <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобильдік деректер байланысы жоқ"</string>
+    <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобильдік интернет байланысы жоқ"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"%s арқылы деректер не роуминг жоспарын енгізу"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Мобильді деректер күйі"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Мобильдік желіге тіркелу"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Қосылайын деп жатқан желіңізде қауіпсіздік мәселелері бар."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Мысалы, кіру беті көрсетілген ұйымға тиесілі болмауы мүмкін."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Бәрібір браузер арқылы жалғастыру"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-km/strings.xml b/packages/CarrierDefaultApp/res/values-km/strings.xml
index 6ef1066..983f09e 100644
--- a/packages/CarrierDefaultApp/res/values-km/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-km/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"បណ្តាញដែលអ្នកកំពុងព្យាយាមចូលមានបញ្ហាសុវត្ថិភាព។"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ឧទាហរណ៍៖ ទំព័រចូលនេះអាចនឹងមិនមែនជាកម្មសិទ្ធិរបស់ស្ថាប័នដែលបានបង្ហាញនេះទេ។"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"យ៉ាងណាក៏ដោយនៅតែបន្តតាមរយៈកម្មវិធីរុករកតាមអ៊ីនធឺណិត"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-kn/strings.xml b/packages/CarrierDefaultApp/res/values-kn/strings.xml
index ea4b09a..86b29ce 100644
--- a/packages/CarrierDefaultApp/res/values-kn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-kn/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ನೀವು ಸೇರಬೇಕೆಂದಿರುವ ನೆಟ್‌ವರ್ಕ್, ಭದ್ರತೆ ಸಮಸ್ಯೆಗಳನ್ನು ಹೊಂದಿದೆ."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ಉದಾಹರಣೆಗೆ, ಲಾಗಿನ್ ಪುಟವು ತೋರಿಸಲಾಗಿರುವ ಸಂಸ್ಥೆಗೆ ಸಂಬಂಧಿಸಿಲ್ಲದಿರಬಹುದು."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ಪರವಾಗಿಲ್ಲ, ಬ್ರೌಸರ್ ಮೂಲಕ ಮುಂದುವರಿಸಿ"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ko/strings.xml b/packages/CarrierDefaultApp/res/values-ko/strings.xml
index d6b3d61..3c6f4a6 100644
--- a/packages/CarrierDefaultApp/res/values-ko/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ko/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"가입하려는 네트워크에 보안 문제가 있습니다."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"예를 들어 로그인 페이지가 표시된 조직에 속하지 않을 수 있습니다."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"브라우저를 통해 계속하기"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml
index 199476f..3cece7d 100644
--- a/packages/CarrierDefaultApp/res/values-ky/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml
@@ -1,17 +1,29 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_name" msgid="5247871339820894594">"ОператордунДемейкиКолдонмосу"</string>
+    <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
     <string name="android_system_label" msgid="2797790869522345065">"Мобилдик байланыш оператору"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Мобилдик Интернетиңиздин трафиги түгөндү"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"Мобилдик Интернет өчүрүлгөн"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"%s сайтына баш багуу үчүн басыңыз"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"%s Интернет провайдери менен байланышыңыз"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобилдик Интернет жок"</string>
-    <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу дайындарды же роуминг планын кошуу"</string>
+    <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу маалыматтарды же роуминг планын кошуу"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Мобилдик Интернеттин абалы"</string>
     <string name="action_bar_label" msgid="4290345990334377177">"Мобилдик тармакка кирүү"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Мисалы, аккаунтка кирүү баракчасы көрсөтүлгөн уюмга таандык эмес болушу мүмкүн."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Баары бир серепчи аркылуу улантуу"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-lo/strings.xml b/packages/CarrierDefaultApp/res/values-lo/strings.xml
index 4a21d7c..c6c0533 100644
--- a/packages/CarrierDefaultApp/res/values-lo/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lo/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ເຄືອຂ່າຍທີ່ທ່ານກຳລັງເຂົ້າຮ່ວມມີບັນຫາຄວາມປອດໄພ."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ຕົວຢ່າງ, ໜ້າເຂົ້າສູ່ລະບົບອາດຈະບໍ່ແມ່ນຂອງອົງກອນທີ່ປາກົດ."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ດຳເນີນການຕໍ່ຜ່ານໂປຣແກຣມທ່ອງເວັບ"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-lt/strings.xml b/packages/CarrierDefaultApp/res/values-lt/strings.xml
index be452b7..fe33b1d 100644
--- a/packages/CarrierDefaultApp/res/values-lt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lt/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Kilo tinklo, prie kurio bandote prisijungti, saugos problemų."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Pavyzdžiui, prisijungimo puslapis gali nepriklausyti rodomai organizacijai."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Vis tiek tęsti naudojant naršyklę"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-lv/strings.xml b/packages/CarrierDefaultApp/res/values-lv/strings.xml
index 80a9b58..f8864e2 100644
--- a/packages/CarrierDefaultApp/res/values-lv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-lv/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Tīklā, kuram mēģināt pievienoties, ir drošības problēmas."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Piemēram, pieteikšanās lapa, iespējams, nepieder norādītajai organizācijai."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Tomēr turpināt, izmantojot pārlūkprogrammu"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-mk/strings.xml b/packages/CarrierDefaultApp/res/values-mk/strings.xml
index 96b222c..0b8daaf 100644
--- a/packages/CarrierDefaultApp/res/values-mk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mk/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Мрежата на која се обидувате да се придружите има проблеми со безбедноста."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"На пример, страницата за најавување може да не припаѓа на прикажаната организација."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Сепак продолжи преку прелистувач"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ml/strings.xml b/packages/CarrierDefaultApp/res/values-ml/strings.xml
index ae08ade..f27d4d8 100644
--- a/packages/CarrierDefaultApp/res/values-ml/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ml/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"നിങ്ങൾ ചേരാൻ ശ്രമിക്കുന്ന നെറ്റ്‌വർക്കിൽ സുരക്ഷാ പ്രശ്‌നങ്ങളുണ്ടായിരിക്കാം."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ഉദാഹരണത്തിന്, കാണിച്ചിരിക്കുന്ന ഓർഗനൈസേഷന്റേതായിരിക്കില്ല ലോഗിൻ പേജ്."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"എന്തായാലും ബ്രൗസർ വഴി തുടരുക"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-mn/strings.xml b/packages/CarrierDefaultApp/res/values-mn/strings.xml
index 1a9b72e..354bd34 100644
--- a/packages/CarrierDefaultApp/res/values-mn/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mn/strings.xml
@@ -5,7 +5,7 @@
     <string name="android_system_label" msgid="2797790869522345065">"Мобайл оператор компани"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Мобайл дата дууссан"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"Таны мобайл датаг идэвхгүй болгосон"</string>
-    <string name="portal_notification_detail" msgid="2295729385924660881">"%s вэб хуудсанд зочлохын тулд товших"</string>
+    <string name="portal_notification_detail" msgid="2295729385924660881">"%s веб хуудсанд зочлохын тулд товших"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"%s үйлчилгээ үзүүлэгчтэйгээ холбогдоно уу"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобайл дата холболт алга"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"Дата эсвэл роуминг төлөвлөгөөг %s-р нэмнэ үү"</string>
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Таны холбогдох гэж буй сүлжээ аюулгүй байдлын асуудалтай байна."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Жишээлбэл нэвтрэх хуудас нь харагдаж буй байгууллагынх биш байж болно."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Ямар ч тохиолдолд хөтчөөр үргэлжлүүлэх"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-mr/strings.xml b/packages/CarrierDefaultApp/res/values-mr/strings.xml
index 79cc4aa..c61d3c8 100644
--- a/packages/CarrierDefaultApp/res/values-mr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-mr/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"तुम्ही ज्या नेटवर्कमध्‍ये सामील होण्याचा प्रयत्न करत आहात त्यात सुरक्षितता समस्या आहेत."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणार्थ, लॉग इन पृष्‍ठ दर्शवलेल्या संस्थेच्या मालकीचे नसू शकते."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"तरीही ब्राउझरद्वारे सुरू ठेवा"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ms/strings.xml b/packages/CarrierDefaultApp/res/values-ms/strings.xml
index 7aca5f0..366463f 100644
--- a/packages/CarrierDefaultApp/res/values-ms/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ms/strings.xml
@@ -5,7 +5,7 @@
     <string name="android_system_label" msgid="2797790869522345065">"Pembawa Mudah Alih"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Data mudah alih telah habis"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"Data mudah alih anda telah dinyahaktifkan"</string>
-    <string name="portal_notification_detail" msgid="2295729385924660881">"Ketik untuk melawat tapak web %s"</string>
+    <string name="portal_notification_detail" msgid="2295729385924660881">"Ketik untuk melawat laman web %s"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"Sila hubungi penyedia perkhidmatan anda, %s"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Tiada sambungan data mudah alih"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"Tambahkan data atau pelan perayauan melalui %s"</string>
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Rangkaian yang cuba anda sertai mempunyai isu keselamatan."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Contohnya, halaman log masuk mungkin bukan milik organisasi yang ditunjukkan."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Teruskan juga melalui penyemak imbas"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-my/strings.xml b/packages/CarrierDefaultApp/res/values-my/strings.xml
index 82372f9..2fa6188 100644
--- a/packages/CarrierDefaultApp/res/values-my/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-my/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"သင်ချိတ်ဆက်ရန် ကြိုးစားနေသည့် ကွန်ရက်တွင် လုံခြုံရေးပြဿနာများ ရှိနေသည်။"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ဥပမာ− ဝင်ရောက်ရန် စာမျက်နှာသည် ပြသထားသည့် အဖွဲ့အစည်းနှင့် သက်ဆိုင်မှုမရှိခြင်း ဖြစ်နိုင်ပါသည်။"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"မည်သို့ပင်ဖြစ်စေ ဘရောက်ဇာမှတစ်ဆင့် ရှေ့ဆက်ရန်"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-nb/strings.xml b/packages/CarrierDefaultApp/res/values-nb/strings.xml
index 1bb9826..16f8eaa 100644
--- a/packages/CarrierDefaultApp/res/values-nb/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nb/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Nettverket du prøver å logge på, har sikkerhetsproblemer."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Det er for eksempel mulig at påloggingssiden ikke tilhører organisasjonen som vises."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsett likevel via nettleseren"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ne/strings.xml b/packages/CarrierDefaultApp/res/values-ne/strings.xml
index 2349f9d..cb175df 100644
--- a/packages/CarrierDefaultApp/res/values-ne/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ne/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"तपाईंले सामेल हुने प्रयास गरिरहनु भएको नेटवर्कमा सुरक्षा सम्बन्धी समस्याहरू छन्।"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"उदाहरणका लागि, लग इन पृष्ठ देखाइएको संस्थाको नहुन सक्छ।"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"जे भए पनि ब्राउजर मार्फत जारी राख्नुहोस्"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-nl/strings.xml b/packages/CarrierDefaultApp/res/values-nl/strings.xml
index 4e2c09b..8511ff5 100644
--- a/packages/CarrierDefaultApp/res/values-nl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-nl/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Het netwerk waarmee je verbinding probeert te maken, heeft beveiligingsproblemen."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Zo hoort de weergegeven inlogpagina misschien niet bij de weergegeven organisatie."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Toch doorgaan via browser"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-or/strings.xml b/packages/CarrierDefaultApp/res/values-or/strings.xml
index fd51ed0..65fd7bb 100644
--- a/packages/CarrierDefaultApp/res/values-or/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-or/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ଆପଣ ଯୋଗ ଦେବାକୁ ଚେଷ୍ଟା କରୁଥିବା ନେଟୱର୍କର ସୁରକ୍ଷା ସମସ୍ୟା ଅଛି।"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ଉଦାହରଣସ୍ୱରୂପ, ଲଗଇନ୍‍ ପୃଷ୍ଠା ଦେଖାଯାଇଥିବା ସଂସ୍ଥାର ହୋଇନଥାଇପାରେ।"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ବ୍ରାଉଜର୍‍ ଜରିଆରେ ଯେମିତିବି ହେଉ ଜାରି ରଖନ୍ତୁ"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-pa/strings.xml b/packages/CarrierDefaultApp/res/values-pa/strings.xml
index f4d4053..0f096ab 100644
--- a/packages/CarrierDefaultApp/res/values-pa/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pa/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ਤੁਸੀਂ ਜਿਸ ਨੈੱਟਵਰਕ ਵਿੱਚ ਸ਼ਾਮਲ ਹੋਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰ ਰਹੇ ਹੋ ਉਸ ਵਿੱਚ ਸੁਰੱਖਿਆ ਸਬੰਧੀ ਸਮੱਸਿਆਵਾਂ ਹਨ।"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ਉਦਾਹਰਣ ਵੱਜੋਂ, ਲੌਗ-ਇਨ ਪੰਨਾ ਦਿਖਾਈ ਗਈ ਸੰਸਥਾ ਨਾਲ ਸੰਬੰਧਿਤ ਨਹੀਂ ਹੋ ਸਕਦਾ ਹੈ।"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ਬ੍ਰਾਊਜ਼ਰ ਰਾਹੀਂ ਫਿਰ ਵੀ ਜਾਰੀ ਰੱਖੋ"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-pl/strings.xml b/packages/CarrierDefaultApp/res/values-pl/strings.xml
index ac45e27..08bc767 100644
--- a/packages/CarrierDefaultApp/res/values-pl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pl/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"W sieci, z którą próbujesz się połączyć, występują problemy z zabezpieczeniami."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Na przykład strona logowania może nie należeć do wyświetlanej organizacji."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Kontynuuj mimo to w przeglądarce"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
index 926de65..23b4152 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rBR/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
index 107a9c2..34a564d 100644
--- a/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt-rPT/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"A rede à qual está a tentar aceder tem problemas de segurança."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de início de sessão pode não pertencer à entidade apresentada."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim através do navegador"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Otimização de rede"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s recomenda um serviço de otimização de dados"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Compre um serviço de otimização de rede para melhorar o desempenho"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Agora não"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Gerir"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Comprar um serviço de otimização de rede."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-pt/strings.xml b/packages/CarrierDefaultApp/res/values-pt/strings.xml
index 926de65..23b4152 100644
--- a/packages/CarrierDefaultApp/res/values-pt/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-pt/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"A rede à qual você está tentando se conectar tem problemas de segurança."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Por exemplo, a página de login pode não pertencer à organização mostrada."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Continuar mesmo assim pelo navegador"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ro/strings.xml b/packages/CarrierDefaultApp/res/values-ro/strings.xml
index b91aa813..165952c 100644
--- a/packages/CarrierDefaultApp/res/values-ro/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ro/strings.xml
@@ -5,13 +5,25 @@
     <string name="android_system_label" msgid="2797790869522345065">"Operator de telefonie mobilă"</string>
     <string name="portal_notification_id" msgid="5155057562457079297">"Datele mobile au expirat"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"Datele mobile au fost dezactivate"</string>
-    <string name="portal_notification_detail" msgid="2295729385924660881">"Atingeți pentru a accesa site-ul %s"</string>
-    <string name="no_data_notification_detail" msgid="3112125343857014825">"Contactați furnizorul de servicii %s"</string>
+    <string name="portal_notification_detail" msgid="2295729385924660881">"Atinge pentru a accesa site-ul %s"</string>
+    <string name="no_data_notification_detail" msgid="3112125343857014825">"Contactează furnizorul de servicii %s"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nu există o conexiune de date mobile"</string>
-    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adăugați un plan de date sau de roaming prin %s"</string>
+    <string name="no_mobile_data_connection" msgid="544980465184147010">"Adaugă un plan de date sau de roaming prin %s"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Starea datelor mobile"</string>
-    <string name="action_bar_label" msgid="4290345990334377177">"Conectați-vă la rețeaua mobilă"</string>
+    <string name="action_bar_label" msgid="4290345990334377177">"Conectează-te la rețeaua mobilă"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"Rețeaua la care încercați să vă conectați are probleme de securitate."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"De exemplu, este posibil ca pagina de conectare să nu aparțină organizației afișate."</string>
-    <string name="ssl_error_continue" msgid="1138548463994095584">"Continuați oricum prin browser"</string>
+    <string name="ssl_error_continue" msgid="1138548463994095584">"Continuă oricum prin browser"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ru/strings.xml b/packages/CarrierDefaultApp/res/values-ru/strings.xml
index ff24f1f..77ce91f 100644
--- a/packages/CarrierDefaultApp/res/values-ru/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ru/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Сеть, к которой вы хотите подключиться, небезопасна."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Например, страница входа в аккаунт может быть фиктивной."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Продолжить в браузере"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-si/strings.xml b/packages/CarrierDefaultApp/res/values-si/strings.xml
index 378a534..fe981ca 100644
--- a/packages/CarrierDefaultApp/res/values-si/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-si/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"ඔබ සම්බන්ධ වීමට උත්සහ කරන ජාලයේ ආරක්ෂක ගැටළු ඇත."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"උදාහරණයක් ලෙස, පුරනය වන පිටුව පෙන්වා ඇති සංවිධානයට අයිති නැති විය හැක."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"කෙසේ වුවත් බ්‍රවුසරය හරහා ඉදිරියට යන්න"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sk/strings.xml b/packages/CarrierDefaultApp/res/values-sk/strings.xml
index 9fe38da..1a2ef10 100644
--- a/packages/CarrierDefaultApp/res/values-sk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sk/strings.xml
@@ -14,4 +14,10 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Sieť, ku ktorej sa pokúšate pripojiť, má problémy so zabezpečením"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Napríklad prihlasovacia stránka nemusí patriť uvedenej organizácii."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Pokračovať pomocou prehliadača"</string>
+    <string name="network_boost_notification_channel" msgid="5430986172506159199">"Zrýchlenie siete"</string>
+    <string name="network_boost_notification_title" msgid="8226368121348880044">"%s odporúča zrýchlenie dátového pripojenia"</string>
+    <string name="network_boost_notification_detail" msgid="3812434025544196192">"Kúpte si zrýchlenie siete zvyšujúce výkon"</string>
+    <string name="network_boost_notification_button_not_now" msgid="4129218252146702688">"Teraz nie"</string>
+    <string name="network_boost_notification_button_manage" msgid="1511552684142641182">"Spravovať"</string>
+    <string name="slice_purchase_app_label" msgid="915654761797446390">"Kúpte si zrýchlenie siete."</string>
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sl/strings.xml b/packages/CarrierDefaultApp/res/values-sl/strings.xml
index bdbc155..1a0f74b9 100644
--- a/packages/CarrierDefaultApp/res/values-sl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sl/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Omrežje, ki se mu poskušate pridružiti, ima varnostne težave."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Stran za prijavo na primer morda ne pripada prikazani organizaciji."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Vseeno nadaljuj v brskalniku"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sq/strings.xml b/packages/CarrierDefaultApp/res/values-sq/strings.xml
index d4899e0..f6e1935 100644
--- a/packages/CarrierDefaultApp/res/values-sq/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sq/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Rrjeti në të cilin po përpiqesh të bashkohesh ka probleme sigurie."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"për shembull, faqja e identifikimit mund të mos i përkasë organizatës së shfaqur."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Vazhdo gjithsesi nëpërmjet shfletuesit"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sr/strings.xml b/packages/CarrierDefaultApp/res/values-sr/strings.xml
index 34c3bdc..e615ead 100644
--- a/packages/CarrierDefaultApp/res/values-sr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sr/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Мрежа којој покушавате да се придружите има безбедносних проблема."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"На пример, страница за пријављивање можда не припада приказаној организацији."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Ипак настави преко прегледача"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sv/strings.xml b/packages/CarrierDefaultApp/res/values-sv/strings.xml
index 4e76c8d..778663b 100644
--- a/packages/CarrierDefaultApp/res/values-sv/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sv/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Nätverket du försöker ansluta till har säkerhetsproblem."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Det kan t.ex. hända att inloggningssidan inte tillhör den organisation som visas."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Fortsätt ändå via webbläsaren"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-sw/strings.xml b/packages/CarrierDefaultApp/res/values-sw/strings.xml
index a52a733..4f0745c 100644
--- a/packages/CarrierDefaultApp/res/values-sw/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-sw/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mtandao unaojaribu kujiunga nao una matatizo ya usalama."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Kwa mfano, ukurasa wa kuingia katika akaunti unaweza usiwe unamilikiwa na shirika lililoonyeshwa."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Endelea hata hivyo kupitia kivinjari"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ta/strings.xml b/packages/CarrierDefaultApp/res/values-ta/strings.xml
index 1a786fa..a1d2928 100644
--- a/packages/CarrierDefaultApp/res/values-ta/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ta/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"நீங்கள் சேர முயலும் நெட்வொர்க்கில் பாதுகாப்புச் சிக்கல்கள் உள்ளன."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"எடுத்துக்காட்டாக, உள்நுழைவுப் பக்கமானது காட்டப்படும் அமைப்பிற்குச் சொந்தமானதாக இல்லாமல் இருக்கலாம்."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"பரவாயில்லை, உலாவி வழியாகத் தொடர்க"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-te/strings.xml b/packages/CarrierDefaultApp/res/values-te/strings.xml
index 8877c0c..7139903 100644
--- a/packages/CarrierDefaultApp/res/values-te/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-te/strings.xml
@@ -3,15 +3,27 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="5247871339820894594">"CarrierDefaultApp"</string>
     <string name="android_system_label" msgid="2797790869522345065">"మొబైల్ క్యారియర్"</string>
-    <string name="portal_notification_id" msgid="5155057562457079297">"మొబైల్ డేటాని పూర్తిగా ఉపయోగించారు"</string>
+    <string name="portal_notification_id" msgid="5155057562457079297">"మొబైల్ డేటాను పూర్తిగా ఉపయోగించారు"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"మీ మొబైల్ డేటా నిష్క్రియం చేయబడింది"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"%s వెబ్‌సైట్‌ని సందర్శించడం కోసం నొక్కండి"</string>
     <string name="no_data_notification_detail" msgid="3112125343857014825">"దయచేసి మీ సేవా ప్రదాత %sని సంప్రదించండి"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"మొబైల్ డేటా కనెక్షన్ లేదు"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"%s ద్వారా డేటాను లేదా రోమింగ్ ప్లాన్‌ను జోడించండి"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"మొబైల్ డేటా స్థితి"</string>
-    <string name="action_bar_label" msgid="4290345990334377177">"మొబైల్ నెట్‌వర్క్‌కి సైన్ ఇన్ చేయి"</string>
+    <string name="action_bar_label" msgid="4290345990334377177">"మొబైల్ నెట్‌వర్క్‌కి సైన్ ఇన్ చేయండి"</string>
     <string name="ssl_error_warning" msgid="3127935140338254180">"మీరు చేరడానికి ప్రయత్నిస్తున్న నెట్‌వర్క్ భద్రతా సమస్యలను కలిగి ఉంది."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ఉదాహరణకు, లాగిన్ పేజీ చూపిన సంస్థకు చెందినది కాకపోవచ్చు."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ఏదేమైనా బ్రౌజర్ ద్వారా కొనసాగించు"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-th/strings.xml b/packages/CarrierDefaultApp/res/values-th/strings.xml
index 8d30cfd..5c63bb1 100644
--- a/packages/CarrierDefaultApp/res/values-th/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-th/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"เครือข่ายที่คุณพยายามเข้าร่วมมีปัญหาด้านความปลอดภัย"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"ตัวอย่างเช่น หน้าเข้าสู่ระบบอาจไม่ใช่ขององค์กรที่แสดงไว้"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"ดำเนินการต่อผ่านเบราว์เซอร์"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-tl/strings.xml b/packages/CarrierDefaultApp/res/values-tl/strings.xml
index 083ec9a..9e320c8 100644
--- a/packages/CarrierDefaultApp/res/values-tl/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tl/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"May mga isyu sa seguridad ang network na sinusubukan mong salihan."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Halimbawa, maaaring hindi pag-aari ng ipinapakitang organisasyon ang page ng login."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Magpatuloy pa rin sa pamamagitan ng browser"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-tr/strings.xml b/packages/CarrierDefaultApp/res/values-tr/strings.xml
index aa17431..63616cc 100644
--- a/packages/CarrierDefaultApp/res/values-tr/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-tr/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Katılmaya çalıştığınız ağda güvenlik sorunları var."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Örneğin, giriş sayfası, gösterilen kuruluşa ait olmayabilir."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Yine de tarayıcıyla devam et"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-uk/strings.xml b/packages/CarrierDefaultApp/res/values-uk/strings.xml
index 8381e35..bd44327 100644
--- a/packages/CarrierDefaultApp/res/values-uk/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uk/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"У мережі, до якої ви намагаєтеся під’єднатись, є проблеми з безпекою."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Наприклад, сторінка входу може не належати вказаній організації."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Усе одно продовжити у веб-переглядачі"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-ur/strings.xml b/packages/CarrierDefaultApp/res/values-ur/strings.xml
index fc286b8..3294cf5 100644
--- a/packages/CarrierDefaultApp/res/values-ur/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-ur/strings.xml
@@ -6,7 +6,7 @@
     <string name="portal_notification_id" msgid="5155057562457079297">"موبائل ڈیٹا ختم ہو چکا ہے"</string>
     <string name="no_data_notification_id" msgid="668400731803969521">"آپ کا موبائل ڈیٹا غیر فعال کر دیا گیا ہے"</string>
     <string name="portal_notification_detail" msgid="2295729385924660881">"‏‎%s ویب سائٹ ملاحظہ کرنے کیلئے تھپتھپائیں"</string>
-    <string name="no_data_notification_detail" msgid="3112125343857014825">"‏براہ کرم اپنے خدمت کے فراہم کنندہ %s سے رابطہ کریں"</string>
+    <string name="no_data_notification_detail" msgid="3112125343857014825">"‏براہ کرم اپنے سروس فراہم کنندہ %s سے رابطہ کریں"</string>
     <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"کوئی موبائل ڈیٹا کنکشن نہیں ہے"</string>
     <string name="no_mobile_data_connection" msgid="544980465184147010">"‏%s کے ذریعے ڈیٹا یا رومنگ پلان شامل کریں"</string>
     <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"موبائل ڈیٹا کی صورت حال"</string>
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"آپ جس نیٹ ورک میں شامل ہونے کی کوشش کر رہے ہیں، اس میں سیکیورٹی کے مسائل ہیں۔"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"مثال کے طور پر ہو سکتا ہے کہ لاگ ان صفحہ دکھائی گئی تنظیم سے تعلق نہ رکھتا ہو۔"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"براؤزر کے ذریعے بہرحال جاری رکھیں"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-uz/strings.xml b/packages/CarrierDefaultApp/res/values-uz/strings.xml
index f2801c8..4eca545 100644
--- a/packages/CarrierDefaultApp/res/values-uz/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-uz/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Siz ulanmoqchi bo‘lgan tarmoqda xavfsizlik bilan bog‘liq muammolar mavjud."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Masalan, tizimga kirish sahifasi ko‘rsatilgan tashkilotga tegishli bo‘lmasligi mumkin."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Brauzerda davom ettirish"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-vi/strings.xml b/packages/CarrierDefaultApp/res/values-vi/strings.xml
index 1047cd4..d8f15e8 100644
--- a/packages/CarrierDefaultApp/res/values-vi/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-vi/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Mạng mà bạn đang cố gắng tham gia có vấn đề về bảo mật."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Ví dụ: trang đăng nhập có thể không thuộc về tổ chức được hiển thị."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Vẫn tiếp tục qua trình duyệt"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
index f84cedb..4ce19f5 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rCN/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"您尝试加入的网络存在安全问题。"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"例如,登录页面可能并不属于页面上显示的单位。"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"仍然通过浏览器继续操作"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
index ad76306..f019beb 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rHK/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"您正在嘗試加入的網絡有安全性問題。"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入頁面可能並不屬於所顯示的機構。"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
index ccf95c1..32724b5 100644
--- a/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zh-rTW/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"你嘗試加入的網路有安全性問題。"</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"例如,登入網頁中顯示的機構可能並非該網頁實際隸屬的機構。"</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"仍要透過瀏覽器繼續操作"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CarrierDefaultApp/res/values-zu/strings.xml b/packages/CarrierDefaultApp/res/values-zu/strings.xml
index 4ef80c1..669822c 100644
--- a/packages/CarrierDefaultApp/res/values-zu/strings.xml
+++ b/packages/CarrierDefaultApp/res/values-zu/strings.xml
@@ -14,4 +14,16 @@
     <string name="ssl_error_warning" msgid="3127935140338254180">"Inethiwekhi ozama ukuyijoyina inezinkinga zokuvikela."</string>
     <string name="ssl_error_example" msgid="6188711843183058764">"Isibonelo, ikhasi lokungena ngemvume kungenzeka lingelenhlangano ebonisiwe."</string>
     <string name="ssl_error_continue" msgid="1138548463994095584">"Qhubeka noma kunjalo ngesiphequluli"</string>
+    <!-- no translation found for network_boost_notification_channel (5430986172506159199) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_title (8226368121348880044) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_detail (3812434025544196192) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_not_now (4129218252146702688) -->
+    <skip />
+    <!-- no translation found for network_boost_notification_button_manage (1511552684142641182) -->
+    <skip />
+    <!-- no translation found for slice_purchase_app_label (915654761797446390) -->
+    <skip />
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index f51266c..3d8369a 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot jou &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horlosie"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Kies \'n <xliff:g id="PROFILE_NAME">%1$s</xliff:g> om deur &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; bestuur te word"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Hierdie program is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê, en sal toegang hê tot jou Foon-, SMS-, Kontakte-, Kalender- en Toestelle in die Omtrek-toestemming."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Programme"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stroom jou foon se programme"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Hierdie app is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met jou kennisgewings te hê, en sal toegang hê tot jou Foon-, SMS-, Kontakte-, Kalender-, Oproeprekords- en Toestelle in die Omtrek-toestemming."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Hierdie app is nodig om jou <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te bestuur. <xliff:g id="APP_NAME">%2$s</xliff:g> sal toegelaat word om interaksie met die volgende toestemmings te hê:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Oorkruistoestel-dienste"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om programme tussen jou toestelle te stroom"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Gee &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang tot hierdie inligting op jou foon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle kennisgewings lees, insluitend inligting soos kontakte, boodskappe en foto\'s"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Dienste"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> versoek tans namens jou <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot jou foon se foto\'s, media en kennisgewings"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"toestel"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dit kan mikrofoon-, kamera- en liggingtoegang insluit, asook ander sensitiewe toestemmings op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Jy kan hierdie toestemmings enige tyd verander in jou Instellings op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Program-ikoon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Meer Inligting-knoppie"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Foon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakte"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Toestelle in die omtrek"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Kennisgewings"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Het toegang tot jou foonnommer en netwerkinligting. Word vereis vir die maak van oproepe en VoIP, stemboodskapdiens, oproepherleiding en die wysiging van oproeprekords"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kan jou kontaklys lees, skep, of wysig, en het toegang tot die lys van al die rekeninge wat op jou toestel gebruik word"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle kennisgewings lees, insluitend inligting soos kontakte, boodskappe en foto\'s"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stroom jou foon se apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index 15b39d2..99d2041 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; የእርስዎን &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; መሣሪያ እንዲደርስ ይፍቀዱለት"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ሰዓት"</string>
     <string name="chooser_title" msgid="2262294130493605839">"በ&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; የሚተዳደር <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ይምረጡ"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር ይህ መተግበሪያ ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ እውቂያዎች፣ የቀን መቁጠሪያ፣ የጥሪ ምዝገባ ማስታወሻዎች እና በአቅራቢያ ያሉ የመሣሪያዎች ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"መተግበሪያዎች"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር መተግበሪያው ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከማሳወቂያዎችዎ ጋር መስተጋብር እንዲፈጥር እና የእርስዎን ስልክ፣ ኤስኤምኤስ፣ ዕውቂያዎች፣ የቀን መቁጠሪያ፣ የጥሪ ምዝገባ ማስታወሻዎች እና በአቅራቢያ ያሉ የመሣሪያዎች ፈቃዶች እንዲደርስ ይፈቀድለታል።"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"የእርስዎን <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ለማስተዳደር መተግበሪያው ያስፈልጋል። <xliff:g id="APP_NAME">%2$s</xliff:g> ከእነዚህ ፈቃዶች ጋር መስተጋብር እንዲፈጥር ይፈቀድለታል፦"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ እንዲደርስበት ይፍቀዱለት"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"መሣሪያ ተሻጋሪ አገልግሎቶች"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> በእርስዎ መሣሪያዎች መካከል መተግበሪያዎችን በዥረት ለመልቀቅ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ይህን መረጃ ከስልክዎ ላይ እንዲደርስ ይፍቀዱለት"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"እንደ እውቂያዎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ ይችላል"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"የGoogle Play አገልግሎቶች"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> የስልክዎን ፎቶዎች፣ ሚዲያ እና ማሳወቂያዎች ለመድረስ የእርስዎን <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ወክሎ ፈቃድ እየጠየቀ ነው"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"መሣሪያ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ይህ የማይክሮፎን፣ የካሜራ እና የአካባቢ መዳረሻ እና ሌሎች በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; ላይ ያሉ አደገኛ ፈቃዶችን ሊያካትት ይችላል።እነዚህን ፈቃዶች በማንኛውም ጊዜ በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;ላይ ቅንብሮችዎ ውስጥ መቀየር ይችላሉ።"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"የመተግበሪያ አዶ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"የተጨማሪ መረጃ አዝራር"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ስልክ"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"ኤስኤምኤስ"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"ዕውቂያዎች"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ቀን መቁጠሪያ"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"በአቅራቢያ ያሉ መሣሪያዎች"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ፎቶዎች እና ሚዲያ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ማሳወቂያዎች"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"መተግበሪያዎች"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"የእርስዎን ስልክ ቁጥር እና የአውታረ መረብ መረጃ መድረስ ይችላል። ጥሪዎችን ለማድረግ እና VoIP፣ የድምፅ መልዕክት፣ የጥሪ ማዘዋወር እና የጥሪ ምዝገባ ማስታወሻዎችን ለማርትዕ ያስፈልጋል"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"የእኛን የዕውቂያ ዝርዝር ማንበብ፣ መፍጠር ወይም ማርትዕ እንዲሁም በመሣሪያዎ ላይ ጥቅም ላይ የዋሉትን ሁሉንም መለያዎች ዝርዝር መድረስ ይችላል"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"እንደ እውቂያዎች፣ መልዕክቶች እና ፎቶዎች ያሉ መረጃዎችን ጨምሮ ሁሉንም ማሳወቂያዎች ማንበብ ይችላል"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"የስልክዎን መተግበሪያዎች በዥረት ይልቀቁ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index 13dcb69..051a629 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"الساعة"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏اختَر <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ليديرها تطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"هذا التطبيق مطلوب لإدارة <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. سيتم السماح لتطبيق <xliff:g id="APP_NAME">%2$s</xliff:g> بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم وسجلّات المكالمات والأجهزة المجاورة."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"التطبيقات"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"بث تطبيقات هاتفك"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"التطبيق مطلوب لإدارة \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". سيتم السماح لتطبيق \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" بالتفاعل مع الإشعارات والوصول إلى أذونات الهاتف والرسائل القصيرة وجهات الاتصال والتقويم وسجلّات المكالمات والأجهزة المجاورة."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"التطبيق مطلوب لإدارة \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". سيتم السماح للتطبيق \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" بالتفاعل مع هذه الأذونات."</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"الخدمات التي تعمل بين الأجهزة"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"يطلب تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> لمشاركة التطبيقات بين أجهزتك."</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏السماح لتطبيق &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; بالوصول إلى هذه المعلومات من هاتفك"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"يطلب تطبيق <xliff:g id="APP_NAME">%1$s</xliff:g> الحصول على إذن نيابةً عن <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> للوصول إلى الصور والوسائط والإشعارات في هاتفك."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"جهاز"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;قد تتضمَّن هذه الأذونات الوصول إلى الميكروفون والكاميرا والموقع الجغرافي وغيرها من أذونات الوصول إلى المعلومات الحسّاسة على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;يمكنك تغيير هذه الأذونات في أي وقت في إعداداتك على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"رمز التطبيق"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"زر مزيد من المعلومات"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"الهاتف"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"الرسائل القصيرة"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"جهات الاتصال"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"التقويم"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"الأجهزة المجاورة"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"الصور والوسائط"</string>
+    <string name="permission_notification" msgid="693762568127741203">"الإشعارات"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"التطبيقات"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"يسمح هذا الإذن بالوصول إلى رقم هاتفك ومعلومات الشبكة. ويجب منح هذا الإذن لإجراء مكالمات وتلقّي بريد صوتي عبر بروتوكول الصوت على الإنترنت وإعادة توجيه المكالمات وتعديل سجلات المكالمات."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"يسمح هذا الإذن بقراءة قائمة جهات الاتصال أو إنشائها أو تعديلها وكذلك قائمة كل الحسابات المُستخدَمة على جهازك."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"يمكن لهذا الملف الشخصي قراءة جميع الإشعارات، بما في ذلك المعلومات، مثل جهات الاتصال والرسائل والصور."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"بث تطبيقات هاتفك"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 9df589a..94c9325 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; এক্সেছ কৰিবলৈ দিয়ক"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ী"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;এ পৰিচালনা কৰিব লগা এটা <xliff:g id="PROFILE_NAME">%1$s</xliff:g> বাছনি কৰক"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এই এপ্‌টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক ,কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"এপ্‌"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"আপোনাৰ ফ’নৰ এপ্‌ ষ্ট্ৰীম কৰক"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এপ্‌টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক আপোনাৰ জাননী ব্যৱহাৰ কৰিবলৈ আৰু আপোনাৰ ফ’ন, এছএমএছ, সম্পৰ্ক ,কেলেণ্ডাৰ, কল লগ আৰু নিকটৱৰ্তী ডিভাইচৰ অনুমতি এক্সেছ কৰিবলৈ দিয়া হ’ব।"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"আপোনাৰ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> পৰিচালনা কৰিবলৈ এপ্‌টোৰ আৱশ্যক। <xliff:g id="APP_NAME">%2$s</xliff:g>ক এই অনুমতিসমূহৰ সৈতে ভাব-বিনিময় কৰিবলৈ দিয়া হ’ব:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্ৰছ-ডিভাইচ সেৱাসমূহ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ডিভাইচসমূহৰ মাজত এপ্‌ ষ্ট্ৰীম কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ক আপোনাৰ ফ’নৰ পৰা এই তথ্যখিনি এক্সেছ কৰাৰ অনুমতি দিয়ক"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"জাননী"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"সম্পৰ্কসূচী, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়িব পাৰে"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play সেৱা"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ আপোনাৰ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>ৰ হৈ আপোনাৰ ফ’নৰ ফট’, মিডিয়া আৰু জাননী এক্সেছ কৰাৰ বাবে অনুৰোধ জনাইছে"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইচ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ইয়াত &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ত মাইক্ৰ’ফ’ন, কেমেৰা আৰু অৱস্থানৰ এক্সেছ আৰু অন্য সংবেদশীল অনুমতিসমূহ প্ৰদান কৰাটো অন্তৰ্ভুক্ত হ’ব পাৰে।&lt;/p&gt; &lt;p&gt;আপুনি যিকোনো সময়তে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ত থকা আপোনাৰ ছেটিঙত এই অনুমতিসমূহ সলনি কৰিব পাৰে।&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"এপৰ চিহ্ন"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"অধিক তথ্যৰ বুটাম"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ফ’ন"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"এছএমএছ"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"সম্পৰ্ক"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"কেলেণ্ডাৰ"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"নিকটৱৰ্তী ডিভাইচ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ফট’ আৰু মিডিয়া"</string>
+    <string name="permission_notification" msgid="693762568127741203">"জাননী"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"এপ্"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"কল আৰু VoIP, ভইচমেইল, কল ৰিডাইৰেক্ট আৰু কলৰ লগ সম্পাদনা কৰিবলৈ আৱশ্যক হোৱা আপোনাৰ ফ’ন নম্বৰ আৰু নেটৱৰ্কৰ তথ্য এক্সেছ কৰিব পাৰে"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"আমাৰ সম্পৰ্কসূচী পঢ়িব, সৃষ্টি কৰিব অথবা সম্পাদনা কৰিব পাৰে আৰু লগতে আপোনাৰ ডিভাইচত ব্যৱহাৰ কৰা আটাইবোৰ একাউণ্টৰ সূচীখন এক্সেছ কৰিব পাৰে"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"সম্পৰ্কসূচী, বাৰ্তা আৰু ফট’ৰ দৰে তথ্যকে ধৰি আটাইবোৰ জাননী পঢ়িব পাৰে"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"আপোনাৰ ফ’নৰ এপ্ ষ্ট্ৰীম কৰক"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 4ef3111..625275dc 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinin &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınıza girişinə icazə verin"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"izləyin"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tərəfindən idarə ediləcək <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Bu tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihaz icazələrinə giriş əldə edəcək."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Tətbiqlər"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun tətbiqlərini yayımlayın"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bildirişlərinizə, Telefon, SMS, Kontaktlar, Təqvim, Zəng qeydləri və Yaxınlıqdakı cihaz icazələrinə giriş əldə edəcək."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Tətbiq <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızı idarə etmək üçün lazımdır. <xliff:g id="APP_NAME">%2$s</xliff:g> bu icazələrlə qarşılıqlı əlaqəyə icazə veriləcək:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlararası xidmətlər"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından cihazlarınız arasında tətbiqləri yayımlamaq üçün icazə istəyir"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tətbiqinə telefonunuzdan bu məlumata giriş icazəsi verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Bütün bildirişləri, o cümlədən kontaktlar, mesajlar və fotolar kimi məlumatları oxuya bilər"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xidmətləri"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> adından telefonunuzun fotoları, mediası və bildirişlərinə giriş üçün icazə istəyir"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Buraya &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; cihazındakı Mikrofon, Kamera və Məkana girişi və digər həssas icazələr daxil ola bilər.&lt;/p&gt; &lt;p&gt;Bu icazələri istənilən vaxt &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; cihazında ayarlarınızda dəyişə bilərsiniz.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Tətbiq İkonası"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Ətraflı Məlumat Düyməsi"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakt"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Təqvim"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Yaxınlıqdakı cihazlar"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto və media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirişlər"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Tətbiqlər"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Telefon nömrənizə və şəbəkə məlumatınıza giriş edə bilər. Zəng etmək və VoIP, səsli poçt, zəng yönləndirməsi və zəng qeydlərini redaktə etmək üçün tələb olunur"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kontakt siyahımızı oxuya, yarada və ya redaktə edə, həmçinin cihazınızda istifadə edilən bütün hesabların siyahısına giriş edə bilər"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Bütün bildirişləri, o cümlədən kontaktlar, mesajlar və fotolar kimi məlumatları oxuya bilər"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefonunuzun tətbiqlərini yayımlayın"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index baf55d2..4b12d60 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ova aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, kalendar, evidencije poziva i uređaje u blizini."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Strimujte aplikacije na telefonu"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa obaveštenjima i pristup dozvolama za telefon, SMS, kontakte, kalendar, evidencije poziva i uređaje u blizini."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> će dobiti dozvolu za interakciju sa ovim dozvolama:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na više uređaja"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za strimovanje aplikacija između uređaja"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Dozvolite da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama sa telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Može da čita sva obaveštenja, uključujući informacije poput kontakata, poruka i slika"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahteva dozvolu u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup slikama, medijskom sadržaju i obaveštenjima sa telefona"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To može da obuhvata pristup mikrofonu, kameri i lokaciji, kao i drugim osetljivim dozvolama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;U svakom trenutku možete da promenite te dozvole u Podešavanjima na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Dugme za više informacija"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakti"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Slike i mediji"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Obaveštenja"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Može da pristupa vašem broju telefona i informacijama o mreži. Neophodno za upućivanje poziva i VoIP, govornu poštu, preusmeravanje poziva i izmene evidencije poziva"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Može da čita, kreira ili menja listu kontakata, kao i da pristupa listi svih naloga koji se koriste na vašem uređaju"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Može da čita sva obaveštenja, uključujući informacije poput kontakata, poruka i slika"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strimujte aplikacije na telefonu"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 276127f..a11f9c1 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ да вашай прылады &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"гадзіннік"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Выберыце прыладу (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), якой будзе кіраваць праграма &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа ўзаемадзейнічаць з вашымі апавяшчэннямі і атрымае доступ да тэлефона, SMS, кантактаў, календара, журналаў выклікаў і прылад паблізу."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Праграмы"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Трансліруйце змесціва праграм з вашага тэлефона"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа ўзаемадзейнічаць з вашымі апавяшчэннямі і атрымае доступ да тэлефона, SMS, кантактаў, календара, журналаў выклікаў і прылад паблізу."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Гэта праграма неабходная для кіравання прыладай \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> зможа выкарыстоўваць наступныя дазволы:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сэрвісы для некалькіх прылад"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на трансляцыю праграм паміж вашымі прыладамі"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Дазвольце праграме &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; мець доступ да гэтай інфармацыі з вашага тэлефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Можа счытваць усе апавяшчэнні, уключаючы паведамленні, фота і інфармацыю пра кантакты"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Сэрвісы Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Праграма \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запытвае дазвол ад імя вашай прылады \"<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>\" на доступ да фота, медыяфайлаў і апавяшчэнняў на вашым тэлефоне"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"прылада"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Дазволы могуць уключаць доступ да мікрафона, камеры і даных пра месцазнаходжанне, а таксама да іншай канфідэнцыяльнай інфармацыі на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Вы можаце ў любы час змяніць гэтыя дазволы ў Наладах на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Значок праграмы"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка \"Даведацца больш\""</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Тэлефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Кантакты"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Каляндар"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Прылады паблізу"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Фота і медыяфайлы"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Апавяшчэнні"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Праграмы"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Доступ да вашага нумара тэлефона і інфармацыі пра сетку. Гэты дазвол патрабуецца, каб рабіць звычайныя і VoIP-выклікі, адпраўляць галасавыя паведамленні, перанакіроўваць выклікі і рэдагаваць журналы выклікаў"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Магчымасць чытаць, ствараць і рэдагаваць спіс кантактаў, а таксама атрымліваць доступ да спіса ўсіх уліковых запісаў на вашай прыладзе"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Можа счытваць усе апавяшчэнні, уключаючы паведамленні, фота і інфармацыю пра кантакты"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Трансляцыя змесціва праграм з вашага тэлефона"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 6b17ffd..e75f392 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Разрешаване на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до устройството ви &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Изберете устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), което да се управлява от &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Това приложение е необходимо за управление на <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите, календара, списъците с обажданията и разрешенията за устройства в близост."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Поточно предаване на приложенията на телефона ви"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Това приложение е необходимо за управление на устройството ви (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи разрешение да взаимодейства с известията ви и да осъществява достъп до разрешенията за телефона, SMS съобщенията, контактите, календара, списъците с обажданията и разрешенията за устройства в близост."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Това приложение е необходимо за управление на устройството ви (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> ще получи разрешение да взаимодейства със следните разрешения:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуги за различни устройства"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> да предава поточно приложения между устройствата ви"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Разрешете на &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да осъществява достъп до тази информация от телефона ви"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Известия"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Може да чете всички известия, включително различна информация, като например контакти, съобщения и снимки"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Услуги за Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> иска разрешение от името на <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за достъп до снимките, мултимедията и известията на телефона ви"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Това може да включва достъп до микрофона, камерата и местоположението, както и други разрешения за достъп до поверителна информация на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Можете да промените тези разрешения по всяко време от настройките на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на приложението"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Бутон за още информация"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контакти"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календар"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Устройства в близост"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Снимки и мултимедия"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Известия"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Приложения"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Може да осъществява достъп до номера и мрежата на телефона ви. Изисква се за провеждането на обаждания и разговори през VoIP, гласовата поща, пренасочването на обаждания и редактирането на списъците с обажданията"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Може да чете, създава и редактира записи в списъка с контактите ви, както и да осъществява достъп до списъка с всички профили, използвани на устройството ви"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Може да чете всички известия, включително различна информация, като например контакти, съобщения и снимки"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Поточно предаване на приложенията на телефона ви"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 1eaf142..8930a81 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"আপনার &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; অ্যাক্সেস করার জন্য &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে অনুমতি দিন"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ঘড়ি"</string>
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> বেছে নিন যেটি &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ম্যানেজ করবে"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"এই অ্যাপকে আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করতে দিতে হবে। <xliff:g id="APP_NAME">%2$s</xliff:g>-কে আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট এবং ফোন, এসএমএস, পরিচিতি, ক্যালেন্ডার, কল লগ ও আশেপাশের ডিভাইস অ্যাক্সেস করার অনুমতি দেওয়া হবে।"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"অ্যাপ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"আপনার ফোনের অ্যাপ স্ট্রিমিংয়ের মাধ্যমে কাস্ট করুন"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করার জন্য অ্যাপটি প্রয়োজন। <xliff:g id="APP_NAME">%2$s</xliff:g>-কে আপনার বিজ্ঞপ্তির সাথে ইন্টার‌্যাক্ট করার এবং ফোন, এসএমএস, পরিচিতি, ক্যালেন্ডার, কল লগ ও আশেপাশের ডিভাইস অ্যাক্সেস করার অনুমতি দেওয়া হবে।"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"আপনার <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ম্যানেজ করার জন্য অ্যাপটি প্রয়োজন। <xliff:g id="APP_NAME">%2$s</xliff:g> অ্যাপকে এইসব অনুমতির সাথে ইন্টার‌্যাক্ট করার জন্য অনুমোদন দেওয়া হবে:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; অ্যাপকে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ক্রস-ডিভাইস পরিষেবা"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"আপনার ডিভাইসগুলির মধ্যে অ্যাপ স্ট্রিম করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"আপনার ফোন থেকে &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-কে এই তথ্য অ্যাক্সেস করার অনুমতি দিন"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"সব বিজ্ঞপ্তি পড়তে পারবে, যার মধ্যে পরিচিতি, মেসেজ ও ফটোর মতো তথ্য অন্তর্ভুক্ত"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play পরিষেবা"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"আপনার ফোনের ফটো, মিডিয়া এবং তথ্য অ্যাক্সেস করার জন্য <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-এর হয়ে অনুমতি চাইছে"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ডিভাইস"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;এটি &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&amp;gt-এ হয়ত মাইক্রোফোন, ক্যামেরা এবং লোকেশনের অ্যাক্সেস ও অন্যান্য সংবেদনশীল অনুমতি অন্তর্ভুক্ত করতে পারে;আপনি যেকোনও সময় &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;-এর \'সেটিংস\'-এ গিয়ে এইসব অনুমতি পরিবর্তন করতে পারবেন"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"অ্যাপের আইকন"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"আরও তথ্য সংক্রান্ত বোতাম"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ফোন"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"এসএমএস"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"পরিচিতি"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ক্যালেন্ডার"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"আশেপাশের ডিভাইস"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ফটো ও মিডিয়া"</string>
+    <string name="permission_notification" msgid="693762568127741203">"বিজ্ঞপ্তি"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"অ্যাপ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"আপনার ফোন নম্বর ও নেটওয়ার্ক সংক্রান্ত তথ্য অ্যাক্সেস করতে পারবে। কল করার জন্য এবং VoIP, ভয়েসমেল, কল রিডাইরেক্ট ও কল লগ এডিট করার জন্য যা প্রয়োজন"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"আমাদের পরিচিতি তালিকা দেখতে, তৈরি বা এডিট করতে পারবে, পাশাপাশি আপনার ডিভাইসে ব্যবহার করা হয় এমন সবকটি অ্যাকাউন্টের তালিকা অ্যাক্সেস করতে পারবে"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"সব বিজ্ঞপ্তি পড়তে পারবে, যার মধ্যে পরিচিতি, মেসেজ ও ফটোর মতো তথ্য অন্তর্ভুক্ত"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"আপনার ফোনের অ্যাপ স্ট্রিম করুন"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index 8c941ac..2a45533 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"sat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite uređaj <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ova aplikacija je potrebna za upravljanje profilom: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će se dozvoliti da ostvari interakciju s vašim obavještenjima i da pristupi odobrenjima za Telefon, SMS, Kontakte, Kalendar, Zapisnike poziva i Uređaje u blizini."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Prenosite aplikacije s telefona"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će se dozvoliti da ostvaruje interakciju s vašim obavještenjima i da pristupa odobrenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikacija je potrebna za upravljanje uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> će biti dozvoljena interakcija s ovim odobrenjima:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Dozvolite da aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pristupa ovim informacijama s telefona"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluga na više uređaja"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da prenosi aplikacije između vaših uređaja"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Dozvolite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa ovim informacijama s vašeg telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sva obavještenja, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play usluge"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> u ime uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> zahtijeva odobrenje da pristupi fotografijama, medijima i odobrenjima na vašem telefonu"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ovo može uključivati pristup mikrofonu, kameri i lokaciji i druga osjetljiva odobrenja na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Uvijek možete promijeniti ova odobrenja u Postavkama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Dugme Više informacija"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakti"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Obavještenja"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Može pristupiti vašem broju telefona i informacijama o mreži. Potrebno je za upućivanje poziva i VoIP, govornu poštu, preusmjeravanje poziva te uređivanje zapisnika poziva"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Može čitati, kreirati ili uređivati našu listu kontakata te pristupiti listi svih računa koji se koriste na vašem uređaju"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sva obavještenja, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Prenosite aplikacije s telefona"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 5cc72ae..8995cdd 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"rellotge"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Tria un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> perquè el gestioni &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Aquesta aplicació es necessita per gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al calendari, als registres de trucades i als dispositius propers."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplicacions"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Reprodueix en continu aplicacions del telèfon"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"L\'aplicació és necessària per gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb les teves notificacions i accedir al telèfon, als SMS, als contactes, al calendari, als registres de trucades i als dispositius propers."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"L\'aplicació és necessària per gestionar <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> tindrà permís per interaccionar amb aquests permisos:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serveis multidispositiu"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> per reproduir en continu aplicacions entre els dispositius"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permet que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; accedeixi a aquesta informació del telèfon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pot llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Serveis de Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demana permís en nom del teu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> per accedir a les fotos, el contingut multimèdia i les notificacions del telèfon"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositiu"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Això pot incloure accés al micròfon, a la càmera i a la ubicació, i altres permisos sensibles a &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Pots canviar aquests permisos en qualsevol moment a &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;, a Configuració.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icona de l\'aplicació"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botó Més informació"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telèfon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contactes"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendari"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositius propers"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos i contingut multimèdia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificacions"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicacions"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Pot accedir al teu número de telèfon i a la informació de la xarxa. Es requereix per fer trucades i VoIP, enviar missatges de veu, redirigir trucades i editar els registres de trucades."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Pot llegir, crear o editar la nostra llista de contactes i també accedir a la llista de tots els comptes que s\'utilitzen al teu dispositiu"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pot llegir totes les notificacions, inclosa informació com ara els contactes, els missatges i les fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Reprodueix en continu aplicacions del telèfon"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index 0d44528..fdf93d8 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Povolit aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k vašemu zařízení &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte zařízení <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, které chcete spravovat pomocí aplikace &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Tato aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům, kalendáři, seznamům hovorů a zařízením v okolí."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikace"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streamujte aplikace v telefonu"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s vašimi oznámeními a získá přístup k telefonu, SMS, kontaktům, kalendáři, seznamům hovorů a zařízením v okolí."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikace je nutná ke správě zařízení <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikace <xliff:g id="APP_NAME">%2$s</xliff:g> bude moci interagovat s těmito oprávněními:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pro více zařízení"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění ke streamování aplikací mezi zařízeními"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Povolte aplikaci &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; přístup k těmto informacím z vašeho telefonu"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Může číst veškerá oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> požaduje za vaše zařízení <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> oprávnění k přístupu k fotkám, médiím a oznámením v telefonu"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zařízení"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Může být zahrnut přístup k mikrofonu, fotoaparátu a poloze a další citlivá oprávnění na zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Tato oprávnění můžete v Nastavení na zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; kdykoliv změnit.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikace"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Tlačítko Další informace"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakty"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendář"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Zařízení v okolí"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotky a média"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Oznámení"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikace"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Má přístup k vašemu telefonnímu číslu a informacím o síti. Vyžadováno pro volání a VoIP, hlasové zprávy, přesměrování hovorů a úpravy seznamů hovorů."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Může načítat, vytvářet a upravovat váš seznam kontaktů a má přístup k seznamu všech účtů používaných v zařízení"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Může číst veškerá oznámení včetně informací, jako jsou kontakty, zprávy a fotky"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streamujte aplikace v telefonu"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index a043978..51fcc62 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til dit &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ur"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vælg den enhed (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), som skal administreres af &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Du skal bruge denne app for at administrere dit <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og får adgang til dine tilladelser Opkald, Sms, Kalender, Opkaldshistorik og Enheder i nærheden."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream din telefons apps"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tilladelse til at interagere med dine notifikationer og får adgang til dine tilladelser for Opkald, Sms, Kalender, Opkaldshistorik og Enheder i nærheden."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Du skal bruge denne app for at administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får mulighed for at interagere med følgende tilladelser:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Giv &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; adgang til disse oplysninger fra din telefon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester, som kan tilsluttes en anden enhed"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at streame apps mellem dine enheder"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Tillad, at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får adgang til disse oplysninger fra din telefon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kan læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> anmoder om tilladelse på vegne af din <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> til at få adgang til din telefons billeder, medier og notifikationer"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhed"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dette kan omfatte mikrofon-, kamera- og lokationsadgang samt andre tilladelser til at tilgå følsomme oplysninger på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan til enhver tid ændre disse tilladelser under Indstillinger på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Knappen Flere oplysninger"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Sms"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakter"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheder i nærheden"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Billeder og medier"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifikationer"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Har adgang til oplysninger om dit telefonnummer og netværk. Påkrævet for at foretage opkald og VoIP, talebeskeder, omdirigering og redigering af opkaldshistorikken"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kan læse, oprette eller redigere din liste over kontakter samt tilgå lister for alle de konti, der bruges på din enhed"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan læse alle notifikationer, herunder oplysninger som f.eks. kontakter, beskeder og billeder"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream din telefons apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 77fb0bc..8747256 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; erlauben, auf dein Gerät (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;) zuzugreifen"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"Smartwatch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Gerät „<xliff:g id="PROFILE_NAME">%1$s</xliff:g>“ auswählen, das von &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; verwaltet werden soll"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Diese App wird zur Verwaltung des Geräts „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“ benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen für „Telefon“, „SMS“, „Kontakte“, „Kalender“, „Anrufliste“ und „Geräte in der Nähe“ zugreifen."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Smartphone-Apps streamen"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Die App wird zur Verwaltung deines Geräts (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit deinen Benachrichtigungen interagieren und auf die Berechtigungen „Telefon“, „SMS“, „Kontakte“, „Kalender“, „Anrufliste“ und „Geräte in der Nähe“ zugreifen."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Die App wird zur Verwaltung deines Geräts (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) benötigt. <xliff:g id="APP_NAME">%2$s</xliff:g> darf mit diesen Berechtigungen interagieren:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Geräteübergreifende Dienste"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet für dein <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Streamen von Apps zwischen deinen Geräten"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; Zugriff auf diese Informationen von deinem Smartphone gewähren"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kann alle Benachrichtigungen lesen, einschließlich Informationen wie Kontakten, Nachrichten und Fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-Dienste"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> bittet im Namen deines <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> um die Berechtigung zum Zugriff auf die Fotos, Medien und Benachrichtigungen deines Smartphones"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"Gerät"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dazu können Berechtigungen für Mikrofon, Kamera und Standortzugriff sowie andere vertrauliche Berechtigungen auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; gehören.&lt;/p&gt;&lt;p&gt;Sie lassen sich jederzeit in den Einstellungen auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; ändern.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App-Symbol"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Weitere-Infos-Schaltfläche"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakte"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Geräte in der Nähe"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos und Medien"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Benachrichtigungen"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Darf auf deine Telefonnummer und Netzwerkinformationen zugreifen. Erforderlich für normale und VoIP-Anrufe, Mailbox, Anrufweiterleitung und das Bearbeiten von Anruflisten"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Darf deine Kontaktliste lesen, erstellen oder bearbeiten sowie auf die Kontaktliste aller auf diesem Gerät verwendeten Konten zugreifen"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kann alle Benachrichtigungen lesen, einschließlich Informationen wie Kontakten, Nachrichten und Fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Smartphone-Apps streamen"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 56d7dcd..ccd5611 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση στη συσκευή &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ρολόι"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Επιλέξτε ένα προφίλ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> για διαχείριση από την εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Αυτή η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις και να έχει πρόσβαση στις άδειες Τηλέφωνο, SMS, Επαφές, Ημερολόγιο, Αρχεία καταγραφής κλήσεων και Συσκευές σε κοντινή απόσταση."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Εφαρμογές"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις ειδοποιήσεις και να έχει πρόσβαση στις άδειες Τηλέφωνο, SMS, Επαφές, Ημερολόγιο, Αρχεία καταγραφής κλήσεων και Συσκευές σε κοντινή απόσταση."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Η εφαρμογή είναι απαραίτητη για τη διαχείριση της συσκευής <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Η εφαρμογή <xliff:g id="APP_NAME">%2$s</xliff:g> θα επιτρέπεται να αλληλεπιδρά με τις εξής άδειες:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Να επιτρέπεται στο &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; η πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας."</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Υπηρεσίες πολλών συσκευών"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για ροή εφαρμογών μεταξύ των συσκευών σας"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Επιτρέψτε στην εφαρμογή &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; να έχει πρόσβαση σε αυτές τις πληροφορίες από το τηλέφωνό σας"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Υπηρεσίες Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> ζητά εκ μέρους της συσκευής σας <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> άδεια για πρόσβαση στις φωτογραφίες, τα αρχεία μέσων και τις ειδοποιήσεις του τηλεφώνου σας"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"συσκευή"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Αυτές μπορεί να περιλαμβάνουν πρόσβαση σε μικρόφωνο, κάμερα και τοποθεσία και άλλες άδειες πρόσβασης σε ευαίσθητες πληροφορίες στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Μπορείτε να αλλάξετε αυτές τις άδειες ανά πάσα στιγμή στις Ρυθμίσεις σας στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Εικονίδιο εφαρμογής"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Κουμπί περισσότερων πληροφορ."</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Τηλέφωνο"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Επαφές"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Ημερολόγιο"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Συσκευές σε κοντινή απόσταση"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Φωτογραφίες και μέσα"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Ειδοποιήσεις"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Εφαρμογές"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Δυνατότητα πρόσβασης στον αριθμό τηλεφώνου σας και στις πληροφορίες δικτύου. Απαιτείται για την πραγματοποίηση κλήσεων και για υπηρεσίες VoIP, μηνύματα αυτόματου τηλεφωνητή, ανακατεύθυνση κλήσεων και επεξεργασία αρχείων καταγραφής κλήσεων"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Δυνατότητα ανάγνωσης, δημιουργίας ή επεξεργασίας της λίστας επαφών σας, καθώς και πρόσβασης στη λίστα επαφών όλων των λογαριασμών που χρησιμοποιούνται στη συσκευή σας"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Μπορεί να διαβάσει όλες τις ειδοποιήσεις, συμπεριλαμβανομένων πληροφοριών όπως επαφές, μηνύματα και φωτογραφίες"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Μεταδώστε σε ροή τις εφαρμογές του τηλεφώνου σας"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index c80620e..1d7623f 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with these permissions:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Phone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Nearby devices"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect and editing call logs"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Can read, create or edit our contact list, as well as access the list of all accounts used on your device"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 3982809..61ae537 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with these permissions:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages, and photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media, and notifications"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include Microphone, Camera, and Location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions any time in your Settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App Icon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"More Information Button"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Phone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Nearby devices"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect, and editing call logs"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Can read, create, or edit our contact list, as well as access the list of all accounts used on your device"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages, and photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index c80620e..1d7623f 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with these permissions:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Phone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Nearby devices"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect and editing call logs"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Can read, create or edit our contact list, as well as access the list of all accounts used on your device"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index c80620e..1d7623f 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access your &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"watch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choose a <xliff:g id="PROFILE_NAME">%1$s</xliff:g> to be managed by &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"This app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream your phone’s apps"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with your notifications and access your phone, SMS, contacts, calendar, call logs and Nearby devices permissions."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"The app is needed to manage your <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> will be allowed to interact with these permissions:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to stream apps between your devices"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Allow &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; to access this information from your phone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> is requesting permission on behalf of your <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> to access your phone’s photos, media and notifications"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;This may include microphone, camera and location access, and other sensitive permissions on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions at any time in your settings on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App icon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"More information button"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Phone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Nearby devices"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos and media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect and editing call logs"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Can read, create or edit our contact list, as well as access the list of all accounts used on your device"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Can read all notifications, including information like contacts, messages and photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream your phone’s apps"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
index 1b8833b..d40ac6a 100644
--- a/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rXC/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access your &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎watch‎‏‎‎‏‎"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‏‎‎‏‏‏‏‎Choose a ‎‏‎‎‏‏‎<xliff:g id="PROFILE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ to be managed by &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;‎‏‎‎‏‎"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‎‎‎‎‏‎‎‏‏‎‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‎‏‎‎‎‎‏‎‎‏‎‏‎‎‎This app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.‎‏‎‎‏‎"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‏‏‎‎‎‎‏‎‎‏‏‏‏‎‎Apps‎‏‎‎‏‎"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‎‎‎‎‏‎‏‎‎‏‏‏‎‏‎‎‏‎‎‏‏‏‎Stream your phone’s apps‎‏‎‎‏‎"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‎‏‎‏‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‏‏‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‎‎‎‏‏‎‎‏‏‎‎The app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with your notifications and access your Phone, SMS, Contacts, Calendar, Call logs and Nearby devices permissions.‎‏‎‎‏‎"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‏‎‏‎‏‎‏‎‎‎‏‎‏‎‎‎The app is needed to manage your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎. ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ will be allowed to interact with these permissions:‎‏‎‎‏‎"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‎‏‎‎‎‎‏‏‏‎‎‏‎‎‏‏‎‎‏‏‎‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‏‎‏‎‎‏‏‎‏‎‏‏‏‏‎‎‏‎‏‎Cross-device services‎‏‎‎‏‎"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‏‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‎‎‏‏‎‎‎‎‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to stream apps between your devices‎‏‎‎‏‎"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‎‏‎‎‏‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‎‏‎‎‏‎‏‎Allow &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt; to access this information from your phone‎‏‎‎‏‎"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎Can read all notifications, including information like contacts, messages, and photos‎‏‎‎‏‎"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎Photos and media‎‏‎‎‏‎"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‏‎‏‏‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‏‎‏‎‏‎‎‏‎‏‎Google Play services‎‏‎‎‏‎"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‎‎‏‎‎‎‎‏‏‏‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‏‏‎‎‎‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ is requesting permission on behalf of your ‎‏‎‎‏‏‎<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ to access your phone’s photos, media, and notifications‎‏‎‎‏‎"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‏‏‏‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‎‏‏‎‏‏‎‎‎device‎‏‎‎‏‎"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‎‎‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‏‏‏‏‎‎‎&lt;p&gt;This may include Microphone, Camera, and Location access, and other sensitive permissions on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;You can change these permissions any time in your Settings on &lt;strong&gt;‎‏‎‎‏‏‎<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>‎‏‎‎‏‏‏‎&lt;/strong&gt;.&lt;/p&gt;‎‏‎‎‏‎"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‏‏‏‏‎‏‎‏‎‏‏‎‏‎App Icon‎‏‎‎‏‎"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‎‏‎‏‏‏‎‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎‎‎‎‎More Information Button‎‏‎‎‏‎"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎Phone‎‏‎‎‏‎"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‎‎‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎‎‏‎‎SMS‎‏‎‎‏‎"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‎‎‎‎‏‎‎‎‎‏‎‎‎‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‎Contacts‎‏‎‎‏‎"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‏‎‏‏‏‎‏‎‏‎‏‏‏‎‏‏‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎Calendar‎‏‎‎‏‎"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‏‏‎‏‏‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‏‎‎‏‎‏‏‎‎‎‏‏‎‏‎‎‏‏‎‎‏‎Nearby devices‎‏‎‎‏‎"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‎‎‎‎‏‎‏‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‎‏‏‏‎‏‏‏‏‏‎‎‎‎‏‎‏‎‏‏‏‎Photos and media‎‏‎‎‏‎"</string>
+    <string name="permission_notification" msgid="693762568127741203">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‎‏‎‏‎‎‎‏‏‏‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‏‎‎‎‏‎‎‏‏‎Notifications‎‏‎‎‏‎"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‏‎‏‏‎‎Apps‎‏‎‎‏‎"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‏‎‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‎‎‎‎‎‏‎‎‎‎‎‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‏‏‎‏‎‏‎Can access your phone number and network info. Required for making calls and VoIP, voicemail, call redirect, and editing call logs‎‏‎‎‏‎"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‏‎‎‎‎‎‎‎‎‎‏‏‎‎‎‏‎‏‎‏‏‎‎‏‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‎‏‏‏‏‎‎‏‎‎‎‎Can read, create, or edit our contact list, as well as access the list of all accounts used on your device‎‏‎‎‏‎"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‎‏‎‎‏‏‎‏‏‏‎‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‏‎‏‏‎‎‎‏‏‏‏‎‎‎‏‏‎Can read all notifications, including information like contacts, messages, and photos‎‏‎‎‏‎"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‏‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‎‎‎‎Stream your phone’s apps‎‏‎‎‏‎"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index b7511ba..ef7e59d 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para que la app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; lo administre"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Calendario, Llamadas y Dispositivos cercanos."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Transmitir las apps de tu teléfono"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a los permisos de Teléfono, SMS, Contactos, Calendario, Llamadas y Dispositivos cercanos."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Esta app es necesaria para administrar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con estos permisos:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para transmitir apps entre dispositivos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permite que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluso con información como contactos, mensajes y fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicita tu permiso en nombre de <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, el contenido multimedia y las notificaciones de tu teléfono"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Esto puede incluir el acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles del dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puedes cambiar estos permisos en cualquier momento en la Configuración del dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ícono de la app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón Más información"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Teléfono"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contactos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendario"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos cercanos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos y contenido multimedia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Puede acceder a tu número de teléfono y a la información de la red (es obligatorio para realizar llamadas VoIP, enviar mensajes de voz, redireccionar llamadas y editar registros de llamadas)"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Puede leer, crear o editar la lista de contactos, además de acceder a la lista de contactos para todas las cuentas que se usan en tu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluso con información como contactos, mensajes y fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Transmitir las apps de tu teléfono"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index 11ed3c3..82ff28a 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a tu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloj"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Elige un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para gestionarlo con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Se necesita esta aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, calendario, registros de llamadas y dispositivos cercanos."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplicaciones"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Proyecta aplicaciones de tu teléfono"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Se necesita la aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> podrá interactuar con tus notificaciones y acceder a tus permisos de teléfono, SMS, contactos, calendario, registros de llamadas y dispositivos cercanos."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Se necesita la aplicación para gestionar tu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Se permitirá que <xliff:g id="APP_NAME">%2$s</xliff:g> interaccione con los siguientes permisos:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicios multidispositivo"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para emitir aplicaciones en otros dispositivos tuyos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información de tu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Servicios de Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> está pidiendo permiso en nombre de tu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acceder a las fotos, los archivos multimedia y las notificaciones de tu teléfono"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Esto puede incluir acceso al micrófono, la cámara y la ubicación, así como otros permisos sensibles de &lt;p&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puedes cambiar estos permisos cuando quieras en los ajustes de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icono de la aplicación"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón Más información"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Teléfono"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contactos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendario"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos cercanos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos y elementos multimedia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificaciones"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicaciones"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Puede acceder a tu número de teléfono e información de red. Es necesario para hacer llamadas y VoIP, enviar mensajes de voz, redirigir llamadas y editar registros de llamadas"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Puede leer, crear o editar tu lista de contactos, así como acceder a la lista de contactos de todas las cuentas que se usan en tu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Puede leer todas las notificaciones, incluida información como contactos, mensajes y fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Muestra en streaming las aplicaciones de tu teléfono"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 40a55b5..ab42dda 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; teie seadmele &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; juurde pääseda"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"käekell"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Valige seade <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, mida haldab rakendus &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Seda rakendust on vaja teie profiili <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada teie märguandeid ja pääseda juurde teie telefoni, SMS-ide, kontaktide, kalendri, kõnelogide ja läheduses olevate seadmete lubadele."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Rakendused"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Telefoni rakenduste voogesitamine"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Seda rakendust on vaja teie seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada teie märguandeid ning pääseda juurde teie telefoni, SMS-ide, kontaktide, kalendri, kõnelogide ja läheduses olevate seadmete lubadele."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Seda rakendust on vaja teie seadme <xliff:g id="DEVICE_NAME">%1$s</xliff:g> haldamiseks. Rakendusel <xliff:g id="APP_NAME">%2$s</xliff:g> lubatakse kasutada järgmisi lube."</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Seadmeülesed teenused"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba teie seadmete vahel rakendusi voogesitada"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Lubage rakendusel &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pääseda teie telefonis juurde sellele teabele"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kõikide märguannete, sealhulgas teabe, nagu kontaktid, sõnumid ja fotod, lugemine"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play teenused"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> taotleb teie seadme <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nimel luba pääseda juurde telefoni fotodele, meediale ja märguannetele"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"seade"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;See võib hõlmata mikrofoni, kaamerat ja juurdepääsu asukohale ning muid tundlikke lube seadmes &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Võite neid lube seadme &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; seadetes igal ajal muuta.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Rakenduse ikoon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Nupp Lisateave"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktid"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Läheduses olevad seadmed"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotod ja meedia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Märguanded"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Rakendused"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Pääseb juurde teie telefoninumbrile ja võrguteabele. Nõutav helistamiseks, VoIP-i ja kõneposti kasutamiseks, kõnede ümbersuunamiseks ning kõnelogide muutmiseks."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Saab lugeda, luua või muuta kontaktiloendit ja pääseda juurde kõigi teie seadmes kasutatavate kontode loendile"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kõikide märguannete, sealhulgas teabe, nagu kontaktid, sõnumid ja fotod, lugemine"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefoni rakenduste voogesitamine"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-eu/strings.xml b/packages/CompanionDeviceManager/res/values-eu/strings.xml
index 83d0e02..66d433d 100644
--- a/packages/CompanionDeviceManager/res/values-eu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-eu/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Eman &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; atzitzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"erlojua"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Aukeratu &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; aplikazioak kudeatu beharreko <xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko beharrezkoa da aplikazio hau. Jakinarazpenekin interakzioan aritzeko eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroa eta inguruko gailuak atzitzeko baimenak izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikazioak"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Igorri zuzenean telefonoko aplikazioak"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko behar da aplikazioa. Jakinarazpenekin interakzioan aritzeko, eta telefonoa, SMSak, kontaktuak, egutegia, deien erregistroak eta inguruko gailuak erabiltzeko baimenak izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> kudeatzeko behar da aplikazioa. Baimen hauek izango ditu <xliff:g id="APP_NAME">%2$s</xliff:g> aplikazioak:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Eman informazioa telefonotik hartzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Gailu baterako baino gehiagotarako zerbitzuak"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Gailu batetik bestera aplikazioak igortzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Eman telefonoko informazio hau atzitzeko baimena &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aplikazioari"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Telefonoko argazkiak, multimedia-edukia eta jakinarazpenak atzitzeko baimena eskatzen ari da <xliff:g id="APP_NAME">%1$s</xliff:g>, <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> gailuaren izenean"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"gailua"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Haien artean, baliteke &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; gailuaren mikrofonoa, kamera, kokapenerako sarbidea eta beste kontuzko baimen batzuk egotea.&lt;/p&gt; &lt;p&gt;Baimen horiek edonoiz alda ditzakezu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; gailuaren ezarpenetan.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Aplikazioaren ikonoa"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Informazio gehiagorako botoia"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefonoa"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMSak"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktuak"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Egutegia"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Inguruko gailuak"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Argazkiak eta multimedia-edukia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Jakinarazpenak"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikazioak"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Telefono-zenbakia eta sareari buruzko informazioa atzi ditzake. Dei arruntak eta VoIP bidezko deiak egiteko, erantzungailurako, deiak birbideratzeko aukerarako eta deien erregistroan editatzeko behar da."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kontaktuen zerrenda irakurri, sortu edo edita dezake, baita kontuan erabilitako kontu guztien zerrenda atzitu ere"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Jakinarazpen guztiak irakur ditzake; besteak beste, kontaktuak, mezuak, argazkiak eta antzeko informazioa"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Igorri zuzenean telefonoko aplikazioak"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index 263f3ea61..b00cb5b 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه دهید به &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; دسترسی داشته باشد"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ساعت"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏انتخاب <xliff:g id="PROFILE_NAME">%1$s</xliff:g> برای مدیریت کردن با &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>‏&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="APP_NAME">%2$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارش‌های تماس» و «دستگاه‌های اطراف» دسترسی خواهد داشت."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"برنامه‌ها"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"جاری‌سازی برنامه‌های تلفن"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="APP_NAME">%2$s</xliff:g> می‌تواند با اعلان‌های شما تعامل داشته باشد و به اجازه‌های «تلفن»، «پیامک»، «مخاطبین»، «تقویم»، «گزارش‌های تماس» و «دستگاه‌های اطراف» دسترسی خواهد داشت."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"این برنامه برای مدیریت <xliff:g id="DEVICE_NAME">%1$s</xliff:g> شما لازم است. <xliff:g id="APP_NAME">%2$s</xliff:g> مجاز است با این اجازه‌ها تعامل داشته باشد:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"‏اجازه دادن به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; برای دسترسی به اطلاعات تلفن"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"سرویس‌های بین‌دستگاهی"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه می‌خواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> برنامه‌ها را بین دستگاه‌های شما جاری‌سازی کند"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏به &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; اجازه دسترسی به این اطلاعات در دستگاهتان داده شود"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل مخاطبین، پیام‌ها، و عکس‌ها را بخواند"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"عکس‌ها و رسانه‌ها"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"‏خدمات Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> اجازه می‌خواهد ازطرف <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> به عکس‌ها، رسانه‌ها، و اعلان‌های تلفن شما دسترسی پیدا کند"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"دستگاه"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;این اجازه‌ها می‌تواند شامل دسترسی به «میکروفون»، «دوربین»، و «مکان»، و دیگر اجازه‌های حساس در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; شود.&lt;/p&gt; &lt;p&gt;هروقت بخواهید می‌توانید این اجازه‌ها را در «تنظیمات» در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; تغییر دهید.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"نماد برنامه"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"دکمه اطلاعات بیشتر"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"تلفن"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"پیامک"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"مخاطبین"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"تقویم"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"دستگاه‌های اطراف"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"عکس‌ها و رسانه‌ها"</string>
+    <string name="permission_notification" msgid="693762568127741203">"اعلان‌ها"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"برنامه‌ها"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"‏می‌تواند به شماره تلفن و اطلاعات شبکه‌تان دسترسی داشته باشد. برای برقراری تماس‌های تلفنی و VoIP، استفاده از پست صوتی، هدایت تماس، و ویرایش گزارش‌های تماس لازم است"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"می‌تواند فهرست مخاطبین ما را بخواند و ایجاد یا ویرایش کند و همچنین می‌تواند به فهرست همه حساب‌های مورداستفاده در دستگاهتان دسترسی داشته باشد"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"می‌تواند همه اعلان‌ها، ازجمله اطلاعاتی مثل مخاطبین، پیام‌ها، و عکس‌ها را بخواند"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"جاری‌سازی برنامه‌های تلفن"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index 67252c5..d4136c7 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn laitteeseesi: &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"kello"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Valitse <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, jota &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; hallinnoi"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Profiilin (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, kalenteriin, puhelulokeihin ja lähellä olevat laitteet ‑lupiin."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Sovellukset"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Striimaa puhelimen sovelluksia"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Laitteen (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa luvan hallinnoida ilmoituksiasi sekä pääsyn puhelimeen, tekstiviesteihin, yhteystietoihin, kalenteriin, puhelulokeihin ja lähellä olevat laitteet ‑lupiin."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Laitteen (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) ylläpitoon tarvitaan tätä sovellusta. <xliff:g id="APP_NAME">%2$s</xliff:g> saa käyttää näitä lupia:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Salli, että &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; saa pääsyn näihin puhelimesi tietoihin"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Laitteidenväliset palvelut"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) puolesta lupaa striimata sovelluksia laitteidesi välillä"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Salli pääsy tähän tietoon puhelimellasi: &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Voi lukea kaikkia ilmoituksia, esim. kontakteihin, viesteihin ja kuviin liittyviä tietoja"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Palvelut"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> pyytää laitteesi (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) puolesta lupaa päästä puhelimesi kuviin, mediaan ja ilmoituksiin"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"laite"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Tähän voi kuulua pääsy mikrofoniin, kameraan ja sijaintiin sekä muita arkaluontoisia lupia laitteella &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Voit muuttaa lupia asetuksista milloin tahansa laitteella &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Sovelluskuvake"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Lisätietopainike"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Puhelin"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Tekstiviesti"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Yhteystiedot"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalenteri"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Lähellä olevat laitteet"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Kuvat ja media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Ilmoitukset"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Sovellukset"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Voi nähdä puhelinnumerosi ja verkon tiedot. Tätä tarvitaan puheluiden soittamiseen, VoIP:n, puhelinvastaajan ja puheluiden uudelleenohjauksen käyttämiseen sekä puhelulokien muokkaamiseen."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Voi luoda yhteystietolistan tai lukea tai muokata sitä sekä avata listan kaikilla tileillä, joita käytetään laitteellasi."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Voi lukea kaikkia ilmoituksia, esim. kontakteihin, viesteihin ja kuviin liittyviä tietoja"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Striimaa puhelimen sovelluksia"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index b85099a..7c17039 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Choisissez un(e) <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Cette application est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations suivantes : téléphone, messages texte, contacts, agenda, journaux d\'appels et appareils à proximité."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Applications"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Diffusez les applications de votre téléphone"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"L\'application est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder aux autorisations suivantes : téléphone, messages texte, contacts, agenda, journaux d\'appels et appareils à proximité."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"L\'application est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec ces autorisations :"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services multiappareils"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour diffuser des applications entre vos appareils"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorisez &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations à partir de votre téléphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, aux fichiers multimédias et aux notifications de votre téléphone"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Cela peut comprendre l\'accès au microphone, à l\'appareil photo et à la position, ainsi que d\'autres autorisations sensibles sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Vous pouvez modifier ces autorisations en tout temps dans vos paramètres sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icône de l\'application"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Bouton En savoir plus"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Téléphone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Messages texte"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Agenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Appareils à proximité"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos et fichiers multimédias"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Applications"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Peut accéder à votre numéro de téléphone et à vos renseignements de réseau. Ceci est nécessaire pour passer des appels téléphoniques et des appels voix sur IP, laisser un message vocal, rediriger les appels et modifier les journaux d\'appels"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Peut lire, créer ou modifier notre liste de contacts et accéder à la liste de tous les comptes utilisés sur votre appareil"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris les renseignements tels que les contacts, les messages et les photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffusez les applications de votre téléphone"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index 8a13866..fde2322 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à votre &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"montre"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Sélectionnez le/la <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qui sera géré(e) par &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Cette appli est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts, à l\'agenda, aux journaux d\'appels et aux appareils à proximité."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Applis"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Diffuser en streaming les applis de votre téléphone"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Cette appli est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> aura l\'autorisation d\'interagir avec vos notifications et d\'accéder au téléphone, aux SMS, aux contacts, à l\'agenda, aux journaux d\'appels et aux appareils à proximité."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Cette appli est nécessaire pour gérer votre <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> pourra interagir avec ces autorisations :"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Services inter-appareils"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour caster des applis d\'un appareil à l\'autre"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autoriser &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; à accéder à ces informations depuis votre téléphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris des informations comme les contacts, messages et photos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Services Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> demande l\'autorisation au nom de votre <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> pour accéder aux photos, contenus multimédias et notifications de votre téléphone"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"appareil"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Il peut s\'agir de l\'accès au micro, à l\'appareil photo et à la position, et d\'autres autorisations sensibles sur l\'appareil &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Vous pouvez modifier ces autorisations à tout moment dans les paramètres de l\'appareil &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icône d\'application"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Bouton Plus d\'informations"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Téléphone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Agenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Appareils à proximité"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Photos et contenus multimédias"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifications"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Applis"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Peut accéder à votre numéro de téléphone et aux informations réseau. Nécessaire pour passer des appels et pour VoIP, la messagerie vocale, la redirection d\'appels et la modification des journaux d\'appels."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Peut lire, créer ou modifier votre liste de contacts, et accéder à la liste de tous les comptes utilisés sur votre appareil"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Peut lire toutes les notifications, y compris des informations comme les contacts, messages et photos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Diffuser en streaming les applis de votre téléphone"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 8134e64..214c3f5 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda ao teu dispositivo (&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;)"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"reloxo"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolle un perfil (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) para que o xestione a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Esta aplicación é necesaria para xestionar o teu dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do calendario, dos rexistros de chamadas e dos dispositivos próximos."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplicacións"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Emite as aplicacións do teu teléfono"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"A aplicación é necesaria para xestionar o teu dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar coas túas notificacións e acceder aos permisos do teu teléfono, das SMS, dos contactos, do calendario, dos rexistros de chamadas e dos dispositivos próximos."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"A aplicación é necesaria para xestionar o teu dispositivo (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>). <xliff:g id="APP_NAME">%2$s</xliff:g> poderá interactuar con estes permisos:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que a aplicación &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información desde o teu teléfono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizos multidispositivo"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para emitir contido de aplicacións entre os teus aparellos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permitir que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acceda a esta información do teu teléfono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Servizos de Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> está solicitando permiso en nome do teu dispositivo (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>) para acceder ás fotos, ao contido multimedia e ás notificacións do teléfono"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Con esta acción podes conceder acceso ao micrófono, á cámara e á localización, así como outros permisos de acceso á información confidencial de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Podes cambiar estes permisos en calquera momento na configuración de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icona de aplicación"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botón de máis información"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Teléfono"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contactos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendario"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos próximos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e contido multimedia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificacións"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicacións"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Pode acceder ao teu número de teléfono e á información de rede do dispositivo. Necesítase para facer chamadas, usar VoIP, acceder ao correo de voz, redirixir chamadas e modificar os rexistros de chamadas"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Pode ler, crear ou editar a túa lista de contactos, así como acceder á lista de todas as contas usadas no teu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificacións (que poden incluír información como contactos, mensaxes e fotos)"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Emite as aplicacións do teu teléfono"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index c6a8330..6f5ebea 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"તમારા &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ને ઍક્સેસ કરવાની &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"સ્માર્ટવૉચ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; દ્વારા મેનેજ કરવા માટે કોઈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> પસંદ કરો"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"તમારી <xliff:g id="DEVICE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે આ ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો, કૅલેન્ડર, કૉલ લૉગ અને નજીકનાં ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ઍપ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"તમારી <xliff:g id="DEVICE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને તમારા નોટિફિકેશન સાથે ક્રિયાપ્રતિક્રિયા કરવાની તેમજ તમારો ફોન, SMS, સંપર્કો, કૅલેન્ડર, કૉલ લૉગ અને નજીકના ડિવાઇસની પરવાનગીઓ ઍક્સેસ કરવાની મંજૂરી આપવામાં આવશે."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"તમારી <xliff:g id="DEVICE_NAME">%1$s</xliff:g> મેનેજ કરવા માટે ઍપ જરૂરી છે. <xliff:g id="APP_NAME">%2$s</xliff:g>ને આ પરવાનગીઓ સાથે ક્રિયાપ્રતિક્રિયા કરવાની મંજૂરી આપવામાં આવશે:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ક્રોસ-ડિવાઇસ સેવાઓ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ડિવાઇસ વચ્ચે ઍપ સ્ટ્રીમ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"તમારા ફોનમાંથી આ માહિતી ઍક્સેસ કરવા માટે, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ને મંજૂરી આપો"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચી શકે છે"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play સેવાઓ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> તમારા <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> વતી તમારા ફોનના ફોટા, મીડિયા અને નોટિફિકેશન ઍક્સેસ કરવાની પરવાનગીની વિનંતી કરી રહી છે"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ડિવાઇસ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;આમાં &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; પરના માઇક્રોફોન, કૅમેરા અને સ્થાનના ઍક્સેસ તથા અન્ય સંવેદનશીલ માહિતીની પરવાનગીઓ શામેલ હોઈ શકે છે.&lt;/p&gt; &lt;p&gt;તમે &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; પર તમારા સેટિંગમાં તમે કોઈપણ સમયે આ પરવાનગીઓને બદલી શકો છો.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ઍપનું આઇકન"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"વધુ માહિતી માટેનું બટન"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ફોન"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"સંપર્કો"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"કૅલેન્ડર"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"નજીકના ડિવાઇસ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ફોટા અને મીડિયા"</string>
+    <string name="permission_notification" msgid="693762568127741203">"નોટિફિકેશન"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ઍપ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"તમારો ફોન નંબર અને નેટવર્કની માહિતી ઍક્સેસ કરી શકે છે. કૉલ અને VoIP કૉલ, વૉઇસમેઇલ કરવા, કૉલ રીડાયરેક્ટ કરવા તથા કૉલ લૉગમાં ફેરફાર કરવા માટે જરૂરી છે"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"તમારી સંપર્ક સૂચિ વાંચી, બનાવી શકે છે અથવા તેમાં ફેરફાર કરી શકે છે તેમજ તમારા ડિવાઇસ પર ઉપયોગમાં લેવાતા બધા એકાઉન્ટની સંપર્ક સૂચિને ઍક્સેસ કરી શકે છે"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"સંપર્કો, મેસેજ અને ફોટા જેવી માહિતી સહિતના બધા નોટિફિકેશન વાંચી શકે છે"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"તમારા ફોનની ઍપ સ્ટ્રીમ કરો"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index c4ca37c..978e333 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -20,9 +20,10 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ऐक्सेस करने की अनुमति दें"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"स्मार्टवॉच"</string>
     <string name="chooser_title" msgid="2262294130493605839">"कोई <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चुनें, ताकि उसे &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; की मदद से मैनेज किया जा सके"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"यह ऐप्लिकेशन, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> को मैनेज करने के लिए ज़रूरी है. <xliff:g id="APP_NAME">%2$s</xliff:g> आपकी सूचनाओं पर कार्रवाई कर पाएगा. साथ ही, इसे आपके फ़ोन, एसएमएस, संपर्कों, कैलेंडर, कॉल लॉग, और आस-पास मौजूद डिवाइसों को ऐक्सेस करने की अनुमति मिल पाएगी."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ऐप्लिकेशन"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"अपने फ़ोन के ऐप्लिकेशन को स्ट्रीम करें"</string>
+    <!-- no translation found for summary_watch (4085794790142204006) -->
+    <skip />
+    <!-- no translation found for summary_watch_single_device (1523091550243476756) -->
+    <skip />
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिवाइस से जुड़ी सेवाएं"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, आपके डिवाइसों के बीच ऐप्लिकेशन को स्ट्रीम करने की अनुमति मांग रहा है"</string>
@@ -30,10 +31,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; को अपने फ़ोन से यह जानकारी ऐक्सेस करने की अनुमति दें"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इनमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> आपके <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> की ओर से, फ़ोन में मौजूद फ़ोटो, मीडिया, और सूचनाओं को ऐक्सेस करने की अनुमति मांग रहा है"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिवाइस"</string>
@@ -45,4 +42,29 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;इसमें &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; पर मौजूद माइक्रोफ़ोन, कैमरा, जगह की जानकारी को ऐक्सेस करने, और अन्य संवेदनशील जानकारी ऐक्सेस करने की अनुमतियां शामिल हो सकती हैं.&lt;/p&gt; &lt;p&gt;किसी भी समय &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; की सेटिंग में जाकर, इन अनुमतियों में बदलाव किए जा सकते हैं.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ऐप्लिकेशन आइकॉन"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ज़्यादा जानकारी वाला बटन"</string>
+    <!-- no translation found for permission_phone (2661081078692784919) -->
+    <skip />
+    <!-- no translation found for permission_sms (6337141296535774786) -->
+    <skip />
+    <!-- no translation found for permission_contacts (3858319347208004438) -->
+    <skip />
+    <!-- no translation found for permission_calendar (6805668388691290395) -->
+    <skip />
+    <!-- no translation found for permission_nearby_devices (7530973297737123481) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"फ़ोटो और मीडिया"</string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचनाएं"</string>
+    <!-- no translation found for permission_app_streaming (6009695219091526422) -->
+    <skip />
+    <!-- no translation found for permission_phone_summary (6154198036705702389) -->
+    <skip />
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <!-- no translation found for permission_contacts_summary (7850901746005070792) -->
+    <skip />
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"इससे सभी सूचनाएं देखी जा सकती हैं. इनमें संपर्क, मैसेज, और फ़ोटो जैसी जानकारी शामिल होती है"</string>
+    <!-- no translation found for permission_app_streaming_summary (606923325679670624) -->
+    <skip />
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 0c6d3a2..437ab99 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Dopustite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa vašem uređaju &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"satom"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Odaberite profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kojim će upravljati aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ta je aplikacija potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikacija vašeg telefona"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikacija je potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s vašim obavijestima i pristupati dopuštenjima za telefon, SMS-ove, kontakte, kalendar, zapisnike poziva i uređaje u blizini."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikacija je potrebna za upravljanje vašim uređajem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacija <xliff:g id="APP_NAME">%2$s</xliff:g> moći će stupati u interakciju s ovim dopuštenjima:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usluge na različitim uređajima"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za emitiranje aplikacija između vaših uređaja"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Omogućite aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; da pristupa informacijama s vašeg telefona"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sve obavijesti, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Usluge za Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> zahtijeva dopuštenje u ime vašeg uređaja <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> za pristup fotografijama, medijskim sadržajima i obavijestima na telefonu"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"uređaj"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To može uključivati pristup mikrofonu, kameri i lokaciji i druga dopuštenja za osjetljive podatke na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ta dopuštenja uvijek možete promijeniti u postavkama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb Više informacija"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakti"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Uređaji u blizini"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije i mediji"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Obavijesti"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Može pristupati vašem broju telefona i podacima o mreži. Potrebno je za uspostavu poziva i VoIP, govornu poštu, preusmjeravanje poziva i uređivanje zapisnika poziva"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Može čitati, izrađivati ili uređivati vaš popis kontakata te pristupati popisu kontakata svih računa korištenih na vašem uređaju"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Može čitati sve obavijesti, uključujući informacije kao što su kontakti, poruke i fotografije"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streaming aplikacija vašeg telefona"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index ac458b3..de7aac1 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; hozzáférésének engedélyezése a(z) &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszközhöz"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"óra"</string>
     <string name="chooser_title" msgid="2262294130493605839">"A(z) &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; alkalmazással kezelni kívánt <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiválasztása"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Szükség van erre az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre, a naptárra, a hívásnaplókra és a közeli eszközökre vonatkozó engedélyekhez."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Alkalmazások"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"A telefon alkalmazásainak streamelése"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Szükség van az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd az értesítésekkel, és hozzáférhet a telefonra, az SMS-ekre, a névjegyekre, a naptárra, a hívásnaplókra és a közeli eszközökre vonatkozó engedélyekhez."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Szükség van az alkalmazásra a következő kezeléséhez: <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A(z) <xliff:g id="APP_NAME">%2$s</xliff:g> műveleteket végezhet majd ezekkel az engedélyekkel:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Többeszközös szolgáltatások"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében az alkalmazások eszközök közötti streameléséhez"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Engedélyezi a(z) „<xliff:g id="APP_NAME">%1$s</xliff:g>” alkalmazás számára az információhoz való hozzáférést a telefonról"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-szolgáltatások"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> engedélyt kér a(z) <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nevében a telefonon tárolt fotókhoz, médiatartalmakhoz és értesítésekhez való hozzáféréshez"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"eszköz"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ide tartozhatnak a mikrofonhoz, a kamerához és a helyhez való hozzáférések, valamint a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; eszközön érvényes egyéb, bizalmas adatokra vonatkozó hozzáférési engedélyek is.&lt;/p&gt; &lt;p&gt;Ezeket az engedélyeket bármikor módosíthatja a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; eszköz beállításai között.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Alkalmazás ikonja"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"További információ gomb"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Címtár"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Naptár"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Közeli eszközök"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotók és médiatartalmak"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Értesítések"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Alkalmazások"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Hozzáférhet telefonszámához és hálózati adataihoz. Hívások és VoIP indításához, hívásátirányításhoz és hívásnaplók szerkesztéséhez szükséges."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Olvashatja, létrehozhatja és szerkesztheti a névjegylistánkat, valamint hozzáférhet az eszközén használt összes fiók listájához"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Elolvashat minden értesítést, ideértve az olyan információkat, mint a névjegyek, az üzenetek és a fotók"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"A telefon alkalmazásainak streamelése"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index b4b29cb..acbb453c1 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին կառավարել ձեր &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; սարքը"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ժամացույց"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Ընտրեք <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ը, որը պետք է կառավարվի &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; հավելվածի կողմից"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> սարքը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Օրացույց», «Կանչերի ցուցակ» և «Մոտակա սարքեր» թույլտվությունները։"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Հավելվածներ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Հեռարձակել հեռախոսի հավելվածները"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> պրոֆիլը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածը կկարողանա փոխազդել ձեր ծանուցումների հետ և կստանա «Հեռախոս», «SMS», «Կոնտակտներ», «Օրացույց», «Կանչերի ցուցակ» և «Մոտակա սարքեր» թույլտվությունները։"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Այս հավելվածն անհրաժեշտ է ձեր <xliff:g id="DEVICE_NAME">%1$s</xliff:g> պրոֆիլը կառավարելու համար։ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածին կթույլատրվի օգտվել այս թույլտվություններից․"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Միջսարքային ծառայություններ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր սարքերի միջև հավելվածներ հեռարձակելու համար"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Թույլատրեք &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; հավելվածին օգտագործել այս տեղեկությունները ձեր հեռախոսից"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ծառայություններ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը ձեր <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> սարքի անունից թույլտվություն է խնդրում՝ ձեր հեռախոսի լուսանկարները, մեդիաֆայլերն ու ծանուցումները տեսնելու համար"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"սարք"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Դրանք կարող են ներառել խոսափողի, տեսախցիկի և տեղադրության տվյալների օգտագործման թույլտվությունները, ինչպես նաև կոնֆիդենցիալ տեղեկությունների օգտագործման այլ թույլտվություններ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; սարքում։&lt;/p&gt; &lt;p&gt;Այդ թույլտվությունները ցանկացած ժամանակ կարելի է փոխել &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; սարքի ձեր կարգավորումներում։&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Հավելվածի պատկերակ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"«Այլ տեղեկություններ» կոճակ"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Հեռախոս"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Կոնտակտներ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Օրացույց"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Մոտակա սարքեր"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Լուսանկարներ և մուլտիմեդիա"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Ծանուցումներ"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Հավելվածներ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Կարող է օգտագործել ձեր հեռախոսահամարը և ցանցի մասին տեղեկությունները։ Պահանջվում է սովորական և VoIP զանգեր կատարելու, ձայնային փոստի, զանգերի վերահասցեավորման և զանգերի մատյանները փոփոխելու համար"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Կարող է կարդալ, ստեղծել և փոփոխել կոնտակտների ցանկը, ինչպես նաև բացել ձեր սարքի բոլոր հաշիվների ցանկը"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Կարող է կարդալ բոլոր ծանուցումները, ներառյալ տեղեկությունները, օրինակ՝ կոնտակտները, հաղորդագրությունները և լուսանկարները"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Հեռարձակել հեռախոսի հավելվածները"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index 82fa00a..9c1c2e0 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"smartwatch"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk dikelola oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Aplikasi ini diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, Kalender, Log panggilan, dan Perangkat di sekitar."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikasi"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streaming aplikasi ponsel"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikasi diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan notifikasi dan mengakses izin Telepon, SMS, Kontak, Kalender, Log panggilan, dan Perangkat di sekitar."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikasi diperlukan untuk mengelola <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> akan diizinkan berinteraksi dengan izin ini:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses informasi ini dari ponsel Anda"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Layanan lintas perangkat"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk menstreaming aplikasi di antara perangkat Anda"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Izinkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses informasi ini dari ponsel Anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Dapat membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Layanan Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> meminta izin atas nama <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> untuk mengakses foto, media, dan notifikasi ponsel Anda"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"perangkat"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ini termasuk akses Mikrofon, Kamera, dan Lokasi, serta izin sensitif lainnya di &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Anda dapat mengubah izin ini kapan saja di Setelan pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikon Aplikasi"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Tombol Informasi Lainnya"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telepon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontak"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Perangkat di sekitar"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifikasi"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikasi"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Dapat mengakses nomor telepon dan info jaringan. Diperlukan untuk melakukan panggilan dan VoIP, pesan suara, pengalihan panggilan, dan pengeditan log panggilan"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Dapat membaca, membuat, atau mengedit daftar kontak, serta mengakses daftar kontak untuk semua akun yang digunakan di perangkat"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Dapat membaca semua notifikasi, termasuk informasi seperti kontak, pesan, dan foto"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streaming aplikasi ponsel"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index 59f4f89..3f8c1c3 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"úr"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Velja <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sem &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; á að stjórna"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Þetta forrit er nauðsynlegt til að hafa umsjón með <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða, dagatals, símtalaskráa og nálægra tækja."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Forrit"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streymdu forritum símans"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Forritið er nauðsynlegt til að hafa umsjón með <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær aðgang að tilkynningum og heimildum síma, SMS, tengiliða, dagatals, símtalaskráa og nálægra tækja."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Forritið er nauðsynlegt til að hafa umsjón með <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> fær aðgang að eftirfarandi heimildum:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Þjónustur á milli tækja"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um heimild til straumspilunar forrita á milli tækjanna þinna fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Veita &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aðgang að þessum upplýsingum úr símanum þínum"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Getur lesið allar tilkynningar, þar á meðal upplýsingar á borð við tengiliði, skilaboð og myndir"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Þjónusta Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> sendir beiðni um aðgang að myndum, margmiðlunarefni og tilkynningum símans þíns fyrir hönd <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"tæki"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Þetta kann að fela í sér aðgang að hljóðnema, myndavél og staðsetningu og aðrar heimildir fyrir viðkvæmu efni í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Hægt er að breyta þessum heimildum hvenær sem er í stillingunum í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Tákn forrits"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Hnappur fyrir upplýsingar"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Sími"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Tengiliðir"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Dagatal"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Nálæg tæki"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Myndir og efni"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Tilkynningar"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Forrit"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Fær aðgang að símanúmeri og netkerfisupplýsingum. Nauðsynlegt til að hringja símtöl og netsímtöl, fyrir talhólf, framsendingu símtala og breytingar símtalaskráa"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Getur lesið, búið til eða breytt tengiliðalista og fær auk þess aðgang að tengiliðalista allra reikninga sem eru notaðir í tækinu"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Getur lesið allar tilkynningar, þar á meðal upplýsingar á borð við tengiliði, skilaboð og myndir"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streymdu forritum símans"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 793f0b8..1d53be9 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Consenti all\'app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"orologio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Scegli un <xliff:g id="PROFILE_NAME">%1$s</xliff:g> da gestire con &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Questa app è necessaria per gestire il tuo <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. L\'app <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Calendar, Registri chiamate e Dispositivi nelle vicinanze."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"App"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Trasmetti in streaming le app del tuo telefono"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le tue notifiche e accedere alle autorizzazioni Telefono, SMS, Contatti, Calendario, Registri chiamate e Dispositivi nelle vicinanze."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Questa app è necessaria per gestire <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> potrà interagire con le seguenti autorizzazioni:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a queste informazioni dal tuo telefono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servizi cross-device"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione a trasmettere app in streaming tra i dispositivi"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Consenti a &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; di accedere a questa informazione dal tuo telefono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Puoi leggere tutte le notifiche, incluse le informazioni come contatti, messaggi e foto"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> richiede per conto del tuo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> l\'autorizzazione ad accedere a foto, contenuti multimediali e notifiche del telefono"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Potrebbero essere incluse le autorizzazioni di accesso al microfono, alla fotocamera e alla posizione, nonché altre autorizzazioni sensibili su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puoi cambiare queste autorizzazioni in qualsiasi momento nelle Impostazioni su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icona dell\'app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Pulsante Altre informazioni"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefono"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contatti"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendario"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivi nelle vicinanze"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto e contenuti multimediali"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notifiche"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"App"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Può accedere al tuo numero di telefono e alle informazioni della rete. Necessaria per chiamate e VoIP, segreteria, deviazione delle chiamate e modifica dei registri chiamate"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Può leggere, creare o modificare l\'elenco contatti, nonché accedere all\'elenco contatti di tutti gli account usati sul dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Puoi leggere tutte le notifiche, incluse le informazioni come contatti, messaggi e foto"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Trasmetti in streaming le app del tuo telefono"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index b414125..a169c78 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"‏אישור לאפליקציה ‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&amp;g;‎‏ לגשת אל ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎‏"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"שעון"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏בחירת <xliff:g id="PROFILE_NAME">%1$s</xliff:g> לניהול באמצעות &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"‏האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר, ליומן, ליומני השיחות ולמכשירים בקרבת מקום."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"אפליקציות"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"שידור אפליקציות מהטלפון"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"‏האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לבצע פעולות בהתראות ותקבל הרשאות גישה לטלפון, ל-SMS לאנשי הקשר, ליומן, ליומני השיחות ולמכשירים בקרבת מקום."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"האפליקציה הזו נחוצה כדי לנהל את <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. האפליקציה <xliff:g id="APP_NAME">%2$s</xliff:g> תוכל לקיים אינטראקציה עם ההרשאות הבאות:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"שירותים למספר מכשירים"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור מכשיר <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לשדר אפליקציות בין המכשירים שלך"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏מתן אישור לאפליקציה &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; לגשת למידע הזה מהטלפון שלך"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"התראות"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"גישת קריאה לכל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מבקשת הרשאה עבור מכשיר <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> כדי לגשת לתמונות, למדיה ולהתראות בטלפון שלך"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"מכשיר"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"‏‎&lt;p&gt;‎‏ההרשאות עשויות לכלול גישה למיקרופון, למצלמה ולמיקום, וכן גישה למידע רגיש אחר ב-‎&lt;/strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>‎&lt;/strong&gt;.&lt;/p&amp;gt‎;‎ ‎&lt;p&gt;אפשר לשנות את ההרשאות האלה בכל שלב בהגדרות של‏ ‎&lt;strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>‏‎&lt;/strong&gt;.&lt;/p&gt;‎‏"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"סמל האפליקציה"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"לחצן מידע נוסף"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"טלפון"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"אנשי קשר"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"יומן"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"מכשירים בקרבת מקום"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"תמונות ומדיה"</string>
+    <string name="permission_notification" msgid="693762568127741203">"התראות"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"אפליקציות"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"‏אפשרות לגשת למספר הטלפון ופרטי הרשת שלך. הדבר נדרש לצורך ביצוע שיחות ו-VoIP, להודעה קולית, להפניית שיחות ולעריכת יומני שיחות"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"אפשרות לקרוא, ליצור או לערוך את רשימת אנשי הקשר שלנו, וגם לגשת לרשימה של כל החשבונות שבהם נעשה שימוש במכשיר שלך"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"גישת קריאה לכל ההתראות, כולל מידע כמו אנשי קשר, הודעות ותמונות."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"שידור אפליקציות מהטלפון"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index a3cd4ee3..686e2dd 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; へのアクセスを許可"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ウォッチ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; の管理対象となる<xliff:g id="PROFILE_NAME">%1$s</xliff:g>の選択"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は、通知の使用と、電話、SMS、連絡先、カレンダー、通話履歴、付近のデバイスの権限へのアクセスが可能となります。"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"アプリ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"スマートフォンのアプリをストリーミングします"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は、通知の使用と、電話、SMS、連絡先、カレンダー、通話履歴、付近のデバイスの権限へのアクセスが可能となります。"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"このアプリは<xliff:g id="DEVICE_NAME">%1$s</xliff:g>の管理に必要です。<xliff:g id="APP_NAME">%2$s</xliff:g> は、次の権限の使用が可能となります。"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"スマートフォンのこの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"クロスデバイス サービス"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってデバイス間でアプリをストリーミングする権限をリクエストしています"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"スマートフォンのこの情報へのアクセスを &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; に許可"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"連絡先、メッセージ、写真に関する情報を含め、すべての通知を読み取ることができます"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 開発者サービス"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> が <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> に代わってスマートフォンの写真、メディア、通知にアクセスする権限をリクエストしています"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"デバイス"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;これには、&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; のマイク、カメラ、位置情報へのアクセスや、その他の機密情報に関わる権限が含まれる可能性があります。&lt;/p&gt; &lt;p&gt;これらの権限は &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; の [設定] でいつでも変更できます。&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"アプリのアイコン"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"詳細情報ボタン"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"電話"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"連絡先"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"カレンダー"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"付近のデバイス"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"写真とメディア"</string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"アプリ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"電話番号とネットワーク情報にアクセスできます。電話と VoIP の発信、ボイスメールの送信、通話のリダイレクト、通話履歴の編集に必要です"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"連絡先リストの読み取り、作成、編集を行えるほか、デバイスで使用するすべてのアカウントのリストにアクセスできます"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"連絡先、メッセージ、写真に関する情報を含め、すべての通知を読み取ることができます"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"スマートフォンのアプリをストリーミングします"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index dbb1760..b0ef1c3 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"დაუშვით &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>-ის&lt;/strong&gt;, წვდომა თქვენს &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>-ზე&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"საათი"</string>
     <string name="chooser_title" msgid="2262294130493605839">"აირჩიეთ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, რომელიც უნდა მართოს &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-მა"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ეს აპი საჭიროა თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-ს სამართავად. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა, კალენდრის, ზარების ჟურნალისა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"აპები"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"თქვენი ტელეფონის აპების სტრიმინგი"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ეს აპი საჭიროა, რომ მართოთ თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს თქვენს შეტყობინებებთან ინტერაქციას და თქვენი ტელეფონის, SMS-ების, კონტაქტებისა, კალენდრის, ზარების ჟურნალისა და ახლომახლო მოწყობილობების ნებართვებზე წვდომას."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ეს აპი საჭიროა, რომ მართოთ თქვენი <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> შეძლებს ინტერაქციას შემდეგი ნებართვებით:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"მოწყობილობათშორისი სერვისები"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ მოწყობილობებს შორის აპების სტრიმინგი შეძლოს"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ნება დართეთ, რომ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; აპს ჰქონდეს ამ ინფორმაციაზე წვდომა თქვენი ტელეფონიდან"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტაქტები, ტექსტური შეტყობინებები და ფოტოები"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ითხოვს უფლებას თქვენი <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-ის სახელით, რომ წვდომა ჰქონდეს თქვენი ტელეფონის ფოტოებზე, მედიასა და შეტყობინებებზე"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"მოწყობილობა"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;აღნიშნული შეიძლება მოიცავდეს მიკროფონზე, კამერასა და მდებარეობაზე წვდომას თუ სხვა ნებართვას სენსიტიურ ინფორმაციაზე &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;-ში.&lt;/p&gt; &lt;p&gt;ამ ნებართვების შეცვლა ნებისმიერ დროს შეგიძლიათ თქვენი პარამეტრებიდან &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;-ში.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"აპის ხატულა"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"დამატებითი ინფორმაციის ღილაკი"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Phone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"კონტაქტები"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"კალენდარი"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ახლომახლო მოწყობილობები"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ფოტოები და მედია"</string>
+    <string name="permission_notification" msgid="693762568127741203">"შეტყობინებები"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"აპები"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"შეუძლია თქვენი ტელეფონის ნომერსა და ქსელის ინფორმაციაზე წვდომა. საჭიროა ზარების განსახორციელებლად და VoIP-ისთვის, ხმოვანი ფოსტისთვის, ზარის გადამისამართებისა და ზარების ჟურნალების რედაქტირებისთვის"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"შეუძლია ჩვენი კონტაქტების სიის წაკითხვა, შექმნა ან რედაქტირება, ასევე, თქვენს მოწყობილობაზე გამოყენებული ყველა ანგარიშის კონტაქტების სიაზე წვდომა"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"შეუძლია წაიკითხოს ყველა შეტყობინება, მათ შორის ისეთი ინფორმაცია, როგორიცაა კონტაქტები, ტექსტური შეტყობინებები და ფოტოები"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"თქვენი ტელეფონის აპების სტრიმინგი"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 0d92a97b..18ab580 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысын пайдалануға рұқсат беру"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сағат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; арқылы басқарылатын <xliff:g id="PROFILE_NAME">%1$s</xliff:g> құрылғысын таңдаңыз"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Бұл қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына хабарландырулар жіберу, Телефон, SMS, Контактілер, Күнтізбе, Қоңырау журналдары қолданбаларын және маңайдағы құрылғыларды пайдалану рұқсаттары беріледі."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Қолданбалар"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Телефон қолданбаларын трансляциялайды."</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына хабарландыруларға қатысты әрекет жасау, телефон, SMS, контактілер, күнтізбе, қоңырау журналдары қолданбаларын және маңайдағы құрылғыларды пайдалану рұқсаттары беріледі."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Қолданба <xliff:g id="DEVICE_NAME">%1$s</xliff:g> құрылғысын басқару үшін қажет. <xliff:g id="APP_NAME">%2$s</xliff:g> қолданбасына осы рұқсаттар беріледі:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Аралық құрылғы қызметтері"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан құрылғылар арасында қолданбалар трансляциялау үшін рұқсат сұрайды."</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; қолданбасына телефоныңыздағы осы ақпаратты пайдалануға рұқсат беріңіз."</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқи алады."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play қызметтері"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> атынан телефондағы фотосуреттерді, медиафайлдар мен хабарландыруларды пайдалану үшін рұқсат сұрайды."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"құрылғы"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Оларға микрофонды, камераны және геодеректі пайдалану рұқсаттары, сондай-ақ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; құрылғысына берілетін басқа да құпия ақпарат рұқсаттары кіруі мүмкін.&lt;/p&gt; &lt;p&gt;Бұл рұқсаттарды кез келген уақытта &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; құрылғысындағы параметрлерден өзгерте аласыз.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Қолданба белгішесі"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"\"Қосымша ақпарат\" түймесі"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контактілер"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Күнтізбе"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Маңайдағы құрылғылар"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Фотосуреттер мен медиафайлдар"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Хабарландырулар"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Қолданбалар"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Телефон нөміріңізге және желі ақпаратына қол жеткізе алады. Қоңырау шалу, VoIP, дауыстық хабар жіберу, қоңырау бағытын ауыстыру және қоңырау журналдарын өзгерту үшін қажет."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Контактілер тізімін оқуға, жасауға немесе өзгертуге, сондай-ақ құрылғыңызда қолданылатын барлық аккаунт тізімін пайдалануға рұқсат беріледі."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Барлық хабарландыруды, соның ішінде контактілер, хабарлар және фотосуреттер сияқты ақпаратты оқи алады."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Телефон қолданбаларын трансляциялайды."</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 4d85cfd..c90b3a2 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើប្រាស់ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; របស់អ្នក"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"នាឡិកា"</string>
     <string name="chooser_title" msgid="2262294130493605839">"ជ្រើសរើស <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ដើម្បីឱ្យស្ថិតក្រោម​ការគ្រប់គ្រងរបស់ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតទូរសព្ទ, SMS, ទំនាក់ទំនង, ប្រតិទិន, កំណត់​ហេតុ​ហៅ​ទូរសព្ទ និងឧបករណ៍នៅជិតរបស់អ្នក។"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"កម្មវិធី"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ផ្សាយកម្មវិធីរបស់ទូរសព្ទអ្នក"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យ​ធ្វើអន្តរកម្មជាមួយ​ការជូនដំណឹងរបស់អ្នក និងចូលប្រើការអនុញ្ញាតទូរសព្ទ, SMS, ទំនាក់ទំនង, ប្រតិទិន, កំណត់​ហេតុ​ហៅ​ទូរសព្ទ និងឧបករណ៍នៅជិតរបស់អ្នក។"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ត្រូវការកម្មវិធីនេះ ដើម្បីគ្រប់គ្រង <xliff:g id="DEVICE_NAME">%1$s</xliff:g> របស់អ្នក។ <xliff:g id="APP_NAME">%2$s</xliff:g> នឹងត្រូវបានអនុញ្ញាតឱ្យធ្វើអន្តរកម្មជាមួយការអនុញ្ញាតទាំងនេះ៖"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលប្រើព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"សេវាកម្មឆ្លងកាត់ឧបករណ៍"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីបញ្ចាំងកម្មវិធីរវាងឧបករណ៍របស់អ្នក"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"អនុញ្ញាតឱ្យ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ចូលមើលព័ត៌មាននេះពីទូរសព្ទរបស់អ្នក"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ការ​ជូនដំណឹង"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"អាចអាន​ការជូនដំណឹង​ទាំងអស់ រួមទាំង​ព័ត៌មាន​ដូចជាទំនាក់ទំនង សារ និងរូបថត"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"សេវាកម្ម Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងស្នើសុំការអនុញ្ញាតជំនួសឱ្យ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> របស់អ្នក ដើម្បីចូលប្រើរូបថត មេឌៀ និងការជូនដំណឹងរបស់ទូរសព្ទអ្នក"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ឧបករណ៍"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;សកម្មភាពនេះ​អាចរួមបញ្ចូល​ការចូលប្រើ​ទីតាំង កាមេរ៉ា និងមីក្រូហ្វូន និងការអនុញ្ញាត​ដែលមានលក្ខណៈ​រសើបផ្សេងទៀត​នៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;។&lt;/p&gt; &lt;p&gt;អ្នកអាចប្ដូរ​ការអនុញ្ញាតទាំងនេះ​បានគ្រប់ពេលវេលា​នៅក្នុងការកំណត់​នៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;។&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"រូប​កម្មវិធី"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ប៊ូតុងព័ត៌មានបន្ថែម"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ទូរសព្ទ"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ប្រតិទិន"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ឧបករណ៍នៅជិត"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"រូបថត និងមេឌៀ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ការ​ជូនដំណឹង"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"កម្មវិធី"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"អាចចូលមើលលេខទូរសព្ទ និងព័ត៌មានបណ្ដាញរបស់អ្នក។ ត្រូវបានតម្រូវសម្រាប់ការហៅទូរសព្ទនិង VoIP, សារជាសំឡេង, ការបញ្ជូនបន្តការហៅទូរសព្ទ និងការកែកំណត់ហេតុហៅទូរសព្ទ"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"អាចអាន បង្កើត ឬកែបញ្ជីទំនាក់ទំនងរបស់យើង ក៏ដូចជាចូលប្រើបញ្ជីគណនីទាំងអស់ដែលត្រូវបានប្រើនៅលើឧបករណ៍របស់អ្នក"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"អាចអាន​ការជូនដំណឹង​ទាំងអស់ រួមទាំង​ព័ត៌មាន​ដូចជាទំនាក់ទំនង សារ និងរូបថត"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ផ្សាយកម្មវិធីរបស់ទូរសព្ទអ្នក"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index a8a790a..f60f7bc 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"ನಿಮ್ಮ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ಅನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ವೀಕ್ಷಿಸಿ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ಮೂಲಕ ನಿರ್ವಹಿಸಬೇಕಾದ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. ಅನ್ನು ನಿರ್ವಹಿಸಲು ಈ ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, Calendar, ಕರೆಯ ಲಾಗ್‌ಗಳು ಹಾಗೂ ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ಆ್ಯಪ್‌ಗಳು"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ನಿಮ್ಮ ಫೋನ್‍ನ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. ನಿಮ್ಮ ಅಧಿಸೂಚನೆಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಮತ್ತು ನಿಮ್ಮ ಫೋನ್, SMS, ಸಂಪರ್ಕಗಳು, Calendar, ಕರೆಯ ಲಾಗ್‌ಗಳು ಹಾಗೂ ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳ ಅನುಮತಿಗಳನ್ನು ಪ್ರವೇಶಿಸಲು <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಅನುಮತಿಸಲಾಗುತ್ತದೆ."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ನಿಮ್ಮ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ವಹಿಸಲು ಆ್ಯಪ್‌ನ ಅಗತ್ಯವಿದೆ. <xliff:g id="APP_NAME">%2$s</xliff:g> ಗೆ ಈ ಅನುಮತಿಗಳೊಂದಿಗೆ ಸಂವಹನ ನಡೆಸಲು ಅನುಮತಿಸಲಾಗುವುದು:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಆ್ಯಕ್ಸೆಸ್ ಮಾಡಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ಕ್ರಾಸ್-ಡಿವೈಸ್ ಸೇವೆಗಳು"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"ನಿಮ್ಮ ಸಾಧನಗಳ ನಡುವೆ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ನಿಮ್ಮ ಫೋನ್ ಮೂಲಕ ಈ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಲು &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ಗೆ ಅನುಮತಿಸಿ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ಸೇವೆಗಳು"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"ನಿಮ್ಮ ಫೋನ್‌ನ ಫೋಟೋಗಳು, ಮೀಡಿಯಾ ಮತ್ತು ಅಧಿಸೂಚನೆಗಳನ್ನು ಪ್ರವೇಶಿಸಲು ನಿಮ್ಮ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ನ ಪರವಾಗಿ <xliff:g id="APP_NAME">%1$s</xliff:g> ಅನುಮತಿಯನ್ನು ವಿನಂತಿಸಿಕೊಳ್ಳುತ್ತಿದೆ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ಸಾಧನ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ಇದು &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಮೈಕ್ರೊಫೋನ್, ಕ್ಯಾಮರಾ ಮತ್ತು ಸ್ಥಳ ಆ್ಯಕ್ಸೆಸ್ ಹಾಗೂ ಇತರ ಸೂಕ್ಷ್ಮ ಅನುಮತಿಗಳನ್ನು ಹೊಂದಿರಬಹುದು&lt;p&gt;&lt;/p&gt; &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ನಿಮ್ಮ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ನೀವು ಈ ಅನುಮತಿಗಳನ್ನು ಯಾವಾಗ ಬೇಕಾದರೂ ಬದಲಾಯಿಸಬಹುದು.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ಹೆಚ್ಚಿನ ಮಾಹಿತಿಯ ಬಟನ್"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ಫೋನ್"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"ಸಂಪರ್ಕಗಳು"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ಸಮೀಪದಲ್ಲಿರುವ ಸಾಧನಗಳು"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ಫೋಟೋಗಳು ಮತ್ತು ಮಾಧ್ಯಮ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ಆ್ಯಪ್‌ಗಳು"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"ನಿಮ್ಮ ಫೋನ್ ಸಂಖ್ಯೆ ಮತ್ತು ನೆಟ್‌ವರ್ಕ್ ಮಾಹಿತಿಯನ್ನು ಪ್ರವೇಶಿಸಬಹುದು. ಕರೆಗಳನ್ನು ಮಾಡಲು ಮತ್ತು VoIP, ಧ್ವನಿಮೇಲ್, ಕರೆ ಮರುನಿರ್ದೇಶನ ಮತ್ತು ಕರೆಯ ಲಾಗ್‌ಗಳನ್ನು ಎಡಿಟ್ ಮಾಡಲು ಅಗತ್ಯವಿದೆ"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"ನಮ್ಮ ಸಂಪರ್ಕ ಪಟ್ಟಿಯನ್ನು ಓದಬಹುದು, ರಚಿಸಬಹುದು ಅಥವಾ ಎಡಿಟ್ ಮಾಡಬಹುದು, ಹಾಗೆಯೇ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಬಳಸಲಾದ ಎಲ್ಲಾ ಖಾತೆಗಳ ಪಟ್ಟಿಯನ್ನು ಪ್ರವೇಶಿಸಬಹುದು"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"ಸಂಪರ್ಕಗಳು, ಸಂದೇಶಗಳು ಮತ್ತು ಫೋಟೋಗಳಂತಹ ಮಾಹಿತಿಯನ್ನು ಒಳಗೊಂಡಂತೆ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ಓದಬಹುದು"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ನಿಮ್ಮ ಫೋನ್‍ನ ಆ್ಯಪ್‌ಗಳನ್ನು ಸ್ಟ್ರೀಮ್ ಮಾಡಿ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index c78affa..3442ab2 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;에서 내 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 기기에 액세스하도록 허용"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"시계"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;에서 관리할 <xliff:g id="PROFILE_NAME">%1$s</xliff:g>을(를) 선택"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 프로필을 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, Calendar, 통화 기록, 근처 기기에 대한 권한을 갖게 됩니다."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"앱"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"휴대전화의 앱을 스트리밍합니다."</string>
+    <string name="summary_watch" msgid="4085794790142204006">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 알림과 상호작용하고 내 전화, SMS, 연락처, Calendar, 통화 기록, 근처 기기에 대한 권한을 갖게 됩니다."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"이 앱은 <xliff:g id="DEVICE_NAME">%1$s</xliff:g> 기기를 관리하는 데 필요합니다. <xliff:g id="APP_NAME">%2$s</xliff:g>에서 다음 권한과 상호작용할 수 있습니다."</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;이 휴대전화의 이 정보에 액세스하도록 허용합니다."</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"교차 기기 서비스"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 기기 간에 앱을 스트리밍할 수 있는 권한을 요청하고 있습니다."</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 앱이 휴대전화에서 이 정보에 액세스하도록 허용"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"알림"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 서비스"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 대신 휴대전화의 사진, 미디어, 알림에 액세스할 수 있는 권한을 요청하고 있습니다."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"기기"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;여기에는 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;에서 허용했던 마이크, 카메라, 위치 정보 액세스 권한 및 기타 민감한 권한이 포함될 수 있습니다.&lt;/p&gt; &lt;p&gt;언제든지 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;의 설정에서 이러한 권한을 변경할 수 있습니다.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"앱 아이콘"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"추가 정보 버튼"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"전화"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"연락처"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"캘린더"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"근처 기기"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"사진 및 미디어"</string>
+    <string name="permission_notification" msgid="693762568127741203">"알림"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"앱"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"전화번호 및 네트워크 정보에 액세스할 수 있습니다. 전화 걸기 및 VoIP, 음성사서함, 통화 리디렉션, 통화 기록 수정 시 필요합니다."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"연락처 목록을 읽고, 만들고, 수정할 수 있으며 기기에서 사용되는 모든 계정의 목록에도 액세스할 수 있습니다."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"연락처, 메시지, 사진 등의 정보를 포함한 모든 알림을 읽을 수 있습니다."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"휴대전화의 앱을 스트리밍합니다."</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index ead2037..36a72ff 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүңүзгө кирүүгө уруксат бериңиз"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"саат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"<xliff:g id="PROFILE_NAME">%1$s</xliff:g> &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; тарабынан башкарылсын"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү башкаруу үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, байланыштар, жылнаама, чалуулар тизмеси жана жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Колдонмолор"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Телефондогу колдонмолорду алып ойнотуу"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү тескөө үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> билдирмелериңизди көрүп, телефонуңуз, SMS билдирүүлөр, байланыштар, жылнаама, чалуулар тизмеси жана жакын жердеги түзмөктөргө болгон уруксаттарды пайдалана алат."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Бул колдонмо <xliff:g id="DEVICE_NAME">%1$s</xliff:g> түзмөгүңүздү тескөө үчүн керек. <xliff:g id="APP_NAME">%2$s</xliff:g> төмөнкү уруксаттарды пайдалана алат:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Түзмөктөр аралык кызматтар"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан түзмөктөрүңүздүн ортосунда колдонмолорду өткөрүүгө уруксат сурап жатат"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; колдонмосуна телефонуңуздагы ушул маалыматты көрүүгө уруксат бериңиз"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуй алат"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиафайлдар"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play кызматтары"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> түзмөгүңүздүн атынан телефондогу сүрөттөрдү, медиа файлдарды жана билдирмелерди колдонууга уруксат сурап жатат"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"түзмөк"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Бул уруксаттарга микрофонго, камерага жана жайгашкан жерге кирүү мүмкүнчүлүгү жана &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү башка купуя маалыматты көрүүгө уруксаттар кириши мүмкүн.&lt;/p&gt; &lt;p&gt;Бул уруксаттарды каалаган убакта &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; түзмөгүндөгү Жөндөөлөрдөн өзгөртө аласыз.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Колдонмонун сүрөтчөсү"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Дагы маалымат баскычы"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Байланыштар"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Жылнаама"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Жакын жердеги түзмөктөр"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Сүрөттөр жана медиафайлдар"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Билдирмелер"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Колдонмолор"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Телефонуңуздун номерин жана тармак тууралуу маалыматты көрө алат. Чалуу жана VoIP, үн почтасы, чалууларды багыттоо жана чалуулар тизмесин түзөтүү үчүн талап кылынат"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Байланыштар тизмесин окуп, түзүп же түзөтүп жана түзмөгүңүздөгү бардык аккаунттардагы тизмелерге кире алат"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Бардык билдирмелерди, анын ичинде байланыштар, билдирүүлөр жана сүрөттөр сыяктуу маалыматты окуй алат"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Телефондогу колдонмолорду алып ойнотуу"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 6a9197e..9283eb7 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ຂອງທ່ານໄດ້"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ໂມງ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"ເລືອກ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ເພື່ອໃຫ້ຖືກຈັດການໂດຍ &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ຕ້ອງໃຊ້ແອັບນີ້ເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ປະຕິທິນ, ບັນທຶກການໂທ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ແອັບ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ຕ້ອງໃຊ້ແອັບດັ່ງກ່າວເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການແຈ້ງເຕືອນຂອງທ່ານ ແລະ ເຂົ້າເຖິງການອະນຸຍາດໂທລະສັບ, SMS, ລາຍຊື່ຜູ້ຕິດຕໍ່, ປະຕິທິນ, ບັນທຶກການໂທ ແລະ ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງຂອງທ່ານ."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ຕ້ອງໃຊ້ແອັບດັ່ງກ່າວເພື່ອຈັດການ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ຂອງທ່ານ. <xliff:g id="APP_NAME">%2$s</xliff:g> ຈະໄດ້ຮັບອະນຸຍາດໃຫ້ໂຕ້ຕອບກັບການອະນຸຍາດເຫຼົ່ານີ້:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ບໍລິການຂ້າມອຸປະກອນ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອສະຕຣີມແອັບລະຫວ່າງອຸປະກອນຂອງທ່ານ"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ອະນຸຍາດ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ໃຫ້ເຂົ້າເຖິງຂໍ້ມູນນີ້ຈາກໂທລະສັບຂອງທ່ານໄດ້"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"ສາມາດອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"ບໍລິການ Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງຮ້ອງຂໍການອະນຸຍາດໃນນາມຂອງ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ເພື່ອເຂົ້າເຖິງຮູບພາບ, ມີເດຍ ແລະ ການແຈ້ງເຕືອນຂອງໂທລະສັບທ່ານ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ອຸປະກອນ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ນີ້ອາດຮວມສິດເຂົ້າເຖິງໄມໂຄຣໂຟນ, ກ້ອງຖ່າຍຮູບ ແລະ ສະຖານທີ່, ຮວມທັງການອະນຸຍາດທີ່ລະອຽດອ່ອນອື່ນໆຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;ທ່ານສາມາດປ່ຽນການອະນຸຍາດເຫຼົ່ານີ້ຕອນໃດກໍໄດ້ໃນການຕັ້ງຄ່າຂອງທ່ານຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ໄອຄອນແອັບ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ປຸ່ມຂໍ້ມູນເພີ່ມເຕີມ"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ໂທລະສັບ"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ປະຕິທິນ"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ອຸປະກອນທີ່ຢູ່ໃກ້ຄຽງ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ຮູບພາບ ແລະ ມີເດຍ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ການແຈ້ງເຕືອນ"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ແອັບ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"ສາມາດເຂົ້າເຖິງເບີໂທລະສັບ ແລະ ຂໍ້ມູນເຄືອຂ່າຍຂອງທ່ານ. ເຊິ່ງຈຳເປັນສຳລັບການໂທ ແລະ VoIP, ຂໍ້ຄວາມສຽງ, ການປ່ຽນເສັ້ນທາງການໂທ ແລະ ການແກ້ໄຂບັນທຶກການໂທ"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"ສາມາດອ່ານ, ສ້າງ ຫຼື ແກ້ໄຂລາຍຊື່ຜູ້ຕິດຕໍ່ຂອງພວກເຮົາ, ຮວມທັງເຂົ້າເຖິງລາຍຊື່ຂອງບັນຊີທັງໝົດທີ່ໃຊ້ຢູ່ໃນອຸປະກອນຂອງທ່ານ"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"ສາມາດອ່ານການແຈ້ງເຕືອນທັງໝົດ, ຮວມທັງຂໍ້ມູນ ເຊັ່ນ: ລາຍຊື່ຜູ້ຕິດຕໍ່, ຂໍ້ຄວາມ ແລະ ຮູບພາບ"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ສະຕຣີມແອັບຂອງໂທລະສັບທ່ານ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index f2cbfa0..3483cf3 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti jūsų &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"laikrodį"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Jūsų <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, kurį valdys &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; (pasirinkite)"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ši programa reikalinga norint tvarkyti jūsų „<xliff:g id="DEVICE_NAME">%1$s</xliff:g>“. „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su pranešimų funkcija ir pasiekti telefono, SMS, Kontaktų, Kalendoriaus, Skambučių žurnalų ir įrenginių netoliese leidimus."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Programos"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Telefono programų perdavimas srautu"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Programa reikalinga norint tvarkyti jūsų <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su pranešimų funkcija ir pasiekti Telefono, SMS, Kontaktų, Kalendoriaus, Skambučių žurnalų ir Įrenginių netoliese leidimus."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Programa reikalinga norint tvarkyti jūsų <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. „<xliff:g id="APP_NAME">%2$s</xliff:g>“ bus leidžiama sąveikauti su toliau nurodytais leidimais."</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Pasl. keliuose įrenginiuose"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų srautu perduoti programas iš vieno įrenginio į kitą"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Leisti &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; pasiekti šią informaciją iš jūsų telefono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Galima skaityti visus pranešimus, įskaitant tokią informaciją kaip kontaktai, pranešimai ir nuotraukos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"„Google Play“ paslaugos"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ prašo leidimo jūsų „<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>“ vardu, kad galėtų pasiekti telefono nuotraukas, mediją ir pranešimus"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"įrenginys"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Gali būti įtraukti prieigos prie mikrofono, kameros ir vietovės leidimai ir kiti leidimai pasiekti neskelbtiną informaciją &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; įrenginyje.&lt;/p&gt; &lt;p&gt;Šiuos leidimus galite bet kada pakeisti „Nustatymų“ skiltyje &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; įrenginyje.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Programos piktograma"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Mygtukas „Daugiau informacijos“"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefonas"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktai"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendorius"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Įrenginiai netoliese"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Nuotraukos ir medija"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Pranešimai"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Programos"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Galima pasiekti telefono numerio ir tinklo informaciją. Reikalinga norint skambinti ir naudoti „VoIP“, balso paštą, skambučių peradresavimo funkciją bei redaguoti skambučių žurnalus"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Galima skaityti, kurti ar redaguoti kontaktų sąrašą bei pasiekti visų įrenginyje naudojamų paskyrų sąrašą"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Galima skaityti visus pranešimus, įskaitant tokią informaciją kaip kontaktai, pranešimai ir nuotraukos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefono programų perdavimas srautu"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index e8947c7..039cc4d 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Atļauja lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt jūsu ierīcei &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"pulkstenis"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Profila (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>) izvēle, ko pārvaldīt lietotnē &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. Lietotnei <xliff:g id="APP_NAME">%2$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas, Kalendārs, Zvanu žurnāli un Tuvumā esošas ierīces."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Lietotnes"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Var straumēt jūsu tālruņa lietotnes"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. Lietotnei <xliff:g id="APP_NAME">%2$s</xliff:g> tiks atļauts mijiedarboties ar jūsu paziņojumiem un piekļūt šādām atļaujām: Tālrunis, Īsziņas, Kontaktpersonas, Kalendārs, Zvanu žurnāli un Tuvumā esošas ierīces."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Šī lietotne ir nepieciešama jūsu ierīces (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) pārvaldībai. Lietotnei <xliff:g id="APP_NAME">%2$s</xliff:g> tiks atļauts mijiedarboties ar šīm atļaujām:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Vairāku ierīču pakalpojumi"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju straumēt lietotnes starp jūsu ierīcēm šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Atļaut lietotnei &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; piekļūt šai informācijai no jūsu tālruņa"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Var lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumi un fotoattēli."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play pakalpojumi"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> pieprasa atļauju piekļūt jūsu tālruņa fotoattēliem, multivides saturam un paziņojumiem šīs ierīces vārdā: <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ierīce"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Tās var būt mikrofona, kameras, atrašanās vietas piekļuves atļaujas un citas sensitīvas atļaujas ierīcē &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Atļaujas jebkurā brīdī varat mainīt ierīces &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; iestatījumos."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Lietotnes ikona"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Plašākas informācijas poga"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Tālrunis"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Īsziņas"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktpersonas"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendārs"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Tuvumā esošas ierīces"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotoattēli un multivides faili"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Paziņojumi"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Lietotnes"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Var piekļūt jūsu tālruņa numuram un tīkla informācijai. Nepieciešama, lai veiktu zvanus un VoIP zvanus, izmantotu balss pastu, pāradresētu zvanus un rediģētu zvanu žurnālus."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Var lasīt, izveidot vai rediģēt jūsu kontaktpersonu sarakstu, kā arī piekļūt visu jūsu ierīcē izmantoto kontu kontaktpersonu sarakstiem"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Var lasīt visus paziņojumus, tostarp tādu informāciju kā kontaktpersonas, ziņojumi un fotoattēli."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Straumēt jūsu tālruņa lietotnes"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 6ef9e5d..938932d 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до вашиот &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часовник"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Изберете <xliff:g id="PROFILE_NAME">%1$s</xliff:g> со којшто ќе управува &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Апликацијава е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за телефонот, SMS, контактите, календарот, евиденцијата на повици и уредите во близина."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Апликации"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Стримувајте ги апликациите на телефонот"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Апликацијата е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со известувањата и да пристапува до дозволите за „Телефон“, SMS, „Контакти“, „Календар“, „Евиденција на повици“ и „Уреди во близина“."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Апликацијата е потребна за управување со вашиот <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ќе може да остварува интеракција со следниве дозволи:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Овозможете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Повеќенаменски услуги"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да стримува апликации помеѓу вашите уреди"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Дозволете &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; да пристапува до овие податоци на телефонот"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Услуги на Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> бара дозвола во име на вашиот <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за да пристапува до фотографиите, аудиовизуелните содржини и известувањата на телефонот"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уред"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ова може да вклучува пристап до микрофон, камера и локација и други чувствителни дозволи на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Може да ги промените дозволиве во секое време во вашите „Поставки“ на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Икона на апликацијата"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Копче за повеќе информации"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контакти"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календар"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Уреди во близина"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Аудиовизуелни содржини"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Известувања"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Апликации"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Може да пристапува до вашиот телефонски број и податоците за мрежата. Потребно за упатување повици и VoIP, говорна пошта, пренасочување повици и изменување евиденција на повици"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Може да го чита, создава или изменува вашиот список со контакти, како и да пристапува до списоците со контакти на сите сметки што се користат на уредот"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"може да ги чита сите известувања, вклучително и податоци како контакти, пораки и фотографии"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Стримувајте ги апликациите на телефонот"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 07e6a43..15434fc 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -20,9 +20,10 @@
     <string name="confirmation_title" msgid="3785000297483688997">"നിങ്ങളുടെ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിനെ അനുവദിക്കുക"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"വാച്ച്"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ഉപയോഗിച്ച് മാനേജ് ചെയ്യുന്നതിന് ഒരു <xliff:g id="PROFILE_NAME">%1$s</xliff:g> തിരഞ്ഞെടുക്കുക"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"നിങ്ങളുടെ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> മാനേജ് ചെയ്യാൻ ഈ ആപ്പ് ആവശ്യമാണ്. നിങ്ങളുടെ അറിയിപ്പുകളുമായി ആശയവിനിമയം നടത്താനും നിങ്ങളുടെ ഫോൺ, SMS, കോൺടാക്‌റ്റുകൾ, കലണ്ടർ, കോൾ ചരിത്രം, സമീപമുള്ള ഉപകരണങ്ങളുടെ അനുമതികൾ എന്നിവ ആക്‌സസ് ചെയ്യാനും <xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിനെ അനുവദിക്കും."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ആപ്പുകൾ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"നിങ്ങളുടെ ഫോണിലെ ആപ്പുകൾ സ്‌ട്രീം ചെയ്യാൻ"</string>
+    <!-- no translation found for summary_watch (4085794790142204006) -->
+    <skip />
+    <!-- no translation found for summary_watch_single_device (1523091550243476756) -->
+    <skip />
     <string name="title_app_streaming" msgid="2270331024626446950">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ക്രോസ്-ഉപകരണ സേവനങ്ങൾ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"നിങ്ങളുടെ ഉപകരണങ്ങളിൽ ഒന്നിൽ നിന്ന് അടുത്തതിലേക്ക് ആപ്പുകൾ സ്ട്രീം ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
@@ -30,10 +31,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"നിങ്ങളുടെ ഫോണിൽ നിന്ന് ഈ വിവരങ്ങൾ ആക്‌സസ് ചെയ്യാൻ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ആപ്പിനെ അനുവദിക്കുക"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"കോൺടാക്‌റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ മുതലായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play സേവനങ്ങൾ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"നിങ്ങളുടെ ഫോണിലെ ഫോട്ടോകൾ, മീഡിയ, അറിയിപ്പുകൾ എന്നിവ ആക്സസ് ചെയ്യാൻ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ഉപകരണത്തിന് വേണ്ടി <xliff:g id="APP_NAME">%1$s</xliff:g> അനുമതി അഭ്യർത്ഥിക്കുന്നു"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ഉപകരണം"</string>
@@ -45,4 +42,29 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; എന്നതിലെ മൈക്രോഫോൺ, ക്യാമറ, ലൊക്കേഷൻ ആക്‌സസ്, സെൻസിറ്റീവ് വിവരങ്ങൾക്കുള്ള മറ്റ് അനുമതികൾ എന്നിവയും ഇതിൽ ഉൾപ്പെട്ടേക്കാം&lt;p&gt;നിങ്ങൾക്ക് &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; എന്നതിലെ ക്രമീകരണത്തിൽ ഏതുസമയത്തും ഈ അനുമതികൾ മാറ്റാം."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ആപ്പ് ഐക്കൺ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"കൂടുതൽ വിവരങ്ങൾ ബട്ടൺ"</string>
+    <!-- no translation found for permission_phone (2661081078692784919) -->
+    <skip />
+    <!-- no translation found for permission_sms (6337141296535774786) -->
+    <skip />
+    <!-- no translation found for permission_contacts (3858319347208004438) -->
+    <skip />
+    <!-- no translation found for permission_calendar (6805668388691290395) -->
+    <skip />
+    <!-- no translation found for permission_nearby_devices (7530973297737123481) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"ഫോട്ടോകളും മീഡിയയും"</string>
+    <string name="permission_notification" msgid="693762568127741203">"അറിയിപ്പുകൾ"</string>
+    <!-- no translation found for permission_app_streaming (6009695219091526422) -->
+    <skip />
+    <!-- no translation found for permission_phone_summary (6154198036705702389) -->
+    <skip />
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <!-- no translation found for permission_contacts_summary (7850901746005070792) -->
+    <skip />
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"കോൺടാക്‌റ്റുകൾ, സന്ദേശങ്ങൾ, ഫോട്ടോകൾ മുതലായ വിവരങ്ങൾ ഉൾപ്പെടെയുള്ള എല്ലാ അറിയിപ്പുകളും വായിക്കാനാകും"</string>
+    <!-- no translation found for permission_app_streaming_summary (606923325679670624) -->
+    <skip />
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 1c74e48..511e9eb 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-д таны &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д хандахыг зөвшөөрнө үү"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"цаг"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;-н удирдах<xliff:g id="PROFILE_NAME">%1$s</xliff:g>-г сонгоно уу"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д таны мэдэгдэлтэй харилцан үйлдэл хийж, Утас, SMS, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Аппууд"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Таны утасны аппуудыг дамжуулах"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д таны мэдэгдэлтэй харилцан үйлдэл хийж, Утас, SMS, Харилцагчид, Календарь, Дуудлагын жагсаалт болон Ойролцоох төхөөрөмжүүдийн зөвшөөрөлд хандахыг зөвшөөрнө."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Энэ апп таны <xliff:g id="DEVICE_NAME">%1$s</xliff:g>-г удирдахад шаардлагатай. <xliff:g id="APP_NAME">%2$s</xliff:g>-д эдгээр зөвшөөрөлтэй харилцан үйлдэл хийхийг зөвшөөрнө:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Төхөөрөмж хоорондын үйлчилгээ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Таны төхөөрөмжүүд хооронд апп дамжуулахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;-д таны утаснаас энэ мэдээлэлд хандахыг зөвшөөрнө үү"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Харилцагчид, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play үйлчилгээ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Таны утасны зураг, медиа болон мэдэгдэлд хандахын тулд <xliff:g id="APP_NAME">%1$s</xliff:g> таны <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>-н өмнөөс зөвшөөрөл хүсэж байна"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"төхөөрөмж"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Үүнд Микрофон, Камер болон Байршлын хандалт болон &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; дээрх бусад эмзэг зөвшөөрөл багтаж болно.&lt;/p&gt; &lt;p&gt;Та эдгээр зөвшөөрлийг &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; дээрх Тохиргоо хэсэгтээ хүссэн үедээ өөрчлөх боломжтой.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Aппын дүрс тэмдэг"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Дэлгэрэнгүй мэдээллийн товчлуур"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Утас"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Харилцагчид"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календарь"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Ойролцоох төхөөрөмжүүд"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Зураг болон медиа"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Мэдэгдэл"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Аппууд"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Таны утасны дугаар болон сүлжээний мэдээлэлд хандах боломжтой. Дуудлага хийх, VoIP, дуут шуудан, дуудлагыг дахин чиглүүлэх болон дуудлагын жагсаалтыг засахад шаардлагатай"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Манай харилцагчийн жагсаалтыг унших, үүсгэх эсвэл засахаас гадна таны төхөөрөмж дээр ашигласан бүх бүртгэлийн жагсаалтад хандах боломжтой"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Харилцагчид, мессеж болон зураг зэрэг мэдээллийг оруулаад бүх мэдэгдлийг унших боломжтой"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Утасныхаа аппуудыг дамжуулаарай"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 1cc0412..37a8349 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"तुमचे &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; अ‍ॅक्सेस करण्यासाठी &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला अनुमती द्या"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"वॉच"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; द्वारे व्यवस्थापित करण्यासाठी <xliff:g id="PROFILE_NAME">%1$s</xliff:g> निवडा"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"तुमची <xliff:g id="DEVICE_NAME">%1$s</xliff:g> प्रोफाइल व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ॲप्स"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"फोनवरील ॲप्स स्ट्रीम करा"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"तुमचे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला तुमच्या सूचनांशी संवाद साधण्याची आणि तुमचा फोन, एसएमएस, संपर्क कॅलेंडर, कॉल लॉग व जवळपासच्या डिव्हाइसच्या परवानग्या अ‍ॅक्सेस करण्याची अनुमती मिळेल."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"तुमचे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापित करण्यासाठी हे ॲप आवश्यक आहे. <xliff:g id="APP_NAME">%2$s</xliff:g> ला पुढील परवानग्यांशी संवाद साधण्याची अनुमती मिळेल:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रॉस-डिव्हाइस सेवा"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"तुमच्या डिव्हाइसदरम्यान ॲप्स स्ट्रीम करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ला ही माहिती तुमच्या फोनवरून अ‍ॅक्सेस करण्यासाठी अनुमती द्या"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"सूचना"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीचा समावेश असलेल्या सर्व सूचना वाचू शकते"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play सेवा"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"तुमच्या फोनमधील फोटो, मीडिया आणि सूचना ॲक्सेस करण्यासाठी <xliff:g id="APP_NAME">%1$s</xliff:g> हे तुमच्या <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> च्या वतीने परवानगीची विनंती करत आहे"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"डिव्हाइस"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;यामध्ये &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;strong&gt; वरील मायक्रोफोन, कॅमेरा आणि स्थान अ‍ॅक्सेस व इतर संवेदनशील परवानग्यांचा समावेश असू शकतो &lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;तुम्ही &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; वर तुमच्या सेटिंग्ज मध्ये या परवानग्या कधीही बदलू शकता&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"अ‍ॅप आयकन"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"अधिक माहिती बटण"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"फोन"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"एसएमएस"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacts"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"जवळपासची डिव्हाइस"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"फोटो आणि मीडिया"</string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचना"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ॲप्स"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"तुमचा फोन नंबर आणि नेटवर्कची माहिती अ‍ॅक्सेस करू शकते. कॉल करणे व VoIP, व्हॉइसमेल, कॉल रीडिरेक्ट करणे आणि कॉल लॉग संपादित करणे यांसाठी आवश्यक"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"आमची संपर्क सूची रीड, तयार आणि संपादित करू शकते, तसेच तुमच्या डिव्हाइसवर वापरल्या जाणाऱ्या खात्यांची सूची अ‍ॅक्सेस करू शकते"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"संपर्क, मेसेज आणि फोटो यांसारख्या माहितीचा समावेश असलेल्या सर्व सूचना वाचू शकते"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"तुमच्या फोनवरील ॲप्स स्ट्रीम करा"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 02743f0..ac9acbc 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; anda"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"jam tangan"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pilih <xliff:g id="PROFILE_NAME">%1$s</xliff:g> untuk diurus oleh &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Kalendar, Log panggilan dan Peranti berdekatan anda."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apl"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Strim apl telefon anda"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan berinteraksi dengan pemberitahuan anda dan mengakses kebenaran Telefon, SMS, Kenalan, Kalendar, Log panggilan serta Peranti berdekatan anda."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Apl ini diperlukan untuk mengurus <xliff:g id="DEVICE_NAME">%1$s</xliff:g> anda. <xliff:g id="APP_NAME">%2$s</xliff:g> akan dibenarkan berinteraksi dengan kebenaran ini:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; mengakses maklumat ini daripada telefon anda"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Perkhidmatan silang peranti"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk menstrim apl antara peranti anda"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Benarkan &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; untuk mengakses maklumat ini daripada telefon anda"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Perkhidmatan Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang meminta kebenaran bagi pihak <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> anda untuk mengakses foto, media dan pemberitahuan telefon anda"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"peranti"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Ini mungkin termasuk akses Mikrofon, Kamera dan Lokasi serta kebenaran sensitif lain pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Anda boleh menukar kebenaran ini pada bila-bila masa dalam Tetapan anda pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikon Apl"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Butang Maklumat Lagi"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kenalan"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Peranti berdekatan"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto dan media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Pemberitahuan"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apl"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Boleh mengakses nombor telefon dan maklumat rangkaian anda. Diperlukan untuk membuat panggilan dan VoIP, mel suara, ubah hala panggilan dan mengedit log panggilan"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Boleh membaca, membuat atau mengedit senarai kenalan kami, serta mengakses senarai semua akaun yang digunakan pada peranti anda"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Boleh membaca semua pemberitahuan, termasuk maklumat seperti kenalan, mesej dan foto"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strim apl telefon anda"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index 61272cc..271ddee 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"သင်၏ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ကို သုံးရန် &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို ခွင့်ပြုပါ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"နာရီ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; က စီမံခန့်ခွဲရန် <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ကို ရွေးချယ်ပါ"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်ကိုလိုအပ်သည်။ သင်၏ ‘ဖုန်း’၊ ‘SMS စာတိုစနစ်’၊ ‘အဆက်အသွယ်များ’၊ ‘ပြက္ခဒိန်’၊ ‘ခေါ်ဆိုမှတ်တမ်း’ နှင့် \'အနီးတစ်ဝိုက်ရှိ စက်များ\' ခွင့်ပြုချက်များကို သုံးရန်နှင့် အကြောင်းကြားချက်များကို ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> အား ခွင့်ပြုပါမည်။"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"အက်ပ်များ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်လွှင့်နိုင်သည်"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ သင်၏ဖုန်း၊ SMS စာတိုစနစ်၊ အဆက်အသွယ်များ၊ ပြက္ခဒိန်၊ ခေါ်ဆိုမှတ်တမ်းနှင့် အနီးတစ်ဝိုက်ရှိ စက်များဆိုင်ရာ ခွင့်ပြုချက်များသုံးရန်၊ အကြောင်းကြားချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်။"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"သင်၏ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ကို စီမံခန့်ခွဲရန် ဤအက်ပ်လိုအပ်သည်။ ဤခွင့်ပြုချက်များနှင့် ပြန်လှန်တုံ့ပြန်ရန် <xliff:g id="APP_NAME">%2$s</xliff:g> ကို ခွင့်ပြုမည်-"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ကို သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုမည်"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"စက်များကြားသုံး ဝန်ဆောင်မှုများ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင်၏စက်များအကြား အက်ပ်များတိုက်ရိုက်လွှင့်ရန် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; အား သင့်ဖုန်းမှ ဤအချက်အလက် သုံးခွင့်ပြုခြင်း"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ဝန်ဆောင်မှုများ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် သင့်ဖုန်း၏ ဓာတ်ပုံ၊ မီဒီယာနှင့် အကြောင်းကြားချက်များသုံးရန် <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ကိုယ်စား ခွင့်ပြုချက်တောင်းနေသည်"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"စက်"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;၎င်းတွင် မိုက်ခရိုဖုန်း၊ ကင်မရာ၊ တည်နေရာ အသုံးပြုခွင့်အပြင် &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ပေါ်ရှိ အခြား သတိထားရမည့် ခွင့်ပြုချက်များ ပါဝင်နိုင်သည်။&lt;/p&gt; &lt;p&gt;ဤခွင့်ပြုချက်များကို &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ပေါ်ရှိ သင်၏ဆက်တင်များတွင် အချိန်မရွေးပြောင်းနိုင်သည်။&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"အက်ပ်သင်္ကေတ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"နောက်ထပ်အချက်အလက်များ ခလုတ်"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ဖုန်း"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS စာတိုစနစ်"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"အဆက်အသွယ်များ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ပြက္ခဒိန်"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"အနီးတစ်ဝိုက်ရှိ စက်များ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ဓာတ်ပုံနှင့် မီဒီယာများ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"အကြောင်းကြားချက်များ"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"အက်ပ်များ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"သင့်ဖုန်းနံပါတ်နှင့် ကွန်ရက်အချက်အလက်ကို သုံးနိုင်သည်။ ဖုန်းခေါ်ဆိုခြင်းနှင့် VoIP၊ အသံမေးလ်၊ ခေါ်ဆိုမှု တစ်ဆင့်ပြန်လွှဲခြင်းနှင့် ခေါ်ဆိုမှတ်တမ်းများ တည်းဖြတ်ခြင်းတို့အတွက် လိုအပ်သည်"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"အဆက်အသွယ် စာရင်းကို ဖတ်နိုင်၊ ပြုလုပ်နိုင် (သို့) တည်းဖြတ်နိုင်သည့်ပြင် သင့်စက်တွင်သုံးသော အကောင့်အားလုံး၏စာရင်းကို သုံးနိုင်သည်"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"အဆက်အသွယ်၊ မက်ဆေ့ဂျ်နှင့် ဓာတ်ပုံကဲ့သို့ အချက်အလက်များအပါအဝင် အကြောင်းကြားချက်အားလုံးကို ဖတ်နိုင်သည်"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"သင့်ဖုန်းရှိအက်ပ်များကို တိုက်ရိုက်ဖွင့်နိုင်သည်"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 6df06c1..01f4d32 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Tillat at &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; bruker &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klokke"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Velg <xliff:g id="PROFILE_NAME">%1$s</xliff:g> som skal administreres av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Denne appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å samhandle med varslene dine og får tilgang til tillatelser for telefon, SMS, kontakter, kalender, samtalelogger og enheter i nærheten."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apper"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Strøm appene på telefonen"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å samhandle med varslene dine og har tilgang til tillatelsene for telefon, SMS, kontakter, kalender, samtalelogger og enheter i nærheten."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Appen kreves for å administrere <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillatelse til å samhandle med disse tillatelsene:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjenester på flere enheter"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å strømme apper mellom enhetene dine, på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Gi &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; tilgang til denne informasjonen fra telefonen din"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Varsler"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kan lese alle varsler, inkludert informasjon som kontakter, meldinger og bilder"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjenester"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ber om tillatelse til å få tilgang til bilder, medier og varsler på telefonen din, på vegne av <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dette kan inkludere tilgang til mikrofon, kamera og posisjon samt andre sensitive tillatelser på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan når som helst endre disse tillatelsene i innstillingene på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Mer informasjon-knapp"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakter"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheter i nærheten"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Bilder og medier"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Varsler"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apper"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Kan se telefonnummeret ditt og nettverksinformasjon. Dette kreves for samtaler og VoIP, talepost, viderekobling av anrop og endring av samtalelogger"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kan lese, opprette eller endre kontaktlisten din og se listen over alle kontoene som brukes på enheten"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan lese alle varsler, inkludert informasjon som kontakter, meldinger og bilder"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Strøm appene på telefonen"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index fc22508..d7d3459 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -20,9 +20,10 @@
     <string name="confirmation_title" msgid="3785000297483688997">"आफ्नो &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; लाई &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; प्रयोग गर्ने अनुमति दिनुहोस्"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"घडी"</string>
     <string name="chooser_title" msgid="2262294130493605839">"आफूले &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रयोग गरी व्यवस्थापन गर्न चाहेको <xliff:g id="PROFILE_NAME">%1$s</xliff:g> चयन गर्नुहोस्"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"तपाईंको <xliff:g id="DEVICE_NAME">%1$s</xliff:g> व्यवस्थापन गर्न यो एपलाई अनुमति दिनु पर्ने हुन्छ। <xliff:g id="APP_NAME">%2$s</xliff:g> लाई तपाईंका सूचना हेर्ने र फोन, SMS, कन्ट्याक्ट, पात्रो, कल लग तथा नजिकैका डिभाइससम्बन्धी अनुमतिहरू हेर्ने तथा प्रयोग गर्ने अनुमति दिइने छ।"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"एपहरू"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"आफ्नो फोनका एपहरू प्रयोग गर्नुहोस्"</string>
+    <!-- no translation found for summary_watch (4085794790142204006) -->
+    <skip />
+    <!-- no translation found for summary_watch_single_device (1523091550243476756) -->
+    <skip />
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"क्रस-डिभाइस सेवाहरू"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंका कुनै एउटा डिभाइसबाट अर्को डिभाइसमा एप स्ट्रिम गर्ने अनुमति माग्दै छ"</string>
@@ -30,10 +31,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; लाई तपाईंको फोनमा भएको यो जानकारी हेर्ने तथा प्रयोग गर्ने अनुमति दिनुहोस्"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका जानकारीसहित सबै सूचनाहरू पढ्न सक्छ"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> तपाईंको डिभाइस <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> को तर्फबाट तपाईंको फोनमा भएका फोटो, मिडिया र सूचनाहरू हेर्ने तथा प्रयोग गर्ने अनुमति माग्दै छ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"यन्त्र"</string>
@@ -45,4 +42,29 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;यसअन्तर्गत &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; का माइक्रोफोन, क्यामेरा र लोकेसन प्रयोग गर्ने अनुमतिका तथा अन्य संवेदनशील अनुमति समावेश हुन्छन्।&lt;/p&gt; &lt;p&gt;तपाईं &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; का सेटिङमा गई जुनसुकै बेला यी अनुमति परिवर्तन गर्न सक्नुहुन्छ।&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"एपको आइकन"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"थप जानकारी देखाउने बटन"</string>
+    <!-- no translation found for permission_phone (2661081078692784919) -->
+    <skip />
+    <!-- no translation found for permission_sms (6337141296535774786) -->
+    <skip />
+    <!-- no translation found for permission_contacts (3858319347208004438) -->
+    <skip />
+    <!-- no translation found for permission_calendar (6805668388691290395) -->
+    <skip />
+    <!-- no translation found for permission_nearby_devices (7530973297737123481) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"फोटो र मिडिया"</string>
+    <string name="permission_notification" msgid="693762568127741203">"सूचनाहरू"</string>
+    <!-- no translation found for permission_app_streaming (6009695219091526422) -->
+    <skip />
+    <!-- no translation found for permission_phone_summary (6154198036705702389) -->
+    <skip />
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <!-- no translation found for permission_contacts_summary (7850901746005070792) -->
+    <skip />
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"कन्ट्याक्ट, म्यासेज र फोटोलगायतका जानकारीसहित सबै सूचनाहरू पढ्न सक्छ"</string>
+    <!-- no translation found for permission_app_streaming_summary (606923325679670624) -->
+    <skip />
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 9c7cc3c..28366f6 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot je &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"horloge"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Een <xliff:g id="PROFILE_NAME">%1$s</xliff:g> kiezen om te beheren met &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Deze app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot rechten voor Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Stream de apps van je telefoon"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"De app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> kan interactie hebben met je meldingen en toegang krijgen tot rechten voor Telefoon, Sms, Contacten, Agenda, Gesprekslijsten en Apparaten in de buurt."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"De app is vereist om je <xliff:g id="DEVICE_NAME">%1$s</xliff:g> te beheren. <xliff:g id="APP_NAME">%2$s</xliff:g> heeft toestemming om interactie te hebben met de volgende rechten:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device-services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toestemming om apps te streamen tussen je apparaten"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; toegang geven tot deze informatie op je telefoon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> vraagt namens jouw <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> toegang tot de foto\'s, media en meldingen van je telefoon"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"apparaat"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Dit kan toegang tot de microfoon, camera en je locatie en andere gevoelige rechten op je &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; omvatten.&lt;/p&gt; &lt;p&gt;Je kunt deze rechten op elk moment wijzigen in je Instellingen op de <xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"App-icoon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Knop Meer informatie"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefoon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Sms"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contacten"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Agenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Apparaten in de buurt"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foto\'s en media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Meldingen"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Heeft toegang tot je telefoonnummer en netwerkgegevens. Vereist voor bellen en VoIP, voicemail, gesprek omleiden en gesprekslijsten bewerken."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kan je contactenlijst lezen, maken of bewerken, en heeft toegang tot de contactenlijst voor alle accounts die op je apparaat worden gebruikt."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan alle meldingen lezen, waaronder informatie zoals contacten, berichten en foto\'s"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Stream de apps van je telefoon"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index e567806..5f7f52e 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"ଆପଣଙ୍କ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;କୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ୱାଚ୍"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ଦ୍ୱାରା ପରିଚାଳିତ ହେବା ପାଇଁ ଏକ <xliff:g id="PROFILE_NAME">%1$s</xliff:g>କୁ ବାଛନ୍ତୁ"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଏହି ଆପ ଆବଶ୍ୟକ। ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କ ଫୋନ, SMS, ଯୋଗାଯୋଗ, କ୍ୟାଲେଣ୍ଡର, କଲ ଲଗ ଏବଂ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ଆପ୍ସ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଆପ ଆବଶ୍ୟକ। ଆପଣଙ୍କ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ଏବଂ ଆପଣଙ୍କର ଫୋନ, SMS, କଣ୍ଟାକ୍ଟ, କେଲେଣ୍ଡର, କଲ ଲଗ ଓ ଆଖପାଖର ଡିଭାଇସ ଅନୁମତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ।"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ଆପଣଙ୍କ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>କୁ ପରିଚାଳନା କରିବା ପାଇଁ ଆପ ଆବଶ୍ୟକ। ଏହି ଅନୁମତିଗୁଡ଼ିକ ସହ ଇଣ୍ଟରାକ୍ଟ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%2$s</xliff:g>କୁ ଅନୁମତି ଦିଆଯିବ:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"କ୍ରସ-ଡିଭାଇସ ସେବାଗୁଡ଼ିକ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"ଆପଣଙ୍କ ଡିଭାଇସଗୁଡ଼ିକ ମଧ୍ୟରେ ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"ଆପଣଙ୍କ ଫୋନରୁ ଏହି ସୂଚନାକୁ ଆକ୍ସେସ କରିବା ପାଇଁ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;କୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"ଯୋଗାଯୋଗ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ିପାରିବ"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ସେବାଗୁଡ଼ିକ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"ଆପଣଙ୍କ ଫୋନର ଫଟୋ, ମିଡିଆ ଏବଂ ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକୁ ଆକ୍ସେସ କରିବା ପାଇଁ <xliff:g id="APP_NAME">%1$s</xliff:g> ଆପଣଙ୍କର <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ତରଫରୁ ଅନୁମତି ପାଇଁ ଅନୁରୋଧ କରୁଛି"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ଡିଭାଇସ୍"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ଏହା &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;ରେ ମାଇକ୍ରୋଫୋନ, କ୍ୟାମେରା ଏବଂ ଲୋକେସନ ଆକ୍ସେସ ଓ ଅନ୍ୟ ସମ୍ବେଦନଶୀଳ ଅନୁମତିଗୁଡ଼ିକୁ ଅନ୍ତର୍ଭୁକ୍ତ କରିପାରେ।&lt;/p&gt; &lt;p&gt;ଆପଣ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;ରେ ଯେ କୌଣସି ସମୟରେ ଆପଣଙ୍କ ସେଟିଂସରେ ଏହି ଅନୁମତିଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ଆପ ଆଇକନ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ଅଧିକ ସୂଚନା ବଟନ"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ଫୋନ"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"କଣ୍ଟାକ୍ଟଗୁଡ଼ିକ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"କେଲେଣ୍ଡର"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ଆଖପାଖର ଡିଭାଇସଗୁଡ଼ିକ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ଫଟୋ ଏବଂ ମିଡିଆ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ଆପ୍ସ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"ଆପଣଙ୍କ ଫୋନ ନମ୍ବର ଏବଂ ନେଟୱାର୍କ ସୂଚନା ଆକ୍ସେସ କରିପାରିବେ।କଲ କରିବା ଓ VoIP, ଭଏସମେଲ, କଲ ଡାଇରେକ୍ଟ ଏବଂ କଲ ଲଗକୁ ଏଡିଟ କରିବା ପାଇଁ ଆବଶ୍ୟକ"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"ଆପଣଙ୍କ କଣ୍ଟାକ୍ଟ ତାଲିକା ପଢ଼ିପାରିବେ, ତିଆରି କିମ୍ବା ଏଡିଟ କରିପାରିବେ ତଥା ଆପଣଙ୍କ ଡିଭାଇସରେ ବ୍ୟବହାର କରାଯାଇଥିବା ସମସ୍ତ ଆକାଉଣ୍ଟର ତାଲିକାକୁ ଆକ୍ସେସ କରିପାରିବେ"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"ଯୋଗାଯୋଗ, ମେସେଜ ଏବଂ ଫଟୋଗୁଡ଼ିକ ପରି ସୂଚନା ସମେତ ସମସ୍ତ ବିଜ୍ଞପ୍ତିକୁ ପଢ଼ିପାରିବ"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ଆପଣଙ୍କ ଫୋନର ଆପ୍ସକୁ ଷ୍ଟ୍ରିମ କରନ୍ତୁ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index dba72eb..4d9b8d3 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ਸਮਾਰਟ-ਵਾਚ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤੇ ਜਾਣ ਲਈ <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ਚੁਣੋ"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਇਹ ਐਪ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਕੈਲੰਡਰ, ਕਾਲ ਲੌਗਾਂ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ਐਪਾਂ"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ਇਹ ਐਪ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਤੁਹਾਡੀਆਂ ਸੂਚਨਾਵਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਅਤੇ ਤੁਹਾਡੇ ਫ਼ੋਨ, SMS, ਸੰਪਰਕਾਂ, ਕੈਲੰਡਰ, ਕਾਲ ਲੌਗਾਂ ਅਤੇ ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸਾਂ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ।"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ਇਹ ਐਪ ਤੁਹਾਡੇ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ। <xliff:g id="APP_NAME">%2$s</xliff:g> ਨੂੰ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਨਾਲ ਅੰਤਰਕਿਰਿਆ ਕਰਨ ਦੀ ਆਗਿਆ ਹੋਵੇਗੀ:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"ਕ੍ਰਾਸ-ਡੀਵਾਈਸ ਸੇਵਾਵਾਂ"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਡੀਵਾਈਸਾਂ ਵਿਚਕਾਰ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ਨੂੰ ਤੁਹਾਡੇ ਫ਼ੋਨ ਤੋਂ ਇਸ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿਓ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"ਤੁਸੀਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹ ਸਕਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play ਸੇਵਾਵਾਂ"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਤੁਹਾਡੇ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> ਦੀ ਤਰਫ਼ੋਂ ਤੁਹਾਡੇ ਫ਼ੋਨ ਦੀਆਂ ਫ਼ੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਸੂਚਨਾਵਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮੰਗ ਰਹੀ ਹੈ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"ਡੀਵਾਈਸ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;ਇਸ ਵਿੱਚ ਮਾਈਕ੍ਰੋਫ਼ੋਨ, ਕੈਮਰਾ, ਟਿਕਾਣਾ ਪਹੁੰਚ ਅਤੇ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਹੋਰ ਸੰਵੇਦਨਸ਼ੀਲ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਸੰਬੰਧੀ ਇਜਾਜ਼ਤਾਂ ਸ਼ਾਮਲ ਹੋ ਸਕਦੀਆਂ ਹਨ।&lt;/p&gt; &lt;p&gt;ਤੁਸੀਂ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਆਪਣੀਆਂ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ ਕਦੇ ਵੀ ਇਨ੍ਹਾਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ਐਪ ਪ੍ਰਤੀਕ"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ਹੋਰ ਜਾਣਕਾਰੀ ਬਟਨ"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ਫ਼ੋਨ"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"ਸੰਪਰਕ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ਕੈਲੰਡਰ"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"ਨਜ਼ਦੀਕੀ ਡੀਵਾਈਸ"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ਫ਼ੋਟੋਆਂ ਅਤੇ ਮੀਡੀਆ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"ਸੂਚਨਾਵਾਂ"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ਐਪਾਂ"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"ਤੁਹਾਡੇ ਫ਼ੋਨ ਨੰਬਰ ਅਤੇ ਨੈੱਟਵਰਕ ਜਾਣਕਾਰੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ। ਇਹ ਕਾਲਾਂ ਅਤੇ VoIP, ਵੌਇਸਮੇਲ, ਕਾਲ ਨੂੰ ਰੀਡਾਇਰੈਕਟ ਕਰਨ ਅਤੇ ਕਾਲ ਲੌਗਾਂ ਦਾ ਸੰਪਾਦਨ ਕਰਨ ਲਈ ਲੋੜੀਂਦੀ ਹੈ"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"ਤੁਹਾਡੀ ਸੰਪਰਕ ਸੂਚੀ ਨੂੰ ਪੜ੍ਹ, ਬਣਾ ਸਕਦੀ ਹੈ ਜਾਂ ਉਸਦਾ ਸੰਪਾਦਨ ਕਰ ਸਕਦੀ ਹੈ ਅਤੇ ਇਸ ਤੋਂ ਇਲਾਵਾ ਤੁਹਾਡੇ ਡੀਵਾਈਸ \'ਤੇ ਵਰਤੇ ਗਏ ਸਾਰੇ ਖਾਤਿਆਂ ਦੀ ਸੂਚੀ ਤੱਕ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"ਤੁਸੀਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਪੜ੍ਹ ਸਕਦੇ ਹੋ, ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਸੰਪਰਕਾਂ, ਸੁਨੇਹਿਆਂ ਅਤੇ ਫ਼ੋਟੋਆਂ ਵਰਗੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਹੁੰਦੀ ਹੈ"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ਆਪਣੇ ਫ਼ੋਨ ਦੀਆਂ ਐਪਾਂ ਨੂੰ ਸਟ੍ਰੀਮ ਕਰੋ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index a632026..2c7a038 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Zezwól na dostęp aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; do urządzenia &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"zegarek"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Wybierz profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, którym ma zarządzać aplikacja &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ta aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i urządzeń w pobliżu."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacje"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z powiadomień oraz uprawnień dotyczących telefonu, SMS-ów, kontaktów, kalendarza, rejestrów połączeń i Urządzeń w pobliżu."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikacja jest niezbędna do zarządzania profilem <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Aplikacja <xliff:g id="APP_NAME">%2$s</xliff:g> będzie mogła korzystać z tych powiadomień:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Zezwól urządzeniu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Usługi na innym urządzeniu"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące strumieniowego odtwarzania treści z aplikacji na innym urządzeniu"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Zezwól aplikacji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na dostęp do tych informacji na Twoim telefonie"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Może odczytywać wszystkie powiadomienia, w tym informacje takie jak kontakty, wiadomości i zdjęcia"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Usługi Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> prosi w imieniu urządzenia <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> o uprawnienia dotyczące dostępu do zdjęć, multimediów i powiadomień na telefonie"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"urządzenie"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Mogą one obejmować dane dostęp do Mikrofonu, Aparatu i lokalizacji oraz inne uprawnienia newralgiczne na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Możesz w dowolnym momencie zmienić uprawnienia na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacji"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Przycisk – więcej informacji"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS-y"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakty"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendarz"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Urządzenia w pobliżu"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Zdjęcia i multimedia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Powiadomienia"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacje"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Może korzystać z numeru telefonu i informacji o sieci. Wymagane przy nawiązywaniu połączeń, korzystaniu z VoIP oraz poczty głosowej, przekierowywaniu połączeń oraz edytowaniu rejestrów połączeń"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Może odczytywać, tworzyć i edytować listę kontaktów, jak również korzystać z listy wszystkich kont używanych na urządzeniu"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Może odczytywać wszystkie powiadomienia, w tym informacje takie jak kontakty, wiadomości i zdjęcia"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Odtwarzaj strumieniowo aplikacje z telefonu"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 60a4079..1a0d4d9 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Esse app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Fazer transmissão dos apps no seu smartphone"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"O app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"O app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com estas permissões:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Você pode mudar essas permissões a qualquer momento nas configurações do &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Smartphone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contatos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Agenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos por perto"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Acessar seu número de telefone e informações da rede. Necessária para chamadas e VoIP, correio de voz, redirecionamento de chamadas e edição de registros de chamadas"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Ler, criar ou editar sua lista de contatos, e também acessar a lista de contatos de todas as contas usadas no seu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Fazer transmissão dos apps no seu smartphone"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index 8eabaf8..5f3eeeb 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda ao seu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerido pela app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Esta app é necessária para gerir o seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com as suas notificações e aceder às autorizações do Telefone, SMS, Contactos, Calendário, Registos de chamadas e Dispositivos próximos."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Faça stream das apps do telemóvel"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"A app é necessária para gerir o seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com as suas notificações e aceder às autorizações do Telemóvel, SMS, Contactos, Calendário, Registos de chamadas e Dispositivos próximos."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"A app é necessária para gerir o seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. A app <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com estas autorizações:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permita que a app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer stream de apps entre os seus dispositivos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permita que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; aceda a estas informações do seu telemóvel"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contactos, mensagens e fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Serviços do Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> está a pedir autorização em nome do seu dispositivo <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para aceder às fotos, ao conteúdo multimédia e às notificações do seu telemóvel"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isto pode incluir o acesso ao microfone, câmara e localização, bem como a outras autorizações confidenciais no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Pode alterar estas autorizações em qualquer altura nas Definições do dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone da app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão Mais informações"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telemóvel"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contactos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendário"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos próximos"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e multimédia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Pode aceder ao seu número de telefone e informações da rede. É precisa para fazer chamadas e VoIP (voice over Internet Protocol), o correio de voz, redirecionar a chamada e editar registos de chamadas"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Pode ler, criar ou editar a nossa lista de contactos e aceder à lista de todas as contas usadas no seu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contactos, mensagens e fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Faça stream das apps do telemóvel"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 60a4079..1a0d4d9 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse o dispositivo &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relógio"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Escolha um <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para ser gerenciado pelo app &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Esse app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Apps"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Fazer transmissão dos apps no seu smartphone"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"O app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. O <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com suas notificações e acessar os apps Telefone, SMS, Contatos, Google Agenda, registros de chamadas e as permissões de dispositivos por perto."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"O app é necessário para gerenciar seu <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> vai poder interagir com estas permissões:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permitir que o app &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Serviços entre dispositivos"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para fazer streaming de apps entre seus dispositivos"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Autorizar que &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; acesse estas informações do smartphone"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play Services"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está pedindo permissão em nome do seu <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para acessar fotos, mídia e notificações do smartphone."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispositivo"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Isso pode incluir acesso a microfone, câmera e localização e outras permissões sensíveis no &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Você pode mudar essas permissões a qualquer momento nas configurações do &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ícone do app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Botão \"Mais informações\""</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Smartphone"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Contatos"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Agenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispositivos por perto"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotos e mídia"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificações"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Apps"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Acessar seu número de telefone e informações da rede. Necessária para chamadas e VoIP, correio de voz, redirecionamento de chamadas e edição de registros de chamadas"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Ler, criar ou editar sua lista de contatos, e também acessar a lista de contatos de todas as contas usadas no seu dispositivo"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Pode ler todas as notificações, incluindo informações como contatos, mensagens e fotos"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Fazer transmissão dos apps no seu smartphone"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index d1f949d..35c0888 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze dispozitivul &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ceas"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Alege un profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> pe care să îl gestioneze &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Această aplicație este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările și să acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplicații"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Să redea în stream aplicațiile telefonului"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplicația este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu notificările tale și să îți acceseze permisiunile pentru Telefon, SMS, Agendă, Calendar, Jurnale de apeluri și Dispozitive din apropiere."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplicația este necesară pentru a gestiona <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> va putea să interacționeze cu următoarele permisiuni:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Servicii pe mai multe dispozitive"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a reda în stream aplicații între dispozitivele tale"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Permite ca &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; să acceseze aceste informații de pe telefon"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Notificări"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Poate să citească toate notificările, inclusiv informații cum ar fi agenda, mesajele și fotografiile"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Servicii Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> solicită permisiunea pentru <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> de a accesa fotografiile, conținutul media și notificările de pe telefon"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"dispozitiv"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Aici pot fi incluse accesul la microfon, la camera foto, la locație și alte permisiuni de accesare a informațiilor sensibile de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Poți modifica oricând aceste permisiuni din Setările de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Pictograma aplicației"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Butonul Mai multe informații"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Agendă"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Dispozitive din apropiere"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografii și media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Notificări"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplicații"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Poate să acceseze numărul tău de telefon și informațiile despre rețea. Permisiunea este necesară pentru inițierea apelurilor și VoIP, mesaje vocale, redirecționarea apelurilor și editarea jurnalelor de apeluri"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Poate să citească, să creeze sau să editeze agenda, precum și să acceseze lista tuturor conturilor folosite pe dispozitiv"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Poate să citească toate notificările, inclusiv informații cum ar fi agenda, mesajele și fotografiile"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Să redea în stream aplicațiile telefonului"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index f519239..612601a 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ к устройству &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"часы"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Выберите устройство (<xliff:g id="PROFILE_NAME">%1$s</xliff:g>), которым будет управлять приложение &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" получит доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты, календарь, список вызовов и устройства поблизости."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Приложения"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Трансляция приложений с телефона."</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" получит доступ к уведомлениям, а также следующие разрешения: телефон, SMS, контакты, календарь, список вызовов и устройства поблизости."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Это приложение необходимо для управления устройством \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Приложение \"<xliff:g id="APP_NAME">%2$s</xliff:g>\" получит следующие разрешения:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервисы стриминга приложений"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы транслировать приложения между вашими устройствами."</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Разрешите приложению &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; получать эту информацию с вашего телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Сервисы Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" запрашивает разрешение от имени вашего устройства <xliff:g id="DEVICE_TYPE">%2$s</xliff:g>, чтобы получить доступ к фотографиям, медиаконтенту и уведомлениям на телефоне."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"устройство"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Сюда может входить доступ к микрофону, камере и данным о местоположении, а также другие разрешения на доступ к конфиденциальной информации на устройстве &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Вы можете в любое время изменить разрешения в настройках устройства &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Значок приложения"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка информации"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контакты"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календарь"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Устройства поблизости"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Фотографии и медиафайлы"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Уведомления"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Приложения"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Доступ к номеру телефона и информации о сети. Это разрешение необходимо, чтобы совершать обычные и VoIP-звонки, отправлять голосовые сообщения, перенаправлять вызовы и редактировать списки вызовов."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Возможность читать, создавать и редактировать список контактов, а также получать доступ к списку всех аккаунтов на вашем устройстве."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Чтение всех уведомлений, в том числе сведений о контактах, сообщениях и фотографиях."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Трансляция приложений с телефона."</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index bf5361e..0743dba 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; කළමනාකරණය කිරීමට ඉඩ දෙන්න"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ඔරලෝසුව"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; මගින් කළමනාකරණය කරනු ලැබීමට <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ක් තෝරන්න"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"මෙම යෙදුමට ඔබගේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනාකරණය කිරීමට අවශ්‍යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> ඔබගේ දැනුම්දීම් සමඟ අන්තර්ක්‍රියා කිරීමට සහ ඔබගේ දුරකථනය, SMS, සම්බන්ධතා, දින දර්ශනය, ඇමතුම් ලොග සහ අවට උපාංග අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙනු ඇත."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"යෙදුම්"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"ඔබගේ දුරකථනයේ යෙදුම් ප්‍රවාහ කරන්න"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනා කිරීමට මෙම යෙදුම අවශ්‍යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> ඔබේ දැනුම්දීම් සමග අන්තර්ක්‍රියා කිරීමට සහ ඔබේ දුරකථනය, කෙටිපණිවුඩය, සම්බන්‍ධතා, දිනදර්ශනය, ඇමතුම් ලොග සහ අවට උපාංග අවසර වෙත ප්‍රවේශ වීමට ඉඩ දෙයි."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ඔබේ <xliff:g id="DEVICE_NAME">%1$s</xliff:g> කළමනා කිරීමට මෙම යෙදුම අවශ්‍යයි. <xliff:g id="APP_NAME">%2$s</xliff:g> හට මෙම අවසර සමග අන්තර්ක්‍රියා කිරීමට අවසර දෙනු ලැබේ:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"හරස්-උපාංග සේවා"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ උපාංග අතර යෙදුම් ප්‍රවාහ කිරීමට අවසරය ඉල්ලමින් සිටියි"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; හට ඔබගේ දුරකථනයෙන් මෙම තොරතුරුවලට ප්‍රවේශ වීමට ඉඩ දෙන්න"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"සම්බන්ධතා, පණිවිඩ සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව සියලු දැනුම්දීම් කියවිය හැකිය"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්‍ය"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play සේවා"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ඔබගේ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> වෙනුවෙන් ඔබගේ දුරකථනයෙහි ඡායාරූප, මාධ්‍ය සහ දැනුම්දීම් වෙත ප්‍රවේශ වීමට අවසරය ඉල්ලමින් සිටියි"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"උපාංගය"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;මෙයට මයික්‍රෆෝනය, කැමරාව සහ ස්ථාන ප්‍රවේශය සහ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; හි අනෙකුත් සංවේදී අවසර ඇතුළත් විය හැකිය.&lt;/p&gt; &lt;p&gt;ඔබට ඔබගේ සැකසීම් තුළ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; හිදී ඕනෑම වේලාවක මෙම අවසර වෙනස් කළ හැකිය.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"යෙදුම් නිරූපකය"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"වැඩිදුර තොරතුරු බොත්තම"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"දුරකථනය"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"කෙටිපණිවුඩය"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"සම්බන්‍ධතා"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"දිනදර්ශනය"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"අවට උපාංග"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ඡායාරූප සහ මාධ්‍ය"</string>
+    <string name="permission_notification" msgid="693762568127741203">"දැනුම්දීම්"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"යෙදුම්"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"ඔබේ දුරකථන අංකයට සහ ජාල තොරතුරු වෙත ප්‍රවේශ විය හැක. ඇමතුම් සහ VoIP, හඬ තැපැල්, ඇමතුම් ප්‍රතියෝමුව, සහ ඇමතුම් සටහන් සංස්කරණය සඳහා අවශ්‍යයි."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"අපගේ සම්බන්‍ධතා ලැයිස්තුව කියවීමට, සෑදීමට, හෝ සංස්කරණ කිරීමට මෙන් ම ඔබේ උපාංගය මත භාවිත කරනු ලබන සියලුම ගිණුම් ලැයිස්තු වෙත ප්‍රවේශ වීමට හැකිය"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"සම්බන්ධතා, පණිවිඩ සහ ඡායාරූප වැනි තොරතුරු ඇතුළුව සියලු දැනුම්දීම් කියවිය හැකිය"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"ඔබේ දුරකථනයේ යෙදුම් ප්‍රවාහ කරන්න"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index ff19fa5..933c289 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k zariadeniu &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"hodinky"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Vyberte profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ktorý bude spravovať aplikácia &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Táto aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k povoleniam telefónu, SMS, kontaktov, kalendára, zoznamu hovorov a zariadení v okolí."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikácie"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streamovať aplikácie telefónu"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s vašimi upozorneniami a získa prístup k povoleniam telefónu, SMS, kontaktov, kalendára, zoznamu hovorov a zariadení v okolí."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikácia sa vyžaduje na správu zariadenia <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> bude môcť interagovať s týmito povoleniami:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Služby pre viacero zariadení"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na streamovanie aplikácií medzi vašimi zariadeniami v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Povoľte aplikácii &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; prístup k týmto informáciám z vášho telefónu"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Služby Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> vyžaduje povolenie na prístup k fotkám, médiám a upozorneniam vášho telefónu v mene tohto zariadenia (<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>)"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"zariadenie"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Môžu zahŕňať prístup k mikrofónu, kamere a polohe a ďalšie citlivé povolenia v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Tieto povolenia môžete kedykoľvek zmeniť v Nastaveniach v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikácie"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Tlačidlo Ďalšie informácie"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefón"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakty"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendár"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Zariadenia v okolí"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotky a médiá"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Upozornenia"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikácie"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Má prístup k vášmu telefónnemu číslu a informáciám o sieti. Vyžaduje sa na volanie a VoIP, fungovanie hlasovej schránky, presmerovanie hovorov a upravovanie zoznamu hovorov"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Môže čítať, vytvárať alebo upravovať náš zoznam kontaktov, ako aj získavať prístup k zoznamu všetkých účtov používaných vo vašom zariadení"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Môže čítať všetky upozornenia vrátane informácií, ako sú kontakty, správy a fotky"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streamovať aplikácie telefónu"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 14feef6f..676da68 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Aplikaciji &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dovolite dostop do naprave &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ura"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Izbira naprave <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, ki jo bo upravljala aplikacija &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bosta omogočena interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Koledar, Dnevniki klicev in Naprave v bližini."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacije"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Pretočno predvajanje aplikacij telefona"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bosta omogočeni interakcija z obvestili in uporaba dovoljenj Telefon, SMS, Stiki, Koledar, Dnevniki klicev in Naprave v bližini."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Ta aplikacija je potrebna za upravljanje naprave »<xliff:g id="DEVICE_NAME">%1$s</xliff:g>«. Aplikaciji <xliff:g id="APP_NAME">%2$s</xliff:g> bo omogočena interakcija s temi dovoljenji:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Storitve za zunanje naprave"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za pretočno predvajanje aplikacij v vaših napravah."</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Dovolite, da &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; dostopa do teh podatkov v vašem telefonu"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Storitve Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> v imenu naprave »<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>« zahteva dovoljenje za dostop do fotografij, predstavnosti in obvestil v telefonu."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"naprava"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;To lahko vključuje dostop do mikrofona, fotoaparata in lokacije ter druga občutljiva dovoljenja v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ta dovoljenja lahko kadar koli spremenite v nastavitvah v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona aplikacije"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Gumb za več informacij"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Stiki"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Koledar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Naprave v bližini"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografije in predstavnost"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Obvestila"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacije"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Lahko dostopa do telefonske številke in podatkov o omrežju. Obvezno za opravljanje klicev, uporabo storitve VoIP in glasovne pošte, preusmerjanje klicev in urejanje dnevnikov klicev."</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Lahko bere, ustvarja ali ureja seznam stikov in dostopa do seznama stikov vseh računov, uporabljenih v napravi."</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Lahko bere vsa obvestila, vključno s podatki, kot so stiki, sporočila in fotografije."</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Pretočno predvajanje aplikacij telefona"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index cefbff8..7bd86ce 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje te &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"ora inteligjente"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Zgjidh një profil <xliff:g id="PROFILE_NAME">%1$s</xliff:g> që do të menaxhohet nga &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ky aplikacion nevojitet për të menaxhuar profilin tënd të <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Kalendarit\", \"Evidencave të telefonatave\" dhe \"Pajisjeve në afërsi\"."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Aplikacionet"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Transmeto aplikacionet e telefonit tënd"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Aplikacioni nevojitet për të menaxhuar profilin tënd të \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me njoftimet e tua dhe të ketë qasje te lejet e \"Telefonit\", \"SMS-ve\", \"Kontakteve\", \"Kalendarit\", \"Evidencave të telefonatave\" dhe të \"Pajisjeve në afërsi\"."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Aplikacioni nevojitet për të menaxhuar profilin tënd të \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". <xliff:g id="APP_NAME">%2$s</xliff:g> do të lejohet të ndërveprojë me këto leje:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Shërbimet mes pajisjeve"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të transmetuar aplikacione ndërmjet pajisjeve të tua"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Lejo që &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; të ketë qasje në këtë informacion nga telefoni yt"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Mund të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Shërbimet e Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> po kërkon leje në emër të <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> për të marrë qasje te fotografitë, media dhe njoftimet e telefonit tënd"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"pajisja"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Kjo mund të përfshijë qasjen te \"Mikrofoni\", \"Kamera\", \"Vendndodhja\" dhe leje të tjera për informacione delikate në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&amp;gtTi mund t\'i ndryshosh këto leje në çdo kohë te \"Cilësimet\" në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ikona e aplikacionit"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Butoni \"Më shumë informacione\""</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefoni"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktet"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalendari"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Pajisjet në afërsi"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotografitë dhe media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Njoftimet"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Aplikacionet"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Mund të qaset te informacionet e numrit të telefonit dhe të rrjetit. Kërkohet për të bërë telefonata dhe VoIP, postë zanore, ridrejtim të telefonatës dhe modifikim të evidencave të telefonatave"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Mund të lexojë, të krijojë ose të modifikojë listën tënde të kontakteve si dhe të qaset në listën e të gjitha llogarive të përdorura në pajisjen tënde"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Mund të lexojë të gjitha njoftimet, duke përfshirë informacione si kontaktet, mesazhet dhe fotografitë"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Transmeto aplikacionet e telefonit tënd"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index 0d05e1a..73cf13d 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа уређају &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"сат"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Одаберите профил <xliff:g id="PROFILE_NAME">%1$s</xliff:g> којим ће управљати апликација &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Ова апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, календар, евиденције позива и уређаје у близини."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Апликације"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Стримујте апликације на телефону"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са обавештењима и приступ дозволама за телефон, SMS, контакте, календар, евиденције позива и уређаје у близини."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Апликација је потребна за управљање уређајем <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> ће добити дозволу за интеракцију са овим дозволама:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Услуге на више уређаја"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за стримовање апликација између уређаја"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Дозволите да &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; приступа овим информацијама са телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Може да чита сва обавештења, укључујући информације попут контаката, порука и слика"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play услуге"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> захтева дозволу у име уређаја <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> за приступ сликама, медијском садржају и обавештењима са телефона"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"уређај"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;То може да обухвата приступ микрофону, камери и локацији, као и другим осетљивим дозволама на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;У сваком тренутку можете да промените те дозволе у Подешавањима на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Икона апликације"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Дугме за више информација"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контакти"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календар"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Уређаји у близини"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Слике и медији"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Обавештења"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Апликације"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Може да приступа вашем броју телефона и информацијама о мрежи. Неопходно за упућивање позива и VoIP, говорну пошту, преусмеравање позива и измене евиденције позива"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Може да чита, креира или мења листу контаката, као и да приступа листи свих налога који се користе на вашем уређају"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Може да чита сва обавештења, укључујући информације попут контаката, порука и слика"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Стримујте апликације на телефону"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index e2799b5..ceb7e40 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Tillåt att &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; får åtkomst till din &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"klocka"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Välj en <xliff:g id="PROFILE_NAME">%1$s</xliff:g> för hantering av &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Kalender, Samtalsloggar och Enheter i närheten."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Appar"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Streama telefonens appar"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med dina aviseringar och får åtkomst till behörigheterna Telefon, Sms, Kontakter, Kalender, Samtalsloggar och Enheter i närheten."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Appen behövs för att hantera <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> får tillåtelse att interagera med följande behörigheter:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Tjänster för flera enheter"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att låta <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> streama appar mellan enheter"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Ge &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; åtkomstbehörighet till denna information på telefonen"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kan läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play-tjänster"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> begär behörighet att ge <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> åtkomst till foton, mediefiler och aviseringar på telefonen"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"enhet"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Det kan gälla behörighet till mikrofon, kamera och plats och åtkomstbehörighet till andra känsliga uppgifter på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Du kan när som helst ändra behörigheterna i inställningarna på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Appikon"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Knappen Mer information"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Sms"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontakter"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalender"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Enheter i närheten"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Foton och media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Aviseringar"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Appar"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Kan få åtkomst till ditt telefonnummer och din nätverksinformation. Krävs för att ringa samtal och VoIP-samtal, röstbrevlådan, omdirigering av samtal och redigering av samtalsloggar"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kan läsa, skapa eller redigera din kontaktlista samt få åtkomst till kontaktlistan för alla konton som används på enheten"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kan läsa alla aviseringar, inklusive information som kontakter, meddelanden och foton"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Streama telefonens appar"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 812b4df..856dab1 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yako"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saa"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Chagua <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ili idhibitiwe na &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Programu hii inahitajika ili udhibiti wasifu wako wa <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa zako za Simu, SMS, Anwani, Kalenda, Rekodi za nambari za simu na Vifaa vilivyo karibu."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Programu"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Tiririsha programu za simu yako"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kufikia arifa zako na kufikia ruhusa zako za Simu, SMS, Anwani, Kalenda, Rekodi za nambari za simu na Vifaa vilivyo karibu."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Programu hii inahitajika ili udhibiti <xliff:g id="DEVICE_NAME">%1$s</xliff:g> yako. <xliff:g id="APP_NAME">%2$s</xliff:g> itaruhusiwa kufikia ruhusa hizi:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Huduma za kifaa kilichounganishwa kwingine"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili itiririshe programu kati ya vifaa vyako"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Ruhusu &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifikie maelezo haya kutoka kwenye simu yako"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Arifa"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Inaweza kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile anwani, ujumbe na picha"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Huduma za Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Programu ya <xliff:g id="APP_NAME">%1$s</xliff:g> inaomba ruhusa kwa niaba ya <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yako ili ifikie picha, maudhui na arifa za simu yako"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"kifaa"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Hii huenda ikajumuisha ufikiaji wa Maikrofoni, Kamera na Mahali, pamoja na ruhusa nyingine nyeti kwenye &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Unaweza kubadilisha ruhusa hizi muda wowote katika Mipangilio yako kwenye &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Aikoni ya Programu"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Kitufe cha Maelezo Zaidi"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Simu"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Anwani"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Kalenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Vifaa vilivyo karibu"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Picha na maudhui"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Arifa"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Programu"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Inaweza kufikia nambari yako ya simu na maelezo ya mtandao. Inahitajika kwa ajili ya kupiga simu na VoIP, ujumbe wa sauti, uelekezaji wa simu kwingine na kubadilisha rekodi za nambari za simu"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Inaweza kusoma, kuunda au kubadilisha orodha yetu ya anwani na pia kufikia orodha ya akaunti zote zinazotumiwa kwenye kifaa chako"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Inaweza kusoma arifa zote, ikiwa ni pamoja na maelezo kama vile anwani, ujumbe na picha"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Tiririsha programu za simu yako"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index fca9e0a..e75b75e 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -20,9 +20,10 @@
     <string name="confirmation_title" msgid="3785000297483688997">"உங்கள் &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"வாட்ச்"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ஆப்ஸ் நிர்வகிக்கக்கூடிய <xliff:g id="PROFILE_NAME">%1$s</xliff:g> ஐத் தேர்ந்தெடுங்கள்"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"உங்கள் <xliff:g id="DEVICE_NAME">%1$s</xliff:g> சாதனத்தை நிர்வகிக்க இந்த ஆப்ஸ் தேவைப்படுகிறது. உங்கள் அறிவிப்புகளைப் பயன்படுத்துவதற்கான அனுமதியையும் மொபைல், மெசேஜ், தொடர்புகள், கேலெண்டர், அழைப்புப் பதிவுகள், அருகிலுள்ள சாதனங்கள் ஆகியவற்றின் அனுமதிகளுக்கான அணுகலையும் <xliff:g id="APP_NAME">%2$s</xliff:g> ஆப்ஸ் பெறும்."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ஆப்ஸ்"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"உங்கள் மொபைலின் ஆப்ஸை ஸ்ட்ரீம் செய்யலாம்"</string>
+    <!-- no translation found for summary_watch (4085794790142204006) -->
+    <skip />
+    <!-- no translation found for summary_watch_single_device (1523091550243476756) -->
+    <skip />
     <string name="title_app_streaming" msgid="2270331024626446950">"மொபைலில் உள்ள இந்தத் தகவல்களை அணுக, &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதிக்கவும்"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"பன்முக சாதன சேவைகள்"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"உங்கள் சாதனங்களுக்கு இடையே ஆப்ஸை ஸ்ட்ரீம் செய்ய உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் அனுமதியைக் கோருகிறது"</string>
@@ -30,10 +31,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"உங்கள் மொபைலிலிருந்து இந்தத் தகவலை அணுக &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ஆப்ஸை அனுமதியுங்கள்"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play சேவைகள்"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"உங்கள் மொபைலில் உள்ள படங்கள், மீடியா, அறிவிப்புகள் ஆகியவற்றை அணுக உங்கள் <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> சார்பாக <xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸ் அனுமதியைக் கோருகிறது"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"சாதனம்"</string>
@@ -45,4 +42,29 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; சாதனத்தில் உள்ள மைக்ரோஃபோன், கேமரா, இருப்பிட அணுகல், பாதுகாக்கவேண்டிய பிற தகவல்கள் ஆகியவற்றுக்கான அனுமதிகள் இதிலடங்கும்.&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; சாதனத்தில் உள்ள அமைப்புகளில் இந்த அனுமதிகளை எப்போது வேண்டுமானாலும் நீங்கள் மாற்றிக்கொள்ளலாம்."</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ஆப்ஸ் ஐகான்"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"கூடுதல் தகவல்கள் பட்டன்"</string>
+    <!-- no translation found for permission_phone (2661081078692784919) -->
+    <skip />
+    <!-- no translation found for permission_sms (6337141296535774786) -->
+    <skip />
+    <!-- no translation found for permission_contacts (3858319347208004438) -->
+    <skip />
+    <!-- no translation found for permission_calendar (6805668388691290395) -->
+    <skip />
+    <!-- no translation found for permission_nearby_devices (7530973297737123481) -->
+    <skip />
+    <string name="permission_storage" msgid="6831099350839392343">"படங்கள் மற்றும் மீடியா"</string>
+    <string name="permission_notification" msgid="693762568127741203">"அறிவிப்புகள்"</string>
+    <!-- no translation found for permission_app_streaming (6009695219091526422) -->
+    <skip />
+    <!-- no translation found for permission_phone_summary (6154198036705702389) -->
+    <skip />
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <!-- no translation found for permission_contacts_summary (7850901746005070792) -->
+    <skip />
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"தொடர்புகள், மெசேஜ்கள், படங்கள் போன்ற தகவல்கள் உட்பட அனைத்து அறிவிப்புகளையும் படிக்க முடியும்"</string>
+    <!-- no translation found for permission_app_streaming_summary (606923325679670624) -->
+    <skip />
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index c318796..3a09d68 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"మీ &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ను యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;ను అనుమతించండి"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"వాచ్"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; ద్వారా మేనేజ్ చేయబడటానికి ఒక <xliff:g id="PROFILE_NAME">%1$s</xliff:g>ను ఎంచుకోండి"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి అలాగే మీ ఫోన్, SMS, కాంటాక్ట్‌లు, Calendar కాల్ లాగ్‌లు, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"యాప్‌లు"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"మీ ఫోన్ యాప్‌లను స్ట్రీమ్ చేయండి"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>‌ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. మీ నోటిఫికేషన్‌లతో ఇంటరాక్ట్ అవ్వడానికి, అలాగే మీ ఫోన్, SMS, కాంటాక్ట్‌లు, క్యాలెండర్, కాల్ లాగ్‌లు, సమీపంలోని పరికరాల అనుమతులను యాక్సెస్ చేయడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"మీ <xliff:g id="DEVICE_NAME">%1$s</xliff:g>‌ను మేనేజ్ చేయడానికి ఈ యాప్ అవసరం. ఈ అనుమతులతో ఇంటరాక్ట్ అవ్వడానికి <xliff:g id="APP_NAME">%2$s</xliff:g> అనుమతించబడుతుంది:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cross-device services"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"మీ పరికరాల మధ్య యాప్‌లను స్ట్రీమ్ చేయడానికి <xliff:g id="APP_NAME">%1$s</xliff:g> మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"మీ ఫోన్ నుండి ఈ సమాచారాన్ని యాక్సెస్ చేయడానికి &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; యాప్‌ను అనుమతించండి"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్‌లు"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"కాంటాక్ట్‌లు, మెసేజ్‌లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్‌లను చదవగలదు"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play సర్వీసులు"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> మీ ఫోన్‌లోని ఫోటోలను, మీడియాను, ఇంకా నోటిఫికేషన్‌లను యాక్సెస్ చేయడానికి మీ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> తరఫున అనుమతిని రిక్వెస్ట్ చేస్తోంది"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"పరికరం"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;లో మైక్రోఫోన్, కెమెరా, లొకేషన్ యాక్సెస్, ఇంకా ఇతర గోప్యమైన సమాచార యాక్సెస్ అనుమతులు ఇందులో ఉండవచ్చు.&lt;/p&gt; &lt;p&gt;మీరు &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;లో మీ సెట్టింగ్‌లలో ఎప్పుడైనా ఈ అనుమతులను మార్చవచ్చు.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"యాప్ చిహ్నం"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"మరింత సమాచారం బటన్"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"ఫోన్"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"కాంటాక్ట్‌లు"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"క్యాలెండర్"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"సమీపంలోని పరికరాలు"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"ఫోటోలు, మీడియా"</string>
+    <string name="permission_notification" msgid="693762568127741203">"నోటిఫికేషన్‌లు"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"యాప్‌లు"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"మీ ఫోన్ నంబర్, ఇంకా నెట్‌వర్క్ సమాచారాన్ని యాక్సెస్ చేయగలదు. కాల్స్ చేయడానికి, VoIP కాల్స్ చేయడానికి, వాయిస్ మెయిల్‌కు, కాల్ మళ్లింపునకు, ఇంకా కాల్ లాగ్‌లను ఎడిట్ చేయడానికి ఇది అవసరం"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"మీ కాంటాక్ట్ లిస్ట్‌ను చదవడం, క్రియేట్ చేయడం, లేదా ఎడిట్ చేయడంతో పాటు మీ పరికరంలో ఉపయోగించబడే ఖాతాలన్నింటి లిస్ట్‌ను యాక్సెస్ కూడా చేయగలదు"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"కాంటాక్ట్‌లు, మెసేజ్‌లు, ఫోటోల వంటి సమాచారంతో సహా అన్ని నోటిఫికేషన్‌లను చదవగలదు"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"మీ ఫోన్‌లోని యాప్‌లను స్ట్రీమ్ చేయండి"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index 7c31a21..522c29f 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึง &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ของคุณ"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"นาฬิกา"</string>
     <string name="chooser_title" msgid="2262294130493605839">"เลือก<xliff:g id="PROFILE_NAME">%1$s</xliff:g>ที่จะให้มีการจัดการโดย &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ปฏิทิน, บันทึกการโทร และอุปกรณ์ที่อยู่ใกล้เคียง"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"แอป"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"สตรีมแอปของโทรศัพท์คุณ"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับการแจ้งเตือนและได้รับสิทธิ์เข้าถึงโทรศัพท์, SMS, รายชื่อติดต่อ, ปฏิทิน, บันทึกการโทร และอุปกรณ์ที่อยู่ใกล้เคียง"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"ต้องใช้แอปนี้ในการจัดการ<xliff:g id="DEVICE_NAME">%1$s</xliff:g> <xliff:g id="APP_NAME">%2$s</xliff:g> จะได้รับอนุญาตให้โต้ตอบกับสิทธิ์เหล่านี้"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"บริการหลายอุปกรณ์"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อสตรีมแอประหว่างอุปกรณ์ต่างๆ ของคุณ"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"อนุญาตให้ &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; เข้าถึงข้อมูลนี้จากโทรศัพท์ของคุณ"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"บริการ Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังขอสิทธิ์ในนามของ <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> เพื่อเข้าถึงรูปภาพ สื่อ และการแจ้งเตือนในโทรศัพท์ของคุณ"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"อุปกรณ์"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;โดยอาจรวมถึงสิทธิ์เข้าถึงไมโครโฟน กล้อง และตำแหน่ง ตลอดจนสิทธิ์ที่มีความละเอียดอ่อนอื่นๆ ใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;คุณเปลี่ยนแปลงสิทธิ์เหล่านี้ได้ทุกเมื่อในการตั้งค่าใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ไอคอนแอป"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"ปุ่มข้อมูลเพิ่มเติม"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"โทรศัพท์"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"รายชื่อติดต่อ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"ปฏิทิน"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"อุปกรณ์ที่อยู่ใกล้เคียง"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"รูปภาพและสื่อ"</string>
+    <string name="permission_notification" msgid="693762568127741203">"การแจ้งเตือน"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"แอป"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"สามารถเข้าถึงหมายเลขโทรศัพท์และข้อมูลเครือข่ายของคุณ จำเป็นสำหรับการโทรและ VoIP, ข้อความเสียง, การเปลี่ยนเส้นทางการโทร และการแก้ไขบันทึกการโทร"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"สามารถอ่าน สร้าง หรือแก้ไขข้อมูลรายชื่อติดต่อของเรา รวมทั้งเข้าถึงข้อมูลรายชื่อติดต่อของทุกบัญชีที่ใช้ในอุปกรณ์ของคุณ"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"สามารถอ่านการแจ้งเตือนทั้งหมด รวมถึงข้อมูลอย่างรายชื่อติดต่อ ข้อความ และรูปภาพ"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"สตรีมแอปของโทรศัพท์คุณ"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index e86bc41..79c23aa 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang iyong &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"relo"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Pumili ng <xliff:g id="PROFILE_NAME">%1$s</xliff:g> para pamahalaan ng &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Kailangan ang app na ito para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga notification mo at i-access ang iyong pahintulot sa Telepono, SMS, Mga Contact, Kalendaryo, Log ng mga tawag, at Mga kalapit na device."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Mga App"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"I-stream ang mga app ng iyong telepono"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Kailangan ang app para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga notification mo at i-access ang iyong pahintulot sa Telepono, SMS, Mga Contact, Kalendaryo, Log ng mga tawag, at Mga kalapit na device."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Kailangan ang app para mapamahalaan ang iyong <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Papayagan ang <xliff:g id="APP_NAME">%2$s</xliff:g> na makipag-ugnayan sa mga pahintulot na ito:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyong ito sa iyong telepono"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Mga cross-device na serbisyo"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para mag-stream ng mga app sa pagitan ng mga device mo"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Payagan ang &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; na i-access ang impormasyon sa iyong telepono"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Magbasa ng lahat ng notification, kabilang ang impormasyon gaya ng mga contact, mensahe, at larawan"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Mga serbisyo ng Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Ang <xliff:g id="APP_NAME">%1$s</xliff:g> ay humihiling ng pahintulot sa ngalan ng iyong <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> para i-access ang mga larawan, media, at notification ng telepono mo"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"device"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Posibleng kabilang dito ang access sa Mikropono, Camera, at Lokasyon, at iba pang pahintulot sa sensitibong impormasyon sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Puwede mong baguhin ang mga pahintulot na ito anumang oras sa iyong Mga Setting sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Icon ng App"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Button ng Dagdag Impormasyon"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telepono"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Mga Contact"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Calendar"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Mga kalapit na device"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Mga larawan at media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Mga Notification"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Mga App"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Naa-access ang iyong numero ng telepono at impormasyon ng network. Kinakailangan para sa mga pagtawag at VoIP, voicemail, pag-redirect ng tawag, at pag-edit ng mga log ng tawag"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Nakaka-read, nakakagawa, o nakakapag-edit ng aming listahan ng contact, pati na rin nakaka-access ng listahan ng lahat ng account na ginamit sa iyong device"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Magbasa ng lahat ng notification, kabilang ang impormasyon gaya ng mga contact, mensahe, at larawan"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"I-stream ang mga app ng iyong telepono"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 756bcbb..ea4e20a 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazınıza erişmesi için &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasına izin verin"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"saat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; tarafından yönetilecek bir <xliff:g id="PROFILE_NAME">%1$s</xliff:g> seçin"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Takvim, Arama kayıtları ve Yakındaki cihazlar izinlerinize erişmesine izin verilir."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Uygulamalar"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Telefonunuzun uygulamalarını yayınlama"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> adlı uygulamanın bildirimlerinizle etkileşimde bulunup Telefon, SMS, Kişiler, Takvim, Arama kayıtları ve Yakındaki cihazlar izinlerinize erişmesine izin verilir."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Bu uygulama, <xliff:g id="DEVICE_NAME">%1$s</xliff:g> cihazınızın yönetilmesi için gereklidir. <xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasının şu izinlerle etkileşime girmesine izin verilir:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Cihazlar arası hizmetler"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g>, cihazlarınız arasında uygulama akışı gerçekleştirmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; uygulamasının, telefonunuzdaki bu bilgilere erişmesine izin verin"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuyabilir"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play hizmetleri"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g>, telefonunuzdaki fotoğraf, medya ve bildirimlere erişmek için <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> cihazınız adına izin istiyor"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"cihaz"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Mikrofon, Kamera ve Konum erişiminin yanı sıra &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; cihazındaki diğer hassas bilgilere erişim izinleri de bu kapsamda olabilir.&lt;/p&gt; &lt;p&gt;Bu izinleri istediğiniz zaman &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; cihazındaki Ayarlar bölümünden değiştirebilirsiniz.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Uygulama Simgesi"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Daha Fazla Bilgi Düğmesi"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kişiler"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Takvim"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Yakındaki cihazlar"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Fotoğraflar ve medya"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirimler"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Uygulamalar"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Telefon numaranıza ve ağ bilgilerinize erişebilir. Arama, VoIP, sesli mesaj, arama yönlendirme gibi işlemleri gerçekleştirmek ve arama kayıtlarını düzenlemek için gereklidir"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kişi listesini okuyabilir, oluşturabilir veya düzenleyebilir, ayrıca cihazınızda kullanılan tüm hesapların listesine erişebilir"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Kişiler, mesajlar ve fotoğraflar da dahil olmak üzere tüm bildirimleri okuyabilir"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefonunuzun uygulamalarını yayınlama"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index cc9f6b5..79b03ea 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Надати додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до пристрою &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"годинник"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Виберіть <xliff:g id="PROFILE_NAME">%1$s</xliff:g>, яким керуватиме додаток &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Цей додаток потрібен, щоб керувати пристроєм <xliff:g id="DEVICE_NAME">%1$s</xliff:g>. Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Календар\", \"Журнали викликів\" і \"Пристрої поблизу\"."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Додатки"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Транслювати додатки телефона"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з вашими сповіщеннями й отримає дозволи \"Телефон\", \"SMS\", \"Контакти\", \"Календар\", \"Журнали викликів\" і \"Пристрої поблизу\"."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Цей додаток потрібен, щоб керувати пристроєм \"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>\". Додаток <xliff:g id="APP_NAME">%2$s</xliff:g> зможе взаємодіяти з такими дозволами:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Надайте додатку &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Сервіси для кількох пристроїв"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на трансляцію додатків між вашими пристроями"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Надайте пристрою &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; доступ до цієї інформації з телефона"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Сервіси Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> від імені вашого пристрою <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> запитує дозвіл на доступ до фотографій, медіафайлів і сповіщень вашого телефона"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"пристрій"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Це може бути доступ до мікрофона, камери та геоданих, а також до іншої конфіденційної інформації на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ви можете будь-коли змінити ці дозволи в налаштуваннях на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Значок додатка"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Кнопка \"Докладніше\""</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Телефон"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Контакти"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Календар"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Пристрої поблизу"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Фотографії та медіафайли"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Сповіщення"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Додатки"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Може переглядати ваш номер телефону й інформацію про мережу. Потрібно для здійснення викликів і зв’язку через VoIP, голосової пошти, переадресації викликів і редагування журналів викликів"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Може читати, створювати або редагувати список контактів, а також переглядати список усіх облікових записів, які використовуються на вашому пристрої"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Може читати всі сповіщення, зокрема таку інформацію, як контакти, повідомлення та фотографії"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Транслювати додатки телефона"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 65b2ba5..71473f7 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"‏‎&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;‎ کو اپنے ‎&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;‎ تک رسائی کی اجازت دیں"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"دیکھیں"</string>
     <string name="chooser_title" msgid="2262294130493605839">"‏&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; کے ذریعے نظم کئے جانے کیلئے <xliff:g id="PROFILE_NAME">%1$s</xliff:g> کو منتخب کریں"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"‏آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لئے اس ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں، کیلنڈر، کال لاگز اور قریبی آلات کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"ایپس"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"‏آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لئے ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو آپ کی اطلاعات کے ساتھ تعامل کرنے اور آپ کے فون، SMS، رابطوں، کیلنڈر، کال لاگز اور قریبی آلات کی اجازتوں تک رسائی کی اجازت ہوگی۔"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"آپ کے <xliff:g id="DEVICE_NAME">%1$s</xliff:g> کا نظم کرنے کے لئے ایپ کی ضرورت ہے۔ <xliff:g id="APP_NAME">%2$s</xliff:g> کو ان اجازتوں کے ساتھ تعامل کرنے کی اجازت ہوگی:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"‏اپنے فون سے ان معلومات تک رسائی حاصل کرنے کی &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو اجازت دیں"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"کراس ڈیوائس سروسز"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے آلات کے درمیان ایپس کی سلسلہ بندی کرنے کی اجازت کی درخواست کر رہی ہے"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"‏اپنے فون سے اس معلومات تک رسائی حاصل کرنے کی &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; کو اجازت دیں"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"رابطوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھ سکتے ہیں"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"‏Google Play سروسز"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> ایپ آپ کے <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> کی جانب سے آپ کے فون کی تصاویر، میڈیا اور اطلاعات تک رسائی کی اجازت طلب کر رہی ہے"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"آلہ"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"‏&lt;p&gt;اس میں مائیکروفون، کیمرا اور مقام تک رسائی اور ;‎&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&amp;gt پر دیگر حساس اجازتیں شامل ہو سکتی ہیں۔&lt;/p&gt; &lt;p&gt;آپ ‎&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>;&lt;/strong&amp;gt پر کسی بھی وقت اپنی ترتیبات میں ان اجازتوں کو تبدیل کر سکتے ہیں۔&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"ایپ کا آئیکن"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"مزید معلومات کا بٹن"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"فون"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"رابطے"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"کیلنڈر"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"قریبی آلات"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"تصاویر اور میڈیا"</string>
+    <string name="permission_notification" msgid="693762568127741203">"اطلاعات"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"ایپس"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"‏آپ کے فون نمبر اور نیٹ ورک کی معلومات تک رسائی حاصل کر سکتی ہے۔ کالز کرنے اور VoIP، صوتی میل، کال ری ڈائریکٹ، اور کال لاگز میں ترمیم کرنے کے لیے درکار ہے"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"ہماری رابطوں کی فہرست پڑھ سکتی ہے، اسے تخلیق سکتی ہے یا اس میں ترمیم کر سکتی ہے، نیز آپ کے آلے پر استعمال ہونے والے تمام اکاؤنٹس کی فہرست تک رسائی حاصل کر سکتی ہے"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"رابطوں، پیغامات اور تصاویر جیسی معلومات سمیت تمام اطلاعات پڑھ سکتے ہیں"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"اپنے فون کی ایپس کی سلسلہ بندی کریں"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index befb370..721a338 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasiga kirish uchun &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga ruxsat bering"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"soat"</string>
     <string name="chooser_title" msgid="2262294130493605839">"&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; boshqaradigan <xliff:g id="PROFILE_NAME">%1$s</xliff:g> qurilmasini tanlang"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Bu ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, taqvim, chaqiruvlar jurnali va yaqin-atrofdagi qurilmalarga kirishga ruxsat beriladi."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Ilovalar"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Telefondagi ilovalarni translatsiya qilish"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga bildirishnomalar bilan ishlash va telefon, SMS, kontaktlar, taqvim, chaqiruvlar jurnali va yaqin-atrofdagi qurilmalarga kirishga ruxsat beriladi."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Ilova <xliff:g id="DEVICE_NAME">%1$s</xliff:g> profilini boshqarish uchun kerak. <xliff:g id="APP_NAME">%2$s</xliff:g> ilovasiga quyidagi ruxsatlar bilan ishlashga ruxsat beriladi:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Qurilmalararo xizmatlar"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"Qurilamalararo ilovalar strimingi uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovasiga telefondagi ushbu maʼlumot uchun ruxsat bering"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play xizmatlari"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"Telefoningizdagi rasm, media va bildirishnomalarga kirish uchun <xliff:g id="APP_NAME">%1$s</xliff:g> ilovasi <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> nomidan ruxsat soʻramoqda"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"qurilma"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Bunga &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt; qurilmasidagi Mikrofon, Kamera, Joylashuv kabi muhim ruxsatlar kirishi mumkin.&lt;/p&gt; &lt;p&gt;Bu ruxsatlarni istalgan vaqt &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt; Sozlamalari orqali oʻzgartirish mumkin.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Ilova belgisi"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Batafsil axborot tugmasi"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Telefon"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Kontaktlar"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Taqvim"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Atrofdagi qurilmalar"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Suratlar va media"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Bildirishnomalar"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Ilovalar"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Telefon raqamingiz va tarmoq maʼlumotlariga kira oladi. Telefon qilish va VoIP, ovozli xabar, chaqiruvlarni yoʻnaltirish va chaqiruvlar jurnallarini tahrirlash uchun talab qilinadi"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Kontaktlar roʻyxatini oʻqishi, yaratishi yoki tahrirlashi, shuningdek, qurilmangizda foydalaniladigan barcha hisoblar roʻyxatiga kirishi mumkin"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Barcha bildirishnomalarni, jumladan, kontaktlar, xabarlar va suratlarni oʻqishi mumkin"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Telefondagi ilovalarni translatsiya qilish"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index b29e08c..cb9e558 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; của bạn"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"đồng hồ"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Chọn một <xliff:g id="PROFILE_NAME">%1$s</xliff:g> sẽ do &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; quản lý"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"Cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> sẽ được phép tương tác với các thông báo và truy cập vào Điện thoại, SMS, Danh bạ, Lịch, Nhật ký cuộc gọi và quyền đối với Thiết bị ở gần."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Ứng dụng"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Truyền các ứng dụng trên điện thoại của bạn"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"Cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> sẽ được phép tương tác với thông báo và truy cập vào Điện thoại, SMS, Danh bạ, Lịch, Nhật ký cuộc gọi và Thiết bị ở gần."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"Cần có ứng dụng này để quản lý <xliff:g id="DEVICE_NAME">%1$s</xliff:g> của bạn. <xliff:g id="APP_NAME">%2$s</xliff:g> được quyền tương tác với những chức năng sau:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Dịch vụ trên nhiều thiết bị"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truyền trực tuyến ứng dụng giữa các thiết bị của bạn"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Cho phép &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; truy cập vào thông tin này trên điện thoại của bạn"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Có thể đọc tất cả các thông báo, kể cả những thông tin như danh bạ, tin nhắn và ảnh"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Dịch vụ Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang yêu cầu quyền thay cho <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> để truy cập vào ảnh, nội dung nghe nhìn và thông báo trên điện thoại của bạn."</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"thiết bị"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Những quyền này có thể bao gồm quyền truy cập vào micrô, máy ảnh và thông tin vị trí, cũng như các quyền truy cập thông tin nhạy cảm khác trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Bạn có thể thay đổi những quyền này bất cứ lúc nào trong phần Cài đặt trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Biểu tượng ứng dụng"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Nút thông tin khác"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Điện thoại"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"Tin nhắn SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Danh bạ"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Lịch"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Thiết bị ở gần"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Ảnh và nội dung nghe nhìn"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Thông báo"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Ứng dụng"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Có thể truy cập vào thông tin mạng và số điện thoại của bạn. Điện thoại cần được cấp quyền này để gọi điện và gọi bằng dịch vụ VoIP, soạn thư thoại, chuyển hướng cuộc gọi, đồng thời chỉnh sửa nhật ký cuộc gọi"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Có thể tạo, đọc, chỉnh sửa, đồng thời truy cập danh bạ của mọi tài khoản được sử dụng trên thiết bị"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Có thể đọc tất cả các thông báo, kể cả những thông tin như danh bạ, tin nhắn và ảnh"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Truyền các ứng dụng trên điện thoại của bạn"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index 7b3be44..dad4709 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"允许&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt;访问您的&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手表"</string>
     <string name="chooser_title" msgid="2262294130493605839">"选择要由&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"需要使用此应用,才能管理您的“<xliff:g id="DEVICE_NAME">%1$s</xliff:g>”。“<xliff:g id="APP_NAME">%2$s</xliff:g>”将能与通知互动,并可获得电话、短信、通讯录、日历、通话记录和附近的设备访问权限。"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"应用"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"流式传输手机上的应用"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"需要使用此应用,才能管理您的<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。<xliff:g id="APP_NAME">%2$s</xliff:g>将能与通知交互,并可获得电话、短信、通讯录、日历、通话记录和附近设备的访问权限。"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"需要使用此应用,才能管理您的<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。<xliff:g id="APP_NAME">%2$s</xliff:g>可与以下权限交互:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"允许“<xliff:g id="APP_NAME">%1$s</xliff:g>”&lt;strong&gt;&lt;/strong&gt;访问您手机中的这项信息"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨设备服务"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求在您的设备之间流式传输应用内容"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允许 &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 访问您手机中的这项信息"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"可以读取所有通知,包括合同、消息和照片等信息"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服务"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”正代表您的<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>请求访问您手机上的照片、媒体内容和通知"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"设备"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;这可能包括&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;的麦克风、摄像头和位置信息访问权限,以及其他敏感权限。&lt;/p&gt; &lt;p&gt;您可以随时在&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;的“设置”中更改这些权限。&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"应用图标"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"更多信息按钮"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"手机"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"短信"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"通讯录"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"日历"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"附近的设备"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"照片和媒体内容"</string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"应用"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"可以访问您的电话号码和网络信息。具备此权限才能实现电话拨打以及 VoIP、语音信箱、电话转接和通话记录编辑功能"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"可以读取、创建或修改您的联系人列表,以及访问您设备上使用的所有帐号的联系人列表"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"可以读取所有通知,包括合同、消息和照片等信息"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"流式传输手机上的应用"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index ede2369..50c4214 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"允許&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; 存取您的 &lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="chooser_title" msgid="2262294130493605839">"選擇由 &lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt; 管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"必須使用此應用程式,才能管理<xliff:g id="DEVICE_NAME">%1$s</xliff:g>。<xliff:g id="APP_NAME">%2$s</xliff:g> 將可存取通知、電話、短訊、通訊錄和日曆、通話記錄和附近的裝置權限。"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"串流播放手機應用程式內容"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知、電話、短訊、通訊錄和日曆、通話記錄和附近的裝置權限。"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"必須使用此應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取以下權限:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在為 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求權限,以在裝置之間串流應用程式內容"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取您手機中的這項資料"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表 <xliff:g id="DEVICE_TYPE">%2$s</xliff:g> 要求權限,以便存取手機上的相片、媒體和通知"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;這可能包括 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt; 的麥克風、相機和位置存取權和其他敏感資料權限。您隨時可透過 &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; 變更這些權限。"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"「更多資料」按鈕"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"手機"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"短訊"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"通訊錄"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"日曆"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"附近的裝置"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"應用程式"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"可存取您的電話號碼及網絡資訊。必須授予此權限才可撥打電話和 VoIP 通話、留言、轉駁來電及編輯通話記錄"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"可讀取、建立或編輯通訊錄,以及存取您裝置上所有用過的帳戶清單"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"可以讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"串流播放手機應用程式內容"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 675072b..7cbd9a7 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取「<xliff:g id="DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"手錶"</string>
     <string name="chooser_title" msgid="2262294130493605839">"選擇要讓「<xliff:g id="APP_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;管理的<xliff:g id="PROFILE_NAME">%1$s</xliff:g>"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆、通話記錄和鄰近裝置的權限。"</string>
-    <string name="permission_apps" msgid="6142133265286656158">"應用程式"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"串流傳輸手機應用程式內容"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可存取通知、電話、簡訊、聯絡人和日曆、通話記錄和鄰近裝置的權限。"</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"你必須使用這個應用程式,才能管理「<xliff:g id="DEVICE_NAME">%1$s</xliff:g>」。「<xliff:g id="APP_NAME">%2$s</xliff:g>」將可與下列權限互動:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取手機中的這項資訊"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"跨裝置服務"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便在裝置之間串流傳輸應用程式內容"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"允許「<xliff:g id="APP_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;存取你手機中的這項資訊"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"可讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Google Play 服務"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在代表你的「<xliff:g id="DEVICE_TYPE">%2$s</xliff:g>」要求必要權限,以便存取手機上的相片、媒體和通知"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"裝置"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;這可能包括「<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;.&lt;/p&gt;的麥克風、相機和位置資訊存取權和其他機密權限。&lt;/p&gt; &lt;p&gt;你隨時可透過「<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;的設定變更這些權限。&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"應用程式圖示"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"更多資訊按鈕"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"電話"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"簡訊"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"聯絡人"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"日曆"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"鄰近裝置"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"相片和媒體"</string>
+    <string name="permission_notification" msgid="693762568127741203">"通知"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"應用程式"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"可存取你的電話號碼和網路資訊。你必須授予這項權限,才能撥打電話和進行 VoIP 通話、聽取語音留言、轉接來電,以及編輯通話記錄"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"可讀取、建立或編輯你的聯絡人清單,還能存取裝置上所有帳戶的聯絡人清單"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"可讀取所有通知,包括聯絡人、訊息和電話等資訊"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"串流傳輸手機應用程式內容"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index ec87f2d..231f71c 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -20,9 +20,8 @@
     <string name="confirmation_title" msgid="3785000297483688997">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukuthi ifinyelele i-&lt;strong&gt;<xliff:g id="DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; yakho"</string>
     <string name="profile_name_watch" msgid="576290739483672360">"buka"</string>
     <string name="chooser_title" msgid="2262294130493605839">"Khetha i-<xliff:g id="PROFILE_NAME">%1$s</xliff:g> ezophathwa yi-&lt;strong&gt;<xliff:g id="APP_NAME">%2$s</xliff:g>&lt;/strong&gt;"</string>
-    <string name="summary_watch" msgid="3002344206574997652">"I-app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele Ifoni yakho, i-SMS, Oxhumana nabo, Ikhalenda, Amarekhodi wamakholi Nezimvume zamadivayisi aseduze."</string>
-    <string name="permission_apps" msgid="6142133265286656158">"Ama-app"</string>
-    <string name="permission_apps_summary" msgid="798718816711515431">"Sakaza ama-app wefoni yakho"</string>
+    <string name="summary_watch" msgid="4085794790142204006">"I-app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. I-<xliff:g id="APP_NAME">%2$s</xliff:g> izovunyelwa ukuthi ihlanganyele nezaziso zakho futhi ifinyelele Ifoni yakho, i-SMS, Oxhumana nabo, Ikhalenda, Amarekhodi wamakholi Nezimvume zamadivayisi aseduze."</string>
+    <string name="summary_watch_single_device" msgid="1523091550243476756">"I-app iyadingeka ukuphatha i-<xliff:g id="DEVICE_NAME">%1$s</xliff:g> yakho. <xliff:g id="APP_NAME">%2$s</xliff:g> uzovunyelwa ukusebenzisana nalezi zimvume:"</string>
     <string name="title_app_streaming" msgid="2270331024626446950">"Vumela i-&lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ifinyelele lolu lwazi kusukela efonini yakho"</string>
     <string name="helper_title_app_streaming" msgid="4151687003439969765">"Amasevisi amadivayisi amaningi"</string>
     <string name="helper_summary_app_streaming" msgid="5977509499890099">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze isakaze-bukhoma ama-app phakathi kwamadivayisi akho"</string>
@@ -30,10 +29,6 @@
     <string name="summary_automotive_projection" msgid="8683801274662496164"></string>
     <string name="title_computer" msgid="4693714143506569253">"Vumela &lt;strong&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/strong&gt; ukufinyelela lolu lwazi kusuka efonini yakho"</string>
     <string name="summary_computer" msgid="3798467601598297062"></string>
-    <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string>
-    <string name="permission_notification_summary" msgid="884075314530071011">"Ingafunda zonke izaziso, okubandakanya ulwazi olufana noxhumana nabo, imilayezo, nezithombe"</string>
-    <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string>
-    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
     <string name="helper_title_computer" msgid="4671071173916176037">"Amasevisi we-Google Play"</string>
     <string name="helper_summary_computer" msgid="9050724687678157852">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> icela imvume esikhundleni se-<xliff:g id="DEVICE_TYPE">%2$s</xliff:g> yakho ukuze ifinyelele izithombe zefoni yakho, imidiya nezaziso"</string>
     <string name="profile_name_generic" msgid="6851028682723034988">"idivayisi"</string>
@@ -45,4 +40,20 @@
     <string name="permission_sync_summary" msgid="4866838188678457084">"&lt;p&gt;Lokhu kungase kuhlanganisa Imakrofoni, Ikhamera, kanye Nokufinyelela kwendawo, kanye nezinye izimvume ezibucayi &lt;strong&gt;ku-<xliff:g id="COMPANION_DEVICE_NAME_0">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt; &lt;p&gt;Ungashintsha lezi zimvume nganoma yisiphi isikhathi Kumasethingi akho &lt;strong&gt;ku-<xliff:g id="COMPANION_DEVICE_NAME_1">%1$s</xliff:g>&lt;/strong&gt;.&lt;/p&gt;"</string>
     <string name="vendor_icon_description" msgid="4445875290032225965">"Isithonjana Se-app"</string>
     <string name="vendor_header_button_description" msgid="6566660389500630608">"Inkinobho Yolwazi Olwengeziwe"</string>
+    <string name="permission_phone" msgid="2661081078692784919">"Ifoni"</string>
+    <string name="permission_sms" msgid="6337141296535774786">"I-SMS"</string>
+    <string name="permission_contacts" msgid="3858319347208004438">"Oxhumana nabo"</string>
+    <string name="permission_calendar" msgid="6805668388691290395">"Ikhalenda"</string>
+    <string name="permission_nearby_devices" msgid="7530973297737123481">"Amadivayisi aseduze"</string>
+    <string name="permission_storage" msgid="6831099350839392343">"Izithombe nemidiya"</string>
+    <string name="permission_notification" msgid="693762568127741203">"Izaziso"</string>
+    <string name="permission_app_streaming" msgid="6009695219091526422">"Ama-app"</string>
+    <string name="permission_phone_summary" msgid="6154198036705702389">"Ingakwazi ukufinyelela inombolo yakho yefoni kanye nolwazi lwenethiwekhi. Iyadingeka ekwenzeni amakholi ne-VoIP, ivoyisimeyili, ukuqondisa kabusha ikholi, nokuhlela amarekhodi amakholi"</string>
+    <string name="permission_sms_summary" msgid="5107174184224165570"></string>
+    <string name="permission_contacts_summary" msgid="7850901746005070792">"Angafunda, asungule, noma ahlele uhlu lwethu loxhumana nabo, futhi afinyelele uhlu lwawo wonke ama-akhawunti asetshenziswa kudivayisi yakho"</string>
+    <string name="permission_calendar_summary" msgid="9070743747408808156"></string>
+    <string name="permission_nearby_devices_summary" msgid="8587497797301075494"></string>
+    <string name="permission_notification_summary" msgid="884075314530071011">"Ingafunda zonke izaziso, okubandakanya ulwazi olufana noxhumana nabo, imilayezo, nezithombe"</string>
+    <string name="permission_app_streaming_summary" msgid="606923325679670624">"Sakaza ama-app wefoni yakho"</string>
+    <string name="permission_storage_summary" msgid="3918240895519506417"></string>
 </resources>
diff --git a/packages/CredentialManager/res/drawable/ic_other_sign_in.xml b/packages/CredentialManager/res/drawable/ic_other_sign_in.xml
new file mode 100644
index 0000000..8150197
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_other_sign_in.xml
@@ -0,0 +1,36 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="VectorPath"
+    android:name="vector"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:name="path"
+        android:pathData="M 20 19 L 12 19 L 12 21 L 20 21 C 21.1 21 22 20.1 22 19 L 22 5 C 22 3.9 21.1 3 20 3 L 12 3 L 12 5 L 20 5 L 20 19 Z"
+        android:fillColor="#000"
+        android:strokeWidth="1"/>
+    <path
+        android:name="path_1"
+        android:pathData="M 12 7 L 10.6 8.4 L 13.2 11 L 8.85 11 C 8.42 9.55 7.09 8.5 5.5 8.5 C 3.57 8.5 2 10.07 2 12 C 2 13.93 3.57 15.5 5.5 15.5 C 7.09 15.5 8.42 14.45 8.85 13 L 13.2 13 L 10.6 15.6 L 12 17 L 17 12 L 12 7 Z M 5.5 13.5 C 4.67 13.5 4 12.83 4 12 C 4 11.17 4.67 10.5 5.5 10.5 C 6.33 10.5 7 11.17 7 12 C 7 12.83 6.33 13.5 5.5 13.5 Z"
+        android:fillColor="#000"
+        android:strokeWidth="1"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/ic_password.xml b/packages/CredentialManager/res/drawable/ic_password.xml
new file mode 100644
index 0000000..bf3056a
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/ic_password.xml
@@ -0,0 +1,31 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:ignore="VectorPath"
+    android:name="vector"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:name="path"
+        android:pathData="M 8.71 10.29 C 8.52 10.1 8.28 10 8 10 L 7.75 10 L 7.75 8.75 C 7.75 7.98 7.48 7.33 6.95 6.8 C 6.42 6.27 5.77 6 5 6 C 4.23 6 3.58 6.27 3.05 6.8 C 2.52 7.33 2.25 7.98 2.25 8.75 L 2.25 10 L 2 10 C 1.72 10 1.48 10.1 1.29 10.29 C 1.1 10.48 1 10.72 1 11 L 1 16 C 1 16.28 1.1 16.52 1.29 16.71 C 1.48 16.9 1.72 17 2 17 L 8 17 C 8.28 17 8.52 16.9 8.71 16.71 C 8.9 16.52 9 16.28 9 16 L 9 11 C 9 10.72 8.9 10.48 8.71 10.29 Z M 6.25 10 L 3.75 10 L 3.75 8.75 C 3.75 8.4 3.87 8.1 4.11 7.86 C 4.35 7.62 4.65 7.5 5 7.5 C 5.35 7.5 5.65 7.62 5.89 7.86 C 6.13 8.1 6.25 8.4 6.25 8.75 L 6.25 10 Z M 10 14 L 23 14 L 23 16 L 10 16 Z M 21.5 9 C 21.102 9 20.721 9.158 20.439 9.439 C 20.158 9.721 20 10.102 20 10.5 C 20 10.898 20.158 11.279 20.439 11.561 C 20.721 11.842 21.102 12 21.5 12 C 21.898 12 22.279 11.842 22.561 11.561 C 22.842 11.279 23 10.898 23 10.5 C 23 10.102 22.842 9.721 22.561 9.439 C 22.279 9.158 21.898 9 21.5 9 Z M 16.5 9 C 16.102 9 15.721 9.158 15.439 9.439 C 15.158 9.721 15 10.102 15 10.5 C 15 10.898 15.158 11.279 15.439 11.561 C 15.721 11.842 16.102 12 16.5 12 C 16.898 12 17.279 11.842 17.561 11.561 C 17.842 11.279 18 10.898 18 10.5 C 18 10.102 17.842 9.721 17.561 9.439 C 17.279 9.158 16.898 9 16.5 9 Z M 11.5 9 C 11.102 9 10.721 9.158 10.439 9.439 C 10.158 9.721 10 10.102 10 10.5 C 10 10.898 10.158 11.279 10.439 11.561 C 10.721 11.842 11.102 12 11.5 12 C 11.898 12 12.279 11.842 12.561 11.561 C 12.842 11.279 13 10.898 13 10.5 C 13 10.102 12.842 9.721 12.561 9.439 C 12.279 9.158 11.898 9 11.5 9 Z"
+        android:fillColor="#000"
+        android:strokeWidth="1"/>
+</vector>
\ No newline at end of file
diff --git a/packages/CredentialManager/res/values-af/strings.xml b/packages/CredentialManager/res/values-af/strings.xml
new file mode 100644
index 0000000..377c13f
--- /dev/null
+++ b/packages/CredentialManager/res/values-af/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Eiebewysbestuurder"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Kanselleer"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Gaan voort"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Skep op ’n ander plek"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Stoor in ’n ander plek"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Gebruik ’n ander toestel"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Stoor op ’n ander toestel"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"’n Maklike manier om veilig aan te meld"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gebruik jou vingerafdruk, gesig of skermslot om aan te meld met ’n unieke wagwoordsleutel wat nie vergeet of gesteel kan word nie. Kom meer te wete"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Kies waar om <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"stoor jou wagwoord"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"stoor jou aanmeldinligting"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Skep ’n wagwoordsleutel in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Stoor jou wagwoord in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Stoor jou aanmeldinligting in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Jy kan jou <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> op enige toestel gebruik. Dit is in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> gestoor vir <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"wagwoordsleutel"</string>
+    <string name="password" msgid="6738570945182936667">"wagwoord"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"aanmeldings"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Gebruik <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> vir al jou aanmeldings?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Stel as verstek"</string>
+    <string name="use_once" msgid="9027366575315399714">"Gebruik een keer"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> wagwoordsleutels"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wagwoorde"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> wagwoordsleutels"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Wagwoordsleutel"</string>
+    <string name="another_device" msgid="5147276802037801217">"’n Ander toestel"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Ander wagwoordbestuurders"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Maak sigblad toe"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gaan terug na die vorige bladsy"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gebruik jou gestoorde wagwoordsleutel vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gebruik jou gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Kies ’n gestoorde aanmelding vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Meld op ’n ander manier aan"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nee, dankie"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Gaan voort"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Aanmeldopsies"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Vir <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Geslote wagwoordbestuurders"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tik om te ontsluit"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Bestuur aanmeldings"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Van ’n ander toestel af"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gebruik ’n ander toestel"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-am/strings.xml b/packages/CredentialManager/res/values-am/strings.xml
new file mode 100644
index 0000000..b80fe2c
--- /dev/null
+++ b/packages/CredentialManager/res/values-am/strings.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <!-- no translation found for string_cancel (6369133483981306063) -->
+    <skip />
+    <!-- no translation found for string_continue (1346732695941131882) -->
+    <skip />
+    <!-- no translation found for string_create_in_another_place (1033635365843437603) -->
+    <skip />
+    <!-- no translation found for string_save_to_another_place (7590325934591079193) -->
+    <skip />
+    <!-- no translation found for string_use_another_device (8754514926121520445) -->
+    <skip />
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ወደ ሌላ መሣሪያ ያስቀምጡ"</string>
+    <!-- no translation found for passkey_creation_intro_title (402553911484409884) -->
+    <skip />
+    <!-- no translation found for passkey_creation_intro_body (7493320456005579290) -->
+    <skip />
+    <!-- no translation found for choose_provider_title (7245243990139698508) -->
+    <skip />
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <!-- no translation found for save_your_password (6597736507991704307) -->
+    <skip />
+    <!-- no translation found for save_your_sign_in_info (7213978049817076882) -->
+    <skip />
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <!-- no translation found for choose_create_option_passkey_title (4146408187146573131) -->
+    <skip />
+    <!-- no translation found for choose_create_option_password_title (8812546498357380545) -->
+    <skip />
+    <!-- no translation found for choose_create_option_sign_in_title (6318246378475961834) -->
+    <skip />
+    <!-- no translation found for choose_create_option_description (4419171903963100257) -->
+    <skip />
+    <!-- no translation found for passkey (632353688396759522) -->
+    <skip />
+    <!-- no translation found for password (6738570945182936667) -->
+    <skip />
+    <!-- no translation found for sign_ins (4710739369149469208) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <!-- no translation found for use_provider_for_all_title (4201020195058980757) -->
+    <skip />
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <!-- no translation found for set_as_default (4415328591568654603) -->
+    <skip />
+    <!-- no translation found for use_once (9027366575315399714) -->
+    <skip />
+    <!-- no translation found for more_options_usage_passwords_passkeys (4794903978126339473) -->
+    <skip />
+    <!-- no translation found for more_options_usage_passwords (1632047277723187813) -->
+    <skip />
+    <!-- no translation found for more_options_usage_passkeys (5390320437243042237) -->
+    <skip />
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <!-- no translation found for another_device (5147276802037801217) -->
+    <skip />
+    <!-- no translation found for other_password_manager (565790221427004141) -->
+    <skip />
+    <!-- no translation found for close_sheet (1393792015338908262) -->
+    <skip />
+    <!-- no translation found for accessibility_back_arrow_button (3233198183497842492) -->
+    <skip />
+    <!-- no translation found for get_dialog_title_use_passkey_for (6236608872708021767) -->
+    <skip />
+    <!-- no translation found for get_dialog_title_use_sign_in_for (5283099528915572980) -->
+    <skip />
+    <!-- no translation found for get_dialog_title_choose_sign_in_for (1361715440877613701) -->
+    <skip />
+    <!-- no translation found for get_dialog_use_saved_passkey_for (4618100798664888512) -->
+    <skip />
+    <!-- no translation found for get_dialog_button_label_no_thanks (8114363019023838533) -->
+    <skip />
+    <!-- no translation found for get_dialog_button_label_continue (6446201694794283870) -->
+    <skip />
+    <!-- no translation found for get_dialog_title_sign_in_options (2092876443114893618) -->
+    <skip />
+    <!-- no translation found for get_dialog_heading_for_username (3456868514554204776) -->
+    <skip />
+    <!-- no translation found for get_dialog_heading_locked_password_managers (8911514851762862180) -->
+    <skip />
+    <!-- no translation found for locked_credential_entry_label_subtext (9213450912991988691) -->
+    <skip />
+    <!-- no translation found for get_dialog_heading_manage_sign_ins (3522556476480676782) -->
+    <skip />
+    <!-- no translation found for get_dialog_heading_from_another_device (1166697017046724072) -->
+    <skip />
+    <!-- no translation found for get_dialog_option_headline_use_a_different_device (8201578814988047549) -->
+    <skip />
+</resources>
diff --git a/packages/CredentialManager/res/values-ar/strings.xml b/packages/CredentialManager/res/values-ar/strings.xml
new file mode 100644
index 0000000..a5c85c5
--- /dev/null
+++ b/packages/CredentialManager/res/values-ar/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"إلغاء"</string>
+    <string name="string_continue" msgid="1346732695941131882">"متابعة"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"الإنشاء في مكان آخر"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"الحفظ في مكان آخر"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"استخدام جهاز آخر"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"الحفظ على جهاز آخر"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"طريقة بسيطة لتسجيل الدخول بأمان"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"استخدِم بصمة إصبعك أو وجهك أو قفل الشاشة لتسجيل الدخول باستخدام مفتاح مرور فريد لا يمكن نسيانه أو سرقته. مزيد من المعلومات"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"اختيار مكان <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"حفظ كلمة المرور"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"حفظ معلومات تسجيل الدخول"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"هل تريد إنشاء مفتاح مرور في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"هل تريد حفظ كلمة مرورك في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"هل تريد حفظ معلومات تسجيل الدخول في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"؟"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"يمكنك استخدام <xliff:g id="TYPE">%2$s</xliff:g> الخاص بـ \"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>\" على أي جهاز. ويتم حفظه في \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\" للحساب \"<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>\"."</string>
+    <string name="passkey" msgid="632353688396759522">"مفتاح مرور"</string>
+    <string name="password" msgid="6738570945182936667">"كلمة المرور"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"عمليات تسجيل الدخول"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"هل تريد استخدام \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" لكل عمليات تسجيل الدخول؟"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ضبط الخيار كتلقائي"</string>
+    <string name="use_once" msgid="9027366575315399714">"الاستخدام مرة واحدة"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"عدد كلمات المرور هو <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>، و عدد مفاتيح المرور هو <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"عدد كلمات المرور: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"عدد مفاتيح المرور: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"جهاز آخر"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"خدمات مدراء كلمات المرور الأخرى"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"إغلاق ورقة البيانات"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"العودة إلى الصفحة السابقة"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"هل تريد استخدام مفتاح المرور المحفوظ لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"هل تريد استخدام بيانات اعتماد تسجيل الدخول المحفوظة لتطبيق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"؟"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"اختيار بيانات اعتماد تسجيل دخول محفوظة لـ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"تسجيل الدخول بطريقة أخرى"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"لا، شكرًا"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"متابعة"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"خيارات تسجيل الدخول"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"معلومات تسجيل دخول \"<xliff:g id="USERNAME">%1$s</xliff:g>\""</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"خدمات إدارة كلمات المرور المقفولة"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"انقر لإلغاء القفل."</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"إداراة عمليات تسجيل الدخول"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"من جهاز آخر"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استخدام جهاز مختلف"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-as/strings.xml b/packages/CredentialManager/res/values-as/strings.xml
new file mode 100644
index 0000000..4d0ba68
--- /dev/null
+++ b/packages/CredentialManager/res/values-as/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"CredentialManager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"বাতিল কৰক"</string>
+    <string name="string_continue" msgid="1346732695941131882">"অব্যাহত ৰাখক"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"অন্য ঠাইত সৃষ্টি কৰক"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য ঠাইত ছেভ কৰক"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইচ ব্যৱহাৰ কৰক"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য এটা ডিভাইচত ছেভ কৰক"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"সুৰক্ষিতভাৱে ছাইন ইন কৰাৰ এক সৰল উপায়"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"পাহৰি নোযোৱা অথবা চুৰি কৰিব নোৱৰা এটা অদ্বিতীয় পাছকী ব্যৱহাৰ কৰি ছাইন ইন কৰিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট, মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক। অধিক জানক"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"ক’ত <xliff:g id="CREATETYPES">%1$s</xliff:g> সেয়া বাছনি কৰক"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"আপোনাৰ পাছৱৰ্ড ছেভ কৰক"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"আপোনাৰ ছাইন ইন কৰাৰ তথ্য ছেভ কৰক"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত পাছকী সৃষ্টি কৰিবনে?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত আপোনাৰ পাছৱৰ্ড ছেভ কৰিবনে?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ত আপোনাৰ ছাইন ইন কৰাৰ তথ্য ছেভ কৰিবনে?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"আপুনি আপোনাৰ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> যিকোনো ডিভাইচত ব্যৱহাৰ কৰিব পাৰে। এইটো <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>ৰ বাবে <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>ত ছেভ কৰা হৈছে"</string>
+    <string name="passkey" msgid="632353688396759522">"পাছকী"</string>
+    <string name="password" msgid="6738570945182936667">"পাছৱৰ্ড"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ছাইন-ইন"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"আপোনাৰ আটাইবোৰ ছাইন ইনৰ বাবে <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ব্যৱহাৰ কৰিবনে?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ডিফ’ল্ট হিচাপে ছেট কৰক"</string>
+    <string name="use_once" msgid="9027366575315399714">"এবাৰ ব্যৱহাৰ কৰক"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> টা পাছৱৰ্ড, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> টা পাছকী"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> টা পাছৱৰ্ড"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> টা পাছকী"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"পাছকী"</string>
+    <string name="another_device" msgid="5147276802037801217">"অন্য এটা ডিভাইচ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"অন্য পাছৱৰ্ড পৰিচালক"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"শ্বীট বন্ধ কৰক"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"পূৰ্বৱৰ্তী পৃষ্ঠালৈ ঘূৰি যাওক"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা পাছকী ব্যৱহাৰ কৰিবনে?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে আপোনাৰ ছেভ হৈ থকা ছাইন ইন তথ্য ব্যৱহাৰ কৰিবনে?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাবে ছেভ হৈ থকা এটা ছাইন ইন বাছনি কৰক"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"অন্য উপায়েৰে ছাইন ইন কৰক"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"নালাগে, ধন্যবাদ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"অব্যাহত ৰাখক"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ছাইন ইনৰ বিকল্প"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>ৰ বাবে"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"লক হৈ থকা পাছৱৰ্ড পৰিচালক"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"আনলক কৰিবলৈ টিপক"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ছাইন ইন পৰিচালনা কৰক"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য এটা ডিভাইচৰ পৰা"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"অন্য এটা ডিভাইচ ব্যৱহাৰ কৰক"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-az/strings.xml b/packages/CredentialManager/res/values-az/strings.xml
new file mode 100644
index 0000000..14313f7
--- /dev/null
+++ b/packages/CredentialManager/res/values-az/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Giriş Məlumatları Meneceri"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Ləğv edin"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Davam edin"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Başqa yerdə yaradın"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Başqa yerdə yadda saxlayın"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Digər cihaz istifadə edin"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Başqa cihazda yadda saxlayın"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Təhlükəsiz daxil olmağın sadə yolu"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Unutmaq və ya oğurlamaq mümkün olmayan unikal giriş açarı ilə daxil olmaq üçün barmaq izi, üz və ya ekran kilidindən istifadə edin. Ətraflı məlumat"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> üçün yer seçin"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"parolunuzu yadda saxlayın"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"giriş məlumatınızı yadda saxlayın"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində giriş açarı yaradılsın?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Parol <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində saxlanılsın?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Giriş məlumatınız <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xidmətində saxlanılsın?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> domenini istənilən cihazda istifadə edə bilərsiniz. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> xidmətində saxlanılıb"</string>
+    <string name="passkey" msgid="632353688396759522">"giriş açarı"</string>
+    <string name="password" msgid="6738570945182936667">"parol"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"girişlər"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Bütün girişlər üçün <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> istifadə edilsin?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Defolt olaraq seçin"</string>
+    <string name="use_once" msgid="9027366575315399714">"Bir dəfə istifadə edin"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parol, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> giriş açarı"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parol"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> giriş açarı"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Giriş açarı"</string>
+    <string name="another_device" msgid="5147276802037801217">"Digər cihaz"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Digər parol menecerləri"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Səhifəni bağlayın"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Əvvəlki səhifəyə qayıdın"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış giriş açarı istifadə edilsin?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişdən istifadə edilsin?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün yadda saxlanmış girişi seçin"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Başqa üsulla daxil olun"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Xeyr, təşəkkürlər"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Davam edin"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Giriş seçimləri"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> üçün"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Kilidli parol menecerləri"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Kilidi açmaq üçün tıklayın"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Girişləri idarə edin"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başqa cihazdan"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Başqa cihaz istifadə edin"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-b+sr+Latn/strings.xml b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..c58ec14
--- /dev/null
+++ b/packages/CredentialManager/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Otkaži"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Napravi na drugom mestu"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvaj na drugom mestu"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Koristi drugi uređaj"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvaj na drugi uređaj"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način da se bezbedno prijavljujete"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Koristite otisak prsta, zaključavanje licem ili zaključavanje ekrana da biste se prijavili pomoću jedinstvenog pristupnog koda koji ne može da se zaboravi ili ukrade. Saznajte više"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite lokaciju za: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte podatke o prijavljivanju"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite da napravite pristupni kôd kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite da sačuvate lozinku kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite da sačuvate podatke o prijavljivanju kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Možete da koristite tip domena <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> na bilo kom uređaju. Čuva se kod korisnika <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"pristupni kôd"</string>
+    <string name="password" msgid="6738570945182936667">"lozinka"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prijavljivanja"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite da za sva prijavljivanja koristite: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Podesi kao podrazumevano"</string>
+    <string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, pristupnih kodova:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Pristupnih kodova: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Drugi uređaj"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Drugi menadžeri lozinki"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zatvorite tabelu"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vratite se na prethodnu stranicu"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite da koristite sačuvani pristupni kôd za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite da koristite sačuvane podatke za prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite sačuvano prijavljivanje za: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na drugi način"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, hvala"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije za prijavljivanje"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za: <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menadžeri zaključanih lozinki"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Dodirnite da biste otključali"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavljivanjima"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Sa drugog uređaja"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Koristi drugi uređaj"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-be/strings.xml b/packages/CredentialManager/res/values-be/strings.xml
new file mode 100644
index 0000000..3c23afd
--- /dev/null
+++ b/packages/CredentialManager/res/values-be/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Скасаваць"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Далей"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Стварыць у іншым месцы"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Захаваць у іншым месцы"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Скарыстаць іншую прыладу"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Захаваць на іншую прыладу"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Просты спосаб бяспечнага ўваходу"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Для ўваходу з унікальным ключом доступу, які нельга згубіць ці ўкрасці, можна скарыстаць адбітак пальца, распазнаванне твару ці разблакіроўку экрана. Даведацца больш"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Выберыце, дзе <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"захаваць пароль"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"захаваць інфармацыю пра спосаб уваходу"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Стварыць ключ доступу ў папцы \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Захаваць пароль у папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Захаваць інфармацыю пра спосаб уваходу ў папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Вы можаце выкарыстоўваць <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> на любой прыладзе. Даныя для \"<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>\" захоўваюцца ў папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\""</string>
+    <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
+    <string name="password" msgid="6738570945182936667">"пароль"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"спосабы ўваходу"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Выкарыстоўваць папку \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\" для ўсіх спосабаў уваходу?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Выкарыстоўваць стандартна"</string>
+    <string name="use_once" msgid="9027366575315399714">"Скарыстаць адзін раз"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Пароляў: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, ключоў доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Пароляў: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Ключоў доступу: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Іншая прылада"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Іншыя спосабы ўваходу"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Закрыць аркуш"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вярнуцца да папярэдняй старонкі"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Скарыстаць захаваны ключ доступу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Скарыстаць захаваныя спосабы ўваходу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Выберыце захаваны спосаб уваходу для праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Увайсці іншым спосабам"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Не, дзякуй"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Далей"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Спосабы ўваходу"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для карыстальніка <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблакіраваныя спосабы ўваходу"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Націсніце, каб разблакіраваць"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіраваць спосабамі ўваходу"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншай прылады"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Скарыстаць іншую прыладу"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-bg/strings.xml b/packages/CredentialManager/res/values-bg/strings.xml
new file mode 100644
index 0000000..af7eb17
--- /dev/null
+++ b/packages/CredentialManager/res/values-bg/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Отказ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Напред"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Създаване другаде"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Запазване на друго място"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Използване на друго устройство"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Запазване на друго устройство"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Лесен начин за безопасно влизане в профил"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Използвайте отпечатъка, лицето или опцията си за заключване на екрана, за да влизате в профила си с помощта на уникален код за достъп, който не може да бъде забравен или откраднат. Научете повече"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Изберете място за <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"запазване на паролата ви"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"запазване на данните ви за вход"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Да се създаде ли код за достъп в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Искате ли да запазите паролата си в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Искате ли да запазите данните си за вход в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Можете да използвате <xliff:g id="TYPE">%2$s</xliff:g> за <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> на всяко устройство. Тези данни се запазват в(ъв) <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"код за достъп"</string>
+    <string name="password" msgid="6738570945182936667">"парола"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"данни за вход"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Да се използва ли <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> за всичките ви данни за вход?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Задаване като основно"</string>
+    <string name="use_once" msgid="9027366575315399714">"Еднократно използване"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> пароли, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кода за достъп"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> пароли"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> кода за достъп"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Друго устройство"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Други мениджъри на пароли"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Затваряне на таблицата"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Назад към предишната страница"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се използва ли запазеният ви код за достъп за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се използват ли запазените ви данни за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Изберете запазени данни за вход за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Влизане в профила по друг начин"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Не, благодаря"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Напред"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опции за влизане в профила"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заключени мениджъри на пароли"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Докоснете, за да отключите"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление на данните за вход"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"От друго устройство"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Използване на друго устройство"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-bn/strings.xml b/packages/CredentialManager/res/values-bn/strings.xml
new file mode 100644
index 0000000..152e5bd
--- /dev/null
+++ b/packages/CredentialManager/res/values-bn/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"বাতিল করুন"</string>
+    <string name="string_continue" msgid="1346732695941131882">"চালিয়ে যান"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"অন্য জায়গায় তৈরি করুন"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"অন্য জায়গায় সেভ করুন"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"অন্য ডিভাইস ব্যবহার করুন"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"অন্য ডিভাইসে সেভ করুন"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"নিরাপদে সাইন-ইন করার একটি সহজ উপায়"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"একটি অনন্য পাসকী ব্যবহার করে সাইন-ইন করতে আপনার ফিঙ্গারপ্রিন্ট, মুখ বা স্ক্রিন লক ব্যবহার করুন যেটি ভুলে যাবেন না বা হারিয়ে যাবেন না। আরও জানুন"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> কোথায় সেভ করবেন তা বেছে নিন"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"আপনার পাসওয়ার্ড সেভ করুন"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"আপনার সাইন-ইন করা সম্পর্কিত তথ্য সেভ করুন"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ পাসকী তৈরি করবেন?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"আপনার পাসওয়ার্ড <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ সেভ করবেন?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"আপনার সাইন-ইন করা সম্পর্কিত তথ্য <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-এ সেভ করবেন?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"যেকোনও ডিভাইসে নিজের <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ব্যবহার করতে পারবেন। এটি <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-এর জন্য <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-এ সেভ করা আছে"</string>
+    <string name="passkey" msgid="632353688396759522">"পাসকী"</string>
+    <string name="password" msgid="6738570945182936667">"পাসওয়ার্ড"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"সাইন-ইন"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"আপনার সব সাইন-ইনের জন্য <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ব্যবহার করবেন?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ডিফল্ট হিসেবে সেট করুন"</string>
+    <string name="use_once" msgid="9027366575315399714">"একবার ব্যবহার করুন"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>টি পাসওয়ার্ড, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>টি পাসকী"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>টি পাসওয়ার্ড"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>টি পাসকী"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"অন্য ডিভাইস"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"অন্যান্য Password Manager"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"শিট বন্ধ করুন"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"আগের পৃষ্ঠায় ফিরে যান"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা পাসকী ব্যবহার করবেন?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য আপনার সেভ করা সাইন-ইন সম্পর্কিত ক্রেডেনশিয়াল ব্যবহার করবেন?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর জন্য সাইন-ইন করা সম্পর্কিত ক্রেডেনশিয়াল বেছে নিন"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"অন্যভাবে সাইন-ইন করুন"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"না থাক"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"চালিয়ে যান"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"সাইন-ইন করার বিকল্প"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-এর জন্য"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"লক করা Password Manager"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"আনলক করতে ট্যাপ করুন"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"সাইন-ইন করার ক্রেডেনশিয়াল ম্যানেজ করুন"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"অন্য ডিভাইস থেকে"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"আলাদা ডিভাইস ব্যবহার করুন"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-bs/strings.xml b/packages/CredentialManager/res/values-bs/strings.xml
new file mode 100644
index 0000000..d774b88
--- /dev/null
+++ b/packages/CredentialManager/res/values-bs/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Upravitelj akreditiva"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Otkaži"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Kreirajte na drugom mjestu"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Sačuvajte na drugom mjestu"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Koristite drugi uređaj"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Sačuvajte na drugom uređaju"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način za sigurnu prijavu"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Koristite otisak prsta, lice ili zaključavanje ekrana da se prijavite jedinstvenim pristupnim ključem koji se ne može zaboraviti niti ukrasti. Saznajte više"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite gdje <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"sačuvajte lozinku"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"sačuvajte informacije za prijavu"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kreirati pristupni ključ na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Sačuvati lozinku na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Sačuvati informacije za prijavu na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Možete koristiti <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> na bilo kojem uređaju. Sačuvan je na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
+    <string name="password" msgid="6738570945182936667">"lozinka"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Koristiti uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve vaše prijave?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
+    <string name="use_once" msgid="9027366575315399714">"Koristi jednom"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Broj lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>; broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Broj lozinki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Pristupni ključ"</string>
+    <string name="another_device" msgid="5147276802037801217">"Drugi uređaj"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji lozinki"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zatvaranje tabele"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Povratak na prethodnu stranicu"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Koristiti sačuvani pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Koristiti sačuvanu prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite sačuvanu prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na drugi način"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, hvala"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije prijave"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za osobu <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zaključani upravitelji lozinki"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Dodirnite da otključate"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljajte prijavama"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"S drugog uređaja"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ca/strings.xml b/packages/CredentialManager/res/values-ca/strings.xml
new file mode 100644
index 0000000..bfd9164
--- /dev/null
+++ b/packages/CredentialManager/res/values-ca/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Cancel·la"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continua"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Crea en un altre lloc"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Desa en un altre lloc"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Utilitza un altre dispositiu"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Desa en un altre dispositiu"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Una manera senzilla i segura d\'iniciar la sessió"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilitza l\'empremta digital, la cara o el bloqueig de pantalla per iniciar la sessió amb una clau d\'accés única que no es pot oblidar ni robar. Més informació"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Tria on vols <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"desar la contrasenya"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"desar la teva informació d\'inici de sessió"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vols crear una clau d\'accés a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vols desar la contrasenya a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vols desar la teva informació d\'inici de sessió a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Pots utilitzar <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> en qualsevol dispositiu. Està desat a <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> per a <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"clau d\'accés"</string>
+    <string name="password" msgid="6738570945182936667">"contrasenya"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"inicis de sessió"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vols utilitzar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per a tots els teus inicis de sessió?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Estableix com a predeterminada"</string>
+    <string name="use_once" msgid="9027366575315399714">"Utilitza un cop"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasenyes, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claus d\'accés"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasenyes"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> claus d\'accés"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Un altre dispositiu"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Altres gestors de contrasenyes"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Tanca el full"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Torna a la pàgina anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vols utilitzar la clau d\'accés desada per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vols utilitzar l\'inici de sessió desat per a <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Tria un inici de sessió desat per a <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Inicia la sessió d\'una altra manera"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No, gràcies"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continua"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcions d\'inici de sessió"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Per a <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestors de contrasenyes bloquejats"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toca per desbloquejar"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestiona els inicis de sessió"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Des d\'un altre dispositiu"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utilitza un dispositiu diferent"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-cs/strings.xml b/packages/CredentialManager/res/values-cs/strings.xml
new file mode 100644
index 0000000..72a5f98
--- /dev/null
+++ b/packages/CredentialManager/res/values-cs/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Zrušit"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Pokračovat"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Vytvořit na jiném místě"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Uložit na jiné místo"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Použít jiné zařízení"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Uložit do jiného zařízení"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednoduchý způsob, jak se bezpečně přihlásit"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Použijte svůj otisk prstu, obličej nebo zámek obrazovky k přihlášení pomocí jedinečného přístupového klíče, který nemůžete zapomenout a který vám nikdo nemůže odcizit. Další informace"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Zvolte, kde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"uložte si heslo"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"uložte své přihlašovací údaje"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vytvořit přístupový klíč v <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Uložit heslo do <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Uložit přihlašovací údaje do <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Svoje <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> můžete používat na libovolném zařízení. Ukládá se do <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pro <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"přístupový klíč"</string>
+    <string name="password" msgid="6738570945182936667">"heslo"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"přihlášení"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Používat <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pro všechna přihlášení?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Nastavit jako výchozí"</string>
+    <string name="use_once" msgid="9027366575315399714">"Použít jednou"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Počet hesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, počet přístupových klíčů: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Počet hesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Počet přístupových klíčů: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Jiné zařízení"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Další správci hesel"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zavřít list"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Zpět na předchozí stránku"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Použít uložený přístupový klíč pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Použít uložené přihlášení pro aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vyberte uložené přihlášení pro <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Přihlásit se jinak"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, díky"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Pokračovat"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti přihlašování"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pro uživatele <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Uzamčení správci hesel"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Klepnutím odemknete"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovat přihlášení"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z jiného zařízení"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použít jiné zařízení"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-da/strings.xml b/packages/CredentialManager/res/values-da/strings.xml
new file mode 100644
index 0000000..a05137e
--- /dev/null
+++ b/packages/CredentialManager/res/values-da/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Annuller"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Fortsæt"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Opret et andet sted"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Gem et andet sted"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Brug en anden enhed"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Gem på en anden enhed"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"En nemmere og mere sikker måde at logge ind på"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Brug dit fingeraftryk, dit ansigt eller din skærmlås for at logge ind med en unik adgangsnøgle, der hverken kan glemmes eller stjæles. Få flere oplysninger"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Vælg, hvor du vil <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"gem din adgangskode"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"gem dine loginoplysninger"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vil du oprette en adgangsnøgle i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vil du gemme din adgangskode i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vil du gemme dine loginoplysninger i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Du kan bruge din <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> på enhver enhed. Den gemmes i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"adgangsnøgle"</string>
+    <string name="password" msgid="6738570945182936667">"adgangskode"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"loginmetoder"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruge <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> til alle dine loginmetoder?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Angiv som standard"</string>
+    <string name="use_once" msgid="9027366575315399714">"Brug én gang"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> adgangskoder, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> adgangsnøgler"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> adgangskoder"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> adgangsnøgler"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"En anden enhed"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Andre adgangskodeadministratorer"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Luk arket"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tilbage til den forrige side"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruge din gemte adgangsnøgle til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruge din gemte loginmetode til <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vælg en gemt loginmetode til <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Log ind på en anden måde"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nej tak"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsæt"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Valgmuligheder for login"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste adgangskodeadministratorer"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tryk for at låse op"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer loginmetoder"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en anden enhed"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Brug en anden enhed"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-de/strings.xml b/packages/CredentialManager/res/values-de/strings.xml
new file mode 100644
index 0000000..fa1e8f1
--- /dev/null
+++ b/packages/CredentialManager/res/values-de/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Anmeldedaten-Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Abbrechen"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Weiter"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"An anderem Speicherort erstellen"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"An anderem Ort speichern"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Anderes Gerät verwenden"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Auf einem anderen Gerät speichern"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Einfach und sicher anmelden"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Verwende deinen Fingerabdruck oder deine Gesichts- bzw. Displaysperre, um dich mit einem eindeutigen Passkey anzumelden, der nicht vergessen oder gestohlen werden kann. Weitere Informationen"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Ort auswählen für: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"Passwort speichern"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"Anmeldedaten speichern"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Passkey hier erstellen: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Passwort hier speichern: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Anmeldedaten hier speichern: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Du kannst <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> auf jedem beliebigen Gerät verwenden. Gespeichert (<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>) für <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"Passkey"</string>
+    <string name="password" msgid="6738570945182936667">"Passwort"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"Anmeldungen"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> für alle Anmeldungen verwenden?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Als Standard festlegen"</string>
+    <string name="use_once" msgid="9027366575315399714">"Einmal verwenden"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> Passwörter, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> Passkeys"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> Passwörter"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> Passkeys"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Ein anderes Gerät"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Andere Passwortmanager"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Tabellenblatt schließen"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Zurück zur vorherigen Seite"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gespeicherten Passkey für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> verwenden?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Gespeicherte Anmeldedaten für <xliff:g id="APP_NAME">%1$s</xliff:g> auswählen"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Andere Anmeldeoption auswählen"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nein danke"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Weiter"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Anmeldeoptionen"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Für <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gesperrte Passwortmanager"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Zum Entsperren tippen"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Anmeldedaten verwalten"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Von einem anderen Gerät"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Anderes Gerät verwenden"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-el/strings.xml b/packages/CredentialManager/res/values-el/strings.xml
new file mode 100644
index 0000000..706d9f3
--- /dev/null
+++ b/packages/CredentialManager/res/values-el/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Ακύρωση"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Συνέχεια"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Δημιουργία σε άλλη θέση"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Αποθήκευση σε άλλη θέση"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Χρήση άλλης συσκευής"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Αποθήκευση σε άλλη συσκευή"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Ένας απλός τρόπος για ασφαλή σύνδεση"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Χρησιμοποιήστε το δακτυλικό αποτύπωμα, το πρόσωπο ή το κλείδωμα οθόνης σας για να συνδεθείτε με ένα μοναδικό κλειδί πρόσβασης που δεν είναι δυνατό να ξεχάσετε ή να κλαπεί. Μάθετε περισσότερα"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Επιλέξτε θέση για <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"αποθήκευση του κωδικού πρόσβασής σας"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"αποθήκευση των στοιχείων σύνδεσής σας"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Να δημιουργηθει κλειδί πρόσβασης στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Να αποθηκευτεί ο κωδικός πρόσβασής σας στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Να αποθηκευτούν τα στοιχεία σύνδεσής σας στο <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>;"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Μπορείτε να χρησιμοποιήσετε το στοιχείο τύπου <xliff:g id="TYPE">%2$s</xliff:g> του τομέα <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> σε οποιαδήποτε συσκευή. Αποθηκεύτηκε στο <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> για <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"κλειδί πρόσβασης"</string>
+    <string name="password" msgid="6738570945182936667">"κωδικός πρόσβασης"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"στοιχεία σύνδεσης"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Να χρησιμοποιηθεί το <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> για όλες τις συνδέσεις σας;"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Ορισμός ως προεπιλογής"</string>
+    <string name="use_once" msgid="9027366575315399714">"Χρήση μία φορά"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> κωδικοί πρόσβασης, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> κλειδιά πρόσβασης"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> κωδικοί πρόσβασης"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> κλειδιά πρόσβασης"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Κλειδί πρόσβασης"</string>
+    <string name="another_device" msgid="5147276802037801217">"Άλλη συσκευή"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Άλλοι διαχειριστές κωδικών πρόσβασης"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Κλείσιμο φύλλου"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Επιστροφή στην προηγούμενη σελίδα"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Να χρησιμοποιηθεί το αποθηκευμένο κλειδί πρόσβασης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Να χρησιμοποιηθούν τα αποθηκευμένα στοιχεία σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>;"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Επιλογή αποθηκευμένων στοιχείων σύνδεσης για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Σύνδεση με άλλον τρόπο"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Όχι, ευχαριστώ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Συνέχεια"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Επιλογές σύνδεσης"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Για τον χρήστη <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Κλειδωμένοι διαχειριστές κωδικών πρόσβασης"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Πατήστε για ξεκλείδωμα"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Διαχείριση στοιχείων σύνδεσης"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Από άλλη συσκευή"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Χρήση διαφορετικής συσκευής"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-en-rAU/strings.xml b/packages/CredentialManager/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..7adeded
--- /dev/null
+++ b/packages/CredentialManager/res/values-en-rAU/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continue"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Set a default password manager to save your passwords and passkeys and sign in faster next time."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Create a passkey in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Save your password to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Save your sign-in info to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Create passkey in"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Save password to"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Save sign-in to"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Use once"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkeys"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Another device"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Other password managers"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No thanks"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tap to unlock"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-en-rCA/strings.xml b/packages/CredentialManager/res/values-en-rCA/strings.xml
new file mode 100644
index 0000000..8a8b884
--- /dev/null
+++ b/packages/CredentialManager/res/values-en-rCA/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continue"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Set a default password manager to save your passwords and passkeys and sign in faster next time."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Create a passkey in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Save your password to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Save your sign-in info to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Create passkey in"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Save password to"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Save sign-in to"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Use once"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkeys"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Another device"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Other password managers"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No thanks"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tap to unlock"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-en-rGB/strings.xml b/packages/CredentialManager/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..7adeded
--- /dev/null
+++ b/packages/CredentialManager/res/values-en-rGB/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continue"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Set a default password manager to save your passwords and passkeys and sign in faster next time."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Create a passkey in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Save your password to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Save your sign-in info to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Create passkey in"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Save password to"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Save sign-in to"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Use once"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkeys"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Another device"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Other password managers"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No thanks"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tap to unlock"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-en-rIN/strings.xml b/packages/CredentialManager/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..7adeded
--- /dev/null
+++ b/packages/CredentialManager/res/values-en-rIN/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancel"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continue"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Create in another place"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Save to another place"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Use another device"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Save to another device"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"A simple way to sign in safely"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choose where to <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"create your passkeys"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"save your password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"save your sign-in info"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Set a default password manager to save your passwords and passkeys and sign in faster next time."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Create a passkey in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Save your password to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Save your sign-in info to <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"You can use your <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> on any device. It is saved to <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sign-ins"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Create passkey in"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Save password to"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Save sign-in to"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Create a passkey in another device?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Use <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for all your sign-ins?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"This password manager will store your passwords and passkeys to help you easily sign in."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Set as default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Use once"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkeys"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passwords"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkeys"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Another device"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Other password managers"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Close sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Go back to the previous page"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Use your saved passkey for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Use your saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choose a saved sign-in for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Sign in another way"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No thanks"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continue"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sign-in options"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Locked password managers"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tap to unlock"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Manage sign-ins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"From another device"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use a different device"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-en-rXC/strings.xml b/packages/CredentialManager/res/values-en-rXC/strings.xml
new file mode 100644
index 0000000..85e94df
--- /dev/null
+++ b/packages/CredentialManager/res/values-en-rXC/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‎‎‎‎‎‏‎‏‏‎‎‏‎‏‎‎‏‎‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎Credential Manager‎‏‎‎‏‎"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‎‎‏‏‏‎‏‏‎‏‎‏‎‎‏‎‏‎‎‎‏‎‎‏‎‏‏‏‏‏‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‏‏‏‏‎Cancel‎‏‎‎‏‎"</string>
+    <string name="string_continue" msgid="1346732695941131882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‎‏‎‎‎‏‏‏‎‎‏‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‏‏‏‎‎‏‏‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‎Continue‎‏‎‎‏‎"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‏‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‏‎‎‎‎‏‎‎‎‎‏‎‎‎‎‎‏‎‎‎‏‏‎Create in another place‎‏‎‎‏‎"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‎‎‎‎‏‎‎‏‏‏‎‎‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‎‎‏‏‏‎‎‏‏‎‎‎‏‏‎‎‏‎Save to another place‎‏‎‎‏‎"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‏‏‎‎‎‏‎‎‏‎‎‎‎‎‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎Use another device‎‏‎‎‏‎"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‎‏‏‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‏‎‏‏‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‎Save to another device‎‏‎‎‏‎"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‎‏‏‎‎‏‎‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎A simple way to sign in safely‎‏‎‎‏‎"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‏‎‏‎‎‎‎‎‎‏‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‎‏‏‏‎‎‏‎‎‎‎‏‏‎‏‎‎Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more‎‏‎‎‏‎"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‎‎‎‎‎‏‎‏‏‎‏‎‎‏‏‏‎‏‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‏‏‎‎‎Choose where to ‎‏‎‎‏‏‎<xliff:g id="CREATETYPES">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‎‎‏‏‏‏‎‎‎‎‎‎‎‎‎‏‏‎‏‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‏‏‎‎‎‏‎‎‎create your passkeys‎‏‎‎‏‎"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‎save your password‎‏‎‎‏‎"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‏‎‏‎‎‏‏‎‎‏‎‏‏‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‎‎‏‎‎‏‎‎‏‎‎save your sign-in info‎‏‎‎‏‎"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‎‏‎‎‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‏‎‏‎‏‎‏‏‏‏‏‎‏‎‏‏‎‏‏‎Set a default password manager to save your passwords and passkeys and sign in faster next time.‎‏‎‎‏‎"</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‏‎‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‎‎‎‏‎‎‎‎‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‏‎‎‏‎‏‏‎Create a passkey in ‎‏‎‎‏‏‎<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‏‎‎‏‏‎‎‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‏‎‎‎‏‎‎‎‏‎‏‏‏‎‎‎‎‎‏‎Save your password to ‎‏‎‎‏‏‎<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‏‏‏‎‎‏‏‎‏‏‎‎‎‏‎‎‎‎‎‏‏‏‎‏‎‏‎‎‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎Save your sign-in info to ‎‏‎‎‏‏‎<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‏‎‏‎‎‎‎‎‎‏‏‎‏‎‏‏‎‏‏‏‎‏‏‎‏‎‎‎‏‎‎‎‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‏‎‎‎‎‏‎You can use your ‎‏‎‎‏‏‎<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ ‎‏‎‎‏‏‎<xliff:g id="TYPE">%2$s</xliff:g>‎‏‎‎‏‏‏‎ on any device. It is saved to ‎‏‎‎‏‏‎<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>‎‏‎‎‏‏‏‎ for ‎‏‎‎‏‏‎<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="passkey" msgid="632353688396759522">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‎‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‏‏‎‎‎‎‎‎‎‎‎‏‏‏‏‎‎‎‏‎‎passkey‎‏‎‎‏‎"</string>
+    <string name="password" msgid="6738570945182936667">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‎‎‏‏‎‏‏‎‏‎‎‏‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‏‏‎password‎‏‎‎‏‎"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‎‏‎‏‏‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‎‏‏‎‎‎‎sign-ins‎‏‎‎‏‎"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‏‎‏‎‏‏‎‎‏‎‎‏‏‏‎‏‏‏‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎‏‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‏‎Create passkey in‎‏‎‎‏‎"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‏‏‏‎‎‏‏‏‎‎‏‏‎‏‏‎‏‎‏‎Save password to‎‏‎‎‏‎"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‎‏‏‏‎‎‎‎‎‏‎‎‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‎‏‎‏‎‏‏‎‏‎‎‎‎Save sign-in to‎‏‎‎‏‎"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‎‎‏‏‎‎‏‏‏‏‏‏‏‎‎‏‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‎‏‎‎‏‎‎‏‎‎‎‎Create a passkey in another device?‎‏‎‎‏‎"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎‏‏‎‎‏‏‏‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‏‏‏‏‎‎‏‎‏‎‏‎Use ‎‏‎‎‏‏‎<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ for all your sign-ins?‎‏‎‎‏‎"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‏‎‏‏‏‏‏‎‏‎‎‎‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‎‏‎‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‏‏‏‏‎‎‎This password manager will store your passwords and passkeys to help you easily sign in.‎‏‎‎‏‎"</string>
+    <string name="set_as_default" msgid="4415328591568654603">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‏‎‎‎‏‏‎‎‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‏‏‏‎‏‎‏‏‎‎‎‏‎‎‏‏‎‏‎‏‎‎‎‏‎‎‎‎‏‎‏‏‎Set as default‎‏‎‎‏‎"</string>
+    <string name="use_once" msgid="9027366575315399714">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‎‎‏‏‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‏‎‎‎‎‏‎‎‎‏‎‎Use once‎‏‎‎‏‎"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‏‎‎‎‏‎‏‎‏‏‏‎‏‎‏‏‏‏‎‎‎‎‏‏‎‏‏‏‏‏‎‎‎‏‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ passwords, ‎‏‎‎‏‏‎<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>‎‏‎‎‏‏‏‎ passkeys‎‏‎‎‏‎"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‏‎‏‎‏‎‎‏‏‎‎‎‏‏‎‎‏‎‎‏‎‏‏‎‏‎‎‎‏‎‎‏‎‏‎‏‎‏‎‏‎‏‎‏‏‏‏‎‏‎‎‏‏‎‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ passwords‎‏‎‎‏‎"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‏‏‎‎‏‏‎‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>‎‏‎‎‏‏‏‎ passkeys‎‏‎‎‏‎"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‎‎‎‏‏‏‏‏‏‎‎‏‎‏‏‏‎‏‏‏‏‎‏‎‏‏‎‎‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‏‏‎‏‎‏‎‎‎‏‎‏‎‎‎Passkey‎‏‎‎‏‎"</string>
+    <string name="another_device" msgid="5147276802037801217">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‏‎‏‏‏‎‎‎‏‎‎‎‎‏‎‎‏‎‎‏‏‎‎‎‎‏‎‎‎‎‎‎‎‏‎Another device‎‏‎‎‏‎"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‎‎‏‎‏‏‏‎‎‏‏‎‏‎‏‎‏‏‎‏‏‎‏‏‎‎‎‏‎‏‏‏‏‎‏‎‎‏‎‏‏‏‎‏‏‎‏‎Other password managers‎‏‎‎‏‎"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎Close sheet‎‏‎‎‏‎"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‎‏‏‎‏‏‏‏‎‏‎‏‎‎‎‎‎‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‏‏‏‏‏‏‎‎‏‏‏‏‎‎‎Go back to the previous page‎‏‎‎‏‎"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‏‎‏‎‎‎‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‎Use your saved passkey for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‏‎‏‎‏‎‎‎‏‎‏‎‏‎‏‏‏‎‎‎‎‎‏‏‏‏‏‎‎‏‏‏‎‎‎‎‎‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‎‏‎‎‎Use your saved sign-in for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎?‎‏‎‎‏‎"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‎‎‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‎‏‎‏‏‎‎‏‎‏‏‎‎‏‎‏‎‎‎‎‏‎‏‎Choose a saved sign-in for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‏‎‎‎‏‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‎‎‎‎‎Sign in another way‎‏‎‎‏‎"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‏‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‏‎‎‏‎‎‎‏‏‏‏‎‏‏‏‏‎‏‏‎‏‏‎‏‏‎‏‎‏‎‎‎‏‎‏‎No thanks‎‏‎‎‏‎"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‎‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‏‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‏‏‏‏‎‎Continue‎‏‎‎‏‎"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‎‎‎‎‏‎‎‏‎‏‎‏‎‏‏‎‏‎‏‎‎‏‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‏‎‎Sign-in options‎‏‎‎‏‎"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‏‏‎‎‏‎‏‎‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‎‏‎‎‏‏‎‏‎‎‎‎For ‎‏‎‎‏‏‎<xliff:g id="USERNAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‏‏‎‏‏‏‎‏‏‏‏‏‎‎‎‏‎‏‏‏‏‎‎‎‎‏‏‎‎‏‎‎‎Locked password managers‎‏‎‎‏‎"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‏‎‏‏‏‎‎‏‏‎‎‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‎Tap to unlock‎‏‎‎‏‎"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‏‎‎‎‏‎‏‎‏‎‎‎‏‎‎‏‏‏‎‎‏‏‏‎‏‏‏‎‎‏‏‏‏‎‎‎‎‏‏‏‏‎‎‎‏‏‏‎‏‎‏‏‏‎‎Manage sign-ins‎‏‎‎‏‎"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‎‎‏‏‎‎‎‎‎‏‎‏‏‎‏‏‎‏‏‎‎‏‎‎‏‏‏‏‏‎‏‏‎‏‏‏‏‎‏‎‎‎‎From another device‎‏‎‎‏‎"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‎‎‎‏‏‏‎‏‏‏‎‎‎‏‏‏‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‏‎‏‎‏‎‎‏‎‏‏‏‏‎‏‎Use a different device‎‏‎‎‏‎"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-es-rUS/strings.xml b/packages/CredentialManager/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..5b8e442
--- /dev/null
+++ b/packages/CredentialManager/res/values-es-rUS/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear en otra ubicación"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otra ubicación"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un modo simple y seguro de ingresar"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa tu huella dactilar, tu rostro o el bloqueo de pantalla para acceder con una llave de acceso única que no olvidarás ni podrán robarte. Más información"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de acceso"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"¿Quieres crear una llave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"¿Quieres guardar tu contraseña de <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"¿Quieres guardar tu información de acceso a <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Puedes usar tu <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> en cualquier dispositivo. Se guardó en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
+    <string name="password" msgid="6738570945182936667">"contraseña"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"accesos"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Quieres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus accesos?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> llaves de acceso, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> contraseñas"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> llaves de acceso"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Llave de acceso"</string>
+    <string name="another_device" msgid="5147276802037801217">"Otro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Otros administradores de contraseñas"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Cerrar hoja"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver a la página anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Quieres usar tu llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Quieres usar tu acceso guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Elige un acceso guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Acceder de otra forma"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No, gracias"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opciones de acceso"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Administradores de contraseñas bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Presiona para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrar accesos"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Desde otro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otra voz"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-es/strings.xml b/packages/CredentialManager/res/values-es/strings.xml
new file mode 100644
index 0000000..19fde72
--- /dev/null
+++ b/packages/CredentialManager/res/values-es/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear en otro lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar en otro lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar otro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar en otro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Una forma sencilla y segura de iniciar sesión"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa la huella digital, la cara o el bloqueo de pantalla para iniciar sesión con una llave de acceso única que no se puede olvidar ni robar. Más información"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Elige dónde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"guardar tu contraseña"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar tu información de inicio de sesión"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"¿Crear una llave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"¿Guardar tu contraseña en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"¿Guardar tu información de inicio de sesión en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Puedes usar tu <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> en cualquier dispositivo. Se guarda en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"llave de acceso"</string>
+    <string name="password" msgid="6738570945182936667">"contraseña"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"inicios de sesión"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"¿Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos tus inicios de sesión?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Fijar como predeterminado"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar una vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> llaves de acceso"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contraseñas"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> llaves de acceso"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Otro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Otros gestores de contraseñas"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Cerrar hoja"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver a la página anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"¿Usar la llave de acceso guardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"¿Usar el inicio de sesión guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Elige un inicio de sesión guardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sesión de otra manera"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No, gracias"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opciones de inicio de sesión"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestores de contraseñas bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toca para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionar inicios de sesión"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De otro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar otro dispositivo"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-et/strings.xml b/packages/CredentialManager/res/values-et/strings.xml
new file mode 100644
index 0000000..5b1b070
--- /dev/null
+++ b/packages/CredentialManager/res/values-et/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Tühista"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Jätka"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Loo teises kohas"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvesta teise kohta"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Kasuta teist seadet"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvesta teise seadmesse"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Lihtne viis turvaliselt sisselogimiseks"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Kasutage sõrmejälge, nägu või ekraanilukku, et logida sisse unikaalse pääsuvõtmega, mida ei saa unustada ega varastada. Lisateave"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Valige, kus <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"parool salvestada"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"sisselogimisandmed salvestada"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kas luua teenuses <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pääsuvõti?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Kas salvestada parool teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Kas salvestada sisselogimisteave teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Saate rakendust <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> kasutada mis tahes seadmes. Salvestatakse teenusesse <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> – <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"pääsukood"</string>
+    <string name="password" msgid="6738570945182936667">"parool"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sisselogimisandmed"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Kas kasutada teenust <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kõigi teie sisselogimisandmete puhul?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Määra vaikeseadeks"</string>
+    <string name="use_once" msgid="9027366575315399714">"Kasuta ühe korra"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parooli, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> pääsuvõtit"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parooli"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> pääsuvõtit"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Teine seade"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Muud paroolihaldurid"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Sule leht"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Minge tagasi eelmisele lehele"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud pääsuvõtit?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Kas kasutada rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud sisselogimisandmeid?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Valige rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> jaoks salvestatud sisselogimisandmed"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Logige sisse muul viisil"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Tänan, ei"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Jätka"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Sisselogimise valikud"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Kasutajale <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukustatud paroolihaldurid"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Avamiseks puudutage"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Sisselogimisandmete haldamine"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Muus seadmes"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Kasuta teist seadet"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-eu/strings.xml b/packages/CredentialManager/res/values-eu/strings.xml
new file mode 100644
index 0000000..b2c1fe5
--- /dev/null
+++ b/packages/CredentialManager/res/values-eu/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Utzi"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Egin aurrera"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Sortu beste toki batean"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Gorde beste toki batean"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Erabili beste gailu bat"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Gorde beste gailu batean"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Segurtasun osoz saioa hasteko modu erraza"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Erabili hatz-marka, aurpegia edo pantailaren blokeoa ahaztu edo lapurtu ezin den sarbide-gako baten bidez saioa hasteko. Lortu informazio gehiago"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Aukeratu non <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"gorde pasahitza"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"gorde kredentzialei buruzko informazioa"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Sarbide-gako bat sortu nahi duzu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Pasahitza <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan gorde nahi duzu?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Kredentzialei buruzko informazioa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> aplikazioan gorde nahi duzu?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> aplikazioko <xliff:g id="TYPE">%2$s</xliff:g> edozein gailutan erabil dezakezu. <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> aplikazioan dago gordeta (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)."</string>
+    <string name="passkey" msgid="632353688396759522">"sarbide-gakoa"</string>
+    <string name="password" msgid="6738570945182936667">"pasahitza"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"kredentzialak"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> erabili nahi duzu kredentzial guztietarako?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Ezarri lehenetsi gisa"</string>
+    <string name="use_once" msgid="9027366575315399714">"Erabili behin"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> pasahitz eta <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> sarbide-gako"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> pasahitz"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> sarbide-gako"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Beste gailu bat"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Beste pasahitz-kudeatzaile batzuk"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Itxi orria"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Itzuli aurreko orrira"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde duzun sarbide-gakoa erabili nahi duzu?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde dituzun kredentzialak erabili nahi dituzu?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Aukeratu <xliff:g id="APP_NAME">%1$s</xliff:g> aplikaziorako gorde dituzun kredentzialak"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Hasi saioa beste modu batean"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ez, eskerrik asko"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Egin aurrera"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Saioa hasteko aukerak"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> erabiltzailearenak"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Blokeatutako pasahitz-kudeatzaileak"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Desblokeatzeko, sakatu hau"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kudeatu kredentzialak"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Beste gailu batean gordetakoak"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Erabili beste gailu bat"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-fa/strings.xml b/packages/CredentialManager/res/values-fa/strings.xml
new file mode 100644
index 0000000..98b487c
--- /dev/null
+++ b/packages/CredentialManager/res/values-fa/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"لغو"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ادامه"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"ایجاد در مکانی دیگر"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"ذخیره در مکانی دیگر"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"استفاده از دستگاهی دیگر"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ذخیره در دستگاهی دیگر"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"روشی ساده برای ورود به سیستم ایمن"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"برای ورود به سیستم با گذرکلیدی یکتا که غیرقابل فراموش شدن یا دزدیده شدن باشد، از اثر انگشت، چهره، یا قفل صفحه استفاده کنید. بیشتر بدانید"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"انتخاب محل <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ذخیره گذرواژه"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ذخیره اطلاعات ورود به سیستم"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"گذرکلید در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ایجاد شود؟"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"گذرواژه در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ذخیره شود؟"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"اطلاعات ورود به سیستم در <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ذخیره شود؟"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"می‌توانید از <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> در هر دستگاهی استفاده کنید. در <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> برای <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ذخیره می‌شود"</string>
+    <string name="passkey" msgid="632353688396759522">"گذرکلید"</string>
+    <string name="password" msgid="6738570945182936667">"گذرواژه"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ورود به سیستم‌ها"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"از <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> برای همه ورود به سیستم‌ها استفاده شود؟"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"تنظیم به‌عنوان پیش‌فرض"</string>
+    <string name="use_once" msgid="9027366575315399714">"یک‌بار استفاده"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه، <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> گذرکلید"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> گذرواژه"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> گذرکلید"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"دستگاهی دیگر"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"دیگر مدیران گذرواژه"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"بستن برگ"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"برگشتن به صفحه قبلی"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"گذرکلید ذخیره‌شده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ورود به سیستم ذخیره‌شده برای <xliff:g id="APP_NAME">%1$s</xliff:g> استفاده شود؟"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"انتخاب ورود به سیستم ذخیره‌شده برای <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ورود به سیستم به روشی دیگر"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"نه متشکرم"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ادامه"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"گزینه‌های ورود به سیستم"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"برای <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مدیران گذرواژه قفل‌شده"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"برای باز کردن قفل ضربه بزنید"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"مدیریت ورود به سیستم‌ها"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"از دستگاهی دیگر"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"استفاده از دستگاه دیگری"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-fi/strings.xml b/packages/CredentialManager/res/values-fi/strings.xml
new file mode 100644
index 0000000..9ad178a
--- /dev/null
+++ b/packages/CredentialManager/res/values-fi/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Peru"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Jatka"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Luo muualla"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Tallenna muualle"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Käytä toista laitetta"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Tallenna toiselle laitteelle"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Helppo tapa kirjautua turvallisesti sisään"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Käytä sormenjälkeä, kasvoja tai näytön lukitusta, niin voit kirjautua sisään yksilöllisellä avainkoodilla, jota ei voi unohtaa tai varastaa. Lue lisää"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Valitse paikka: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"tallenna salasanasi"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"tallenna kirjautumistiedot"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Luodaanko avainkoodi (<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>)?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Tallennetaanko salasanasi tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Tallennetaanko kirjautumistietosi tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> (<xliff:g id="TYPE">%2$s</xliff:g>) on käytettävissä millä tahansa laitteella. Se tallennetaan tänne: <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)"</string>
+    <string name="passkey" msgid="632353688396759522">"avainkoodi"</string>
+    <string name="password" msgid="6738570945182936667">"salasana"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"sisäänkirjautumiset"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Otetaanko <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> käyttöön kaikissa sisäänkirjautumisissa?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Aseta oletukseksi"</string>
+    <string name="use_once" msgid="9027366575315399714">"Käytä kerran"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> salasanaa, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> avainkoodia"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> salasanaa"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> avainkoodia"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Toinen laite"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Muut salasanojen ylläpitotyökalut"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Sulje taulukko"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Takaisin edelliselle sivulle"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Käytetäänkö tallennettua avainkoodiasi täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Käytetäänkö tallennettuja kirjautumistietoja täällä: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Valitse tallennetut kirjautumistiedot (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Kirjaudu sisään toisella tavalla"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ei kiitos"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Jatka"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Kirjautumisvaihtoehdot"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Käyttäjä: <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Lukitut salasanojen ylläpitotyökalut"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Avaa napauttamalla"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Muuta kirjautumistietoja"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Toiselta laitteelta"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Käytä toista laitetta"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-fr-rCA/strings.xml b/packages/CredentialManager/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..a2e7581
--- /dev/null
+++ b/packages/CredentialManager/res/values-fr-rCA/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Gestionnaire d\'identifiants"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Annuler"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuer"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Créer à un autre emplacement"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer à un autre emplacement"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Une manière simple de se connecter en toute sécurité"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilisez vos empreintes digitales, votre visage ou un écran de verrouillage pour vous connecter avec une clé d\'accès unique qui ne peut pas être oubliée ou volée. En savoir plus"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos données de connexion"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Créer une clé d\'accès dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Enregistrer votre mot de passe dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Enregistrer vos données de connexion dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Vous pouvez utiliser votre <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> sur n\'importe quel appareil. Il est enregistré sur <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pour <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
+    <string name="password" msgid="6738570945182936667">"mot de passe"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
+    <string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> clés d\'accès"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Clé d\'accès"</string>
+    <string name="another_device" msgid="5147276802037801217">"Un autre appareil"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Autres gestionnaires de mots de passe"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Fermer la feuille"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Retourner à la page précédente"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser votre connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choisir une connexion enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Se connecter d\'une autre manière"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Non merci"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuer"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Options de connexion"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestionnaires de mots de passe verrouillés"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toucher pour déverrouiller"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gérer les connexions"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"À partir d\'un autre appareil"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-fr/strings.xml b/packages/CredentialManager/res/values-fr/strings.xml
new file mode 100644
index 0000000..2b280fb
--- /dev/null
+++ b/packages/CredentialManager/res/values-fr/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Gestionnaire d\'identifiants"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Annuler"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuer"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Créer ailleurs"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Enregistrer ailleurs"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Utiliser un autre appareil"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Enregistrer sur un autre appareil"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Une façon simple et sécurisée de vous connecter"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Utilisez votre empreinte digitale, votre visage ou le verrouillage de l\'écran pour vous connecter avec une clé d\'accès unique que vous ne pourrez pas oublier ni vous faire voler. En savoir plus"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Choisir où <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"enregistrer votre mot de passe"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"enregistrer vos informations de connexion"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Créer une clé d\'accès dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Enregistrer votre mot de passe dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Enregistrer vos informations de connexion dans <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Vous pouvez utiliser votre <xliff:g id="TYPE">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> sur n\'importe quel appareil. Il est enregistré dans <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pour <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"clé d\'accès"</string>
+    <string name="password" msgid="6738570945182936667">"mot de passe"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"connexions"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Utiliser <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pour toutes vos connexions ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Définir par défaut"</string>
+    <string name="use_once" msgid="9027366575315399714">"Utiliser une fois"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> clés d\'accès"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mots de passe"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> clés d\'accès"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Clé d\'accès"</string>
+    <string name="another_device" msgid="5147276802037801217">"Un autre appareil"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Autres gestionnaires de mots de passe"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Fermer la feuille"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Revenir à la page précédente"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Utiliser votre clé d\'accès enregistrée pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Utiliser vos informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g> ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Choisir des informations de connexion enregistrées pour <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Se connecter d\'une autre manière"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Non, merci"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuer"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Options de connexion"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pour <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestionnaires de mots de passe verrouillés"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Appuyer pour déverrouiller"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gérer les connexions"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Depuis un autre appareil"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Utiliser un autre appareil"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-gl/strings.xml b/packages/CredentialManager/res/values-gl/strings.xml
new file mode 100644
index 0000000..cc03ca4
--- /dev/null
+++ b/packages/CredentialManager/res/values-gl/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Xestor de credenciais"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Crear noutro lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Gardar noutro lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Gardar noutro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un xeito fácil de iniciar sesión de forma segura"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa a impresión dixital, a cara ou o bloqueo de pantalla para iniciar sesión cunha clave de acceso única que non podes esquecer nin cha poden roubar. Máis información"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Escolle onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"gardar o contrasinal"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"gardar a información de inicio de sesión"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Queres crear unha clave de acceso en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Queres gardar o contrasinal en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Queres gardar a información de inicio de sesión en <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Podes usar o teu <xliff:g id="TYPE">%2$s</xliff:g> de <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> en calquera dispositivo. Está gardado en <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"clave de acceso"</string>
+    <string name="password" msgid="6738570945182936667">"contrasinal"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"métodos de inicio de sesión"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Queres usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cada vez que inicies sesión?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Establecer como predeterminado"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar unha vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasinais, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> claves de acceso"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> contrasinais"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> claves de acceso"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Clave de acceso"</string>
+    <string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Outros xestores de contrasinais"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Pechar folla"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volver á páxina anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Queres usar a clave de acceso gardada para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Queres usar o método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolle un método de inicio de sesión gardado para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sesión doutra forma"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Non, grazas"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcións de inicio de sesión"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Xestores de contrasinais bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toca para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Xestionar os métodos de inicio de sesión"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Doutro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar outro dispositivo"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-gu/strings.xml b/packages/CredentialManager/res/values-gu/strings.xml
new file mode 100644
index 0000000..f796d20
--- /dev/null
+++ b/packages/CredentialManager/res/values-gu/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"લૉગ ઇન વિગતોના મેનેજર"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"રદ કરો"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ચાલુ રાખો"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"કોઈ અન્ય સ્થાન પર બનાવો"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"કોઈ અન્ય સ્થાન પર સાચવો"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"અન્ય ડિવાઇસ પર સાચવો"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"સલામત રીતે સાઇન ઇન કરવાની સરળ રીત"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ભૂલી ન શકાય કે ચોરાઈ ન જાય, તેવી કોઈ વિશિષ્ટ પાસકી વડે સાઇન ઇન કરવા માટે, તમારી ફિંગરપ્રિન્ટ, ચહેરો અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો. વધુ જાણો"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ક્યાં સાચવવી છે, તે પસંદ કરો"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"તમારો પાસવર્ડ સાચવો"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"તમારી સાઇન-ઇનની માહિતી સાચવો"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"શું <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં કોઈ પાસકી બનાવીએ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"શું તમારો પાસવર્ડ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં સાચવીએ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"શું તમારી સાઇન-ઇનની માહિતી <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>માં સાચવીએ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"તમે કોઈપણ ડિવાઇસ પર તમારા <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>નો ઉપયોગ કરી શકો છો. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> માટે <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>માં તેને સાચવવામાં આવે છે"</string>
+    <string name="passkey" msgid="632353688396759522">"પાસકી"</string>
+    <string name="password" msgid="6738570945182936667">"પાસવર્ડ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"સાઇન-ઇન"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"શું તમારા બધા સાઇન-ઇન માટે <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>નો ઉપયોગ કરીએ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ડિફૉલ્ટ તરીકે સેટ કરો"</string>
+    <string name="use_once" msgid="9027366575315399714">"એકવાર ઉપયોગ કરો"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> પાસવર્ડ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> પાસકી"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> પાસવર્ડ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> પાસકી"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"પાસકી"</string>
+    <string name="another_device" msgid="5147276802037801217">"કોઈ અન્ય ડિવાઇસ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"અન્ય પાસવર્ડ મેનેજર"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"શીટ બંધ કરો"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"પાછલા પેજ પર પરત જાઓ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારી સાચવેલી પાસકીનો ઉપયોગ કરીએ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે શું તમારા સાચવેલા સાઇન-ઇનનો ઉપયોગ કરીએ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> માટે કોઈ સાચવેલું સાઇન-ઇન પસંદ કરો"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"કોઈ અન્ય રીતે સાઇન ઇન કરો"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ના, આભાર"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ચાલુ રાખો"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"સાઇન-ઇનના વિકલ્પો"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> માટે"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"લૉક કરેલા પાસવર્ડ મેનેજર"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"અનલૉક કરવા માટે ટૅપ કરો"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"સાઇન-ઇન મેનેજ કરો"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"કોઈ અન્ય ડિવાઇસમાંથી"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"કોઈ અન્ય ડિવાઇસનો ઉપયોગ કરો"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-hi/strings.xml b/packages/CredentialManager/res/values-hi/strings.xml
new file mode 100644
index 0000000..fbf1c02
--- /dev/null
+++ b/packages/CredentialManager/res/values-hi/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"रद्द करें"</string>
+    <string name="string_continue" msgid="1346732695941131882">"जारी रखें"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"दूसरी जगह पर बनाएं"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"दूसरी जगह पर सेव करें"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"दूसरे डिवाइस का इस्तेमाल करें"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"दूसरे डिवाइस पर सेव करें"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षित तरीके से साइन इन करने का आसान तरीका"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"साइन इन करने के लिए फ़िंगरप्रिंट, फ़ेस या स्क्रीन लॉक जैसी यूनीक पासकी का इस्तेमाल करें. इन्हें, न तो भुलाया जा सकता है न ही चुराया जा सकता है. ज़्यादा जानें"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"चुनें कि <xliff:g id="CREATETYPES">%1$s</xliff:g> कहां पर सेव करना है"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"अपना पासवर्ड सेव करें"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"साइन इन से जुड़ी अपनी जानकारी सेव करें"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"क्या आपको <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में पासकी बनानी है?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"क्या आपको अपना पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में सेव करना है?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"क्या आपको साइन इन करने से जुड़ी जानकारी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> में सेव करनी है?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"अपना <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> किसी भी डिवाइस पर इस्तेमाल किया जा सकता है. इसे <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> के लिए, <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> में सेव किया जाता है"</string>
+    <string name="passkey" msgid="632353688396759522">"पासकी"</string>
+    <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"साइन इन"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"क्या आपको साइन इन से जुड़ी सारी जानकारी सेव करने के लिए, <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> का इस्तेमाल करना है?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"डिफ़ॉल्ट के तौर पर सेट करें"</string>
+    <string name="use_once" msgid="9027366575315399714">"इसका इस्तेमाल एक बार किया जा सकता है"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड और <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> पासकी"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"दूसरा डिवाइस"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"दूसरे पासवर्ड मैनेजर"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"शीट बंद करें"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"पिछले पेज पर वापस जाएं"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई पासकी का इस्तेमाल करना है?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"क्या आपको <xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई जानकारी का इस्तेमाल करना है?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> पर साइन इन करने के लिए, सेव की गई जानकारी में से चुनें"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"किसी दूसरे तरीके से साइन इन करें"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"रहने दें"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"जारी रखें"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन करने के विकल्प"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> के लिए"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक किए गए पासवर्ड मैनेजर"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"अनलॉक करने के लिए टैप करें"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इन करने की सुविधा को मैनेज करें"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"किसी दूसरे डिवाइस से"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"दूसरे डिवाइस का इस्तेमाल करें"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-hr/strings.xml b/packages/CredentialManager/res/values-hr/strings.xml
new file mode 100644
index 0000000..6c1952f
--- /dev/null
+++ b/packages/CredentialManager/res/values-hr/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Odustani"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Nastavi"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Izradi na drugom mjestu"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Spremi na drugom mjestu"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Upotrijebite neki drugi uređaj"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Spremi na drugi uređaj"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednostavan način za sigurnu prijavu"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Prijavite se otiskom prsta, licem ili zaključavanjem zaslona kao jedinstvenim pristupnim ključem koji je nemoguće zaboraviti ili ukrasti. Saznajte više"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Odaberite mjesto za sljedeće: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"spremi zaporku"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"spremi podatke za prijavu"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite li izraditi pristupni ključ na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite li spremiti zaporku na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite li spremiti podatke o prijavi na usluzi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Aplikaciju <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> možete upotrijebiti na bilo kojem uređaju. Sprema se na uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> za: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"pristupni ključ"</string>
+    <string name="password" msgid="6738570945182936667">"zaporka"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite li upotrebljavati uslugu <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> za sve prijave?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Postavi kao zadano"</string>
+    <string name="use_once" msgid="9027366575315399714">"Upotrijebi jednom"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Broj zaporki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Broj zaporki: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Broj pristupnih ključeva: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Drugi uređaj"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji zaporki"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zatvaranje lista"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vratite se na prethodnu stranicu"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite li upotrijebiti spremljeni pristupni ključ za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite li upotrijebiti spremljene podatke za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Odaberite spremljene podatke za prijavu za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijavite se na neki drugi način"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, hvala"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Nastavi"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcije prijave"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za korisnika <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Upravitelji zaključanih zaporki"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Dodirnite za otključavanje"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljanje prijavama"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na drugom uređaju"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Upotrijebite drugi uređaj"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-hu/strings.xml b/packages/CredentialManager/res/values-hu/strings.xml
new file mode 100644
index 0000000..0efa3e8
--- /dev/null
+++ b/packages/CredentialManager/res/values-hu/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Tanúsítványkezelő"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Mégse"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Folytatás"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Létrehozás másik helyen"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Mentés másik helyre"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Másik eszköz használata"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Mentés másik eszközre"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"A biztonságos bejelentkezés egyszerű módja"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Ujjlenyomatát, arcát vagy képernyőzárát használva egyedi azonosítókulccsal jelentkezhet be, amelyet nem lehet elfelejteni vagy ellopni. További információ."</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Válassza ki a(z) <xliff:g id="CREATETYPES">%1$s</xliff:g> helyét"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"jelszó mentése"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"bejelentkezési adatok mentése"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Létrehoz azonosítókulcsot a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásban?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Menti jelszavát a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásba?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Menti bejelentkezési adatait a(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> szolgáltatásba?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"A(z) <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> bármilyen eszközön használható. A(z) <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> szolgáltatásba van mentve a következő számára: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"azonosítókulcs"</string>
+    <string name="password" msgid="6738570945182936667">"jelszó"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"bejelentkezési adatok"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Szeretné a következőt használni az összes bejelentkezési adatához: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Beállítás alapértelmezettként"</string>
+    <string name="use_once" msgid="9027366575315399714">"Egyszeri használat"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> jelszó, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> azonosítókulcs"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> jelszó"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> azonosítókulcs"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Azonosítókulcs"</string>
+    <string name="another_device" msgid="5147276802037801217">"Másik eszköz"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Egyéb jelszókezelők"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Munkalap bezárása"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Vissza az előző oldalra"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett azonosítókulcsot használni?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Szeretné a(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazáshoz mentett bejelentkezési adatait használni?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Mentett bejelentkezési adatok választása a következő számára: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Bejelentkezés más módon"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Most nem"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Folytatás"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Bejelentkezési beállítások"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zárolt jelszókezelők"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Koppintson a feloldáshoz"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Bejelentkezési adatok kezelése"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Másik eszközről"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Másik eszköz használata"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-hy/strings.xml b/packages/CredentialManager/res/values-hy/strings.xml
new file mode 100644
index 0000000..de47e9f
--- /dev/null
+++ b/packages/CredentialManager/res/values-hy/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Չեղարկել"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Շարունակել"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Ստեղծել այլ տեղում"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Պահել այլ տեղում"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Օգտագործել այլ սարք"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Պահել մեկ այլ սարքում"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Մուտք գործելու անվտանգ և պարզ եղանակ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Օգտագործեք ձեր մատնահետքը, դեմքը կամ էկրանի կողպումը՝ մուտք գործելու հաշիվ եզակի անցաբառի միջոցով, որը հնարավոր չէ կոտրել կամ մոռանալ։ Իմանալ ավելին"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Ընտրեք, թե որտեղ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"պահել գաղտնաբառը"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"պահել մուտքի տվյալները"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Ստեղծե՞լ անցաբառ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Պահե՞լ ձեր գաղտնաբառը <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Պահե՞լ ձեր մուտքի տվյալները <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածում"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Դուք կարող եք օգտագործել <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ցանկացած սարքում։ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-ի տվյալները պահված են <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> հավելվածում։"</string>
+    <string name="passkey" msgid="632353688396759522">"անցաբառ"</string>
+    <string name="password" msgid="6738570945182936667">"գաղտնաբառ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"մուտք"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Միշտ մուտք գործե՞լ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> հավելվածի միջոցով"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Նշել որպես կանխադրված"</string>
+    <string name="use_once" msgid="9027366575315399714">"Օգտագործել մեկ անգամ"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> անցաբառ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> գաղտնաբառ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> անցաբառ"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Այլ սարք"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Գաղտնաբառերի այլ կառավարիչներ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Փակել թերթը"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Անցնել նախորդ էջ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Օգտագործե՞լ պահված անցաբառը <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Օգտագործե՞լ մուտքի պահված տվյալները <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Ընտրեք մուտքի պահված տվյալներ <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի համար"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Մուտք գործել այլ եղանակով"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ոչ, շնորհակալություն"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Շարունակել"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Մուտքի տարբերակներ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-ի համար"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Գաղտնաբառերի կողպված կառավարիչներ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Հպեք՝ ապակողպելու համար"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Մուտքի կառավարում"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Մեկ այլ սարքից"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Օգտագործել այլ սարք"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-in/strings.xml b/packages/CredentialManager/res/values-in/strings.xml
new file mode 100644
index 0000000..d980d44
--- /dev/null
+++ b/packages/CredentialManager/res/values-in/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Pengelola Kredensial"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Batal"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Lanjutkan"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Buat di tempat lain"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan ke tempat lain"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Gunakan perangkat lain"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan ke perangkat lain"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cara mudah untuk login dengan aman"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gunakan sidik jari, wajah, atau kunci layar untuk login dengan kunci sandi unik yang mudah diingat dan tidak dapat dicuri. Pelajari lebih lanjut"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"menyimpan sandi Anda"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"menyimpan info login Anda"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Buat kunci sandi di <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Simpan sandi ke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Simpan info login ke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Anda dapat menggunakan <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> di perangkat mana pun. Disimpan ke <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> untuk <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"kunci sandi"</string>
+    <string name="password" msgid="6738570945182936667">"sandi"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"login"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua info login Anda?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Setel sebagai default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> sandi, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> kunci sandi"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> sandi"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> kunci sandi"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Kunci sandi"</string>
+    <string name="another_device" msgid="5147276802037801217">"Perangkat lain"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Pengelola sandi lainnya"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Tutup sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kembali ke halaman sebelumnya"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci sandi tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan info login tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pilih info login tersimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Login dengan cara lain"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Lain kali"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Lanjutkan"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opsi login"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Untuk <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Pengelola sandi terkunci"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Ketuk untuk membuka kunci"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Kelola login"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Dari perangkat lain"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan perangkat lain"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-is/strings.xml b/packages/CredentialManager/res/values-is/strings.xml
new file mode 100644
index 0000000..3fd6af2
--- /dev/null
+++ b/packages/CredentialManager/res/values-is/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Hætta við"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Áfram"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Búa til annarsstaðar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Vista annarsstaðar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Nota annað tæki"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Vista í öðru tæki"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Einföld leið við örugga innskráningu"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Notaðu fingrafar, andlit eða skjálás til að skrá þig inn með einkvæmum aðgangslykli sem ekki er hægt að gleyma eða stela. Nánar"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Veldu hvar á að <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"vistaðu aðgangsorðið"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"vistaðu innskráningarupplýsingarnar"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Búa til aðgangslykil í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vista aðgangsorð í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vista innskráningarupplýsingar í <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Þú getur notað <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> í hvaða tæki sem er. Það er vistað á <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> fyrir <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"aðgangslykill"</string>
+    <string name="password" msgid="6738570945182936667">"aðgangsorð"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"innskráningar"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Nota <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> fyrir allar innskráningar?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Stilla sem sjálfgefið"</string>
+    <string name="use_once" msgid="9027366575315399714">"Nota einu sinni"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> aðgangsorð, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> aðgangslyklar"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> aðgangsorð"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> aðgangslyklar"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Annað tæki"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Önnur aðgangsorðastjórnun"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Loka blaði"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Fara aftur á fyrri síðu"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Notað vistaðan aðgangslykil fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Nota vistaða innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Veldu vistaða innskráningu fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Skrá inn með öðrum hætti"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nei takk"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Áfram"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Innskráningarkostir"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Fyrir: <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Læst aðgangsorðastjórnun"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Ýttu til að opna"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Stjórna innskráningu"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Úr öðru tæki"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Nota annað tæki"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-it/strings.xml b/packages/CredentialManager/res/values-it/strings.xml
new file mode 100644
index 0000000..3a7b0fb
--- /dev/null
+++ b/packages/CredentialManager/res/values-it/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Gestore delle credenziali"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Annulla"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continua"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Crea in un altro luogo"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Salva in un altro luogo"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usa un altro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Salva su un altro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un modo semplice per accedere in sicurezza"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Usa l\'impronta digitale, il volto o il blocco schermo per accedere con una passkey unica che non può essere dimenticata o rubata. Scopri di più"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Scegli dove <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"salva la password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"salva le tue informazioni di accesso"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vuoi creare una passkey su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vuoi salvare la password su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vuoi salvare le informazioni di accesso su <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Puoi utilizzare <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> su qualsiasi dispositivo. Questa informazione è salvata su <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> per <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"accessi"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vuoi usare <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> per tutti gli accessi?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Imposta come valore predefinito"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usa una volta"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> password, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> password"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkey"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Un altro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Altri gestori delle password"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Chiudi il foglio"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Torna alla pagina precedente"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vuoi usare la passkey salvata per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vuoi usare l\'accesso salvato per <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Scegli un accesso salvato per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Accedi in un altro modo"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"No, grazie"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continua"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opzioni di accesso"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Per <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestori delle password bloccati"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tocca per sbloccare"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestisci gli accessi"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Da un altro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usa un dispositivo diverso"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-iw/strings.xml b/packages/CredentialManager/res/values-iw/strings.xml
new file mode 100644
index 0000000..397ad60
--- /dev/null
+++ b/packages/CredentialManager/res/values-iw/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"מנהל פרטי הכניסה"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"ביטול"</string>
+    <string name="string_continue" msgid="1346732695941131882">"המשך"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"יצירה במקום אחר"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"שמירה במקום אחר"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"שימוש במכשיר אחר"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"שמירה במכשיר אחר"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"דרך פשוטה להיכנס לחשבון בבטחה"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"אפשר להשתמש בטביעת אצבע, בזיהוי פנים או בנעילת מסך כדי להיכנס לחשבון עם מפתח גישה ייחודי שאי אפשר לשכוח או לגנוב אותו. מידע נוסף"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"צריך לבחור לאן <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"שמירת הסיסמה שלך"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"שמירת פרטי הכניסה שלך"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ליצור מפתח גישה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"לשמור את הסיסמה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"לשמור את פרטי הכניסה ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"אפשר להשתמש ב-<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> מסוג <xliff:g id="TYPE">%2$s</xliff:g> בכל מכשיר. הוא שמור ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ל-<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"מפתח גישה"</string>
+    <string name="password" msgid="6738570945182936667">"סיסמה"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"פרטי כניסה"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"להשתמש ב-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> בכל הכניסות?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"הגדרה כברירת מחדל"</string>
+    <string name="use_once" msgid="9027366575315399714">"שימוש פעם אחת"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> סיסמאות, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> מפתחות גישה"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> סיסמאות"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> מפתחות גישה"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"מפתח גישה"</string>
+    <string name="another_device" msgid="5147276802037801217">"מכשיר אחר"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"מנהלי סיסמאות אחרים"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"סגירת הגיליון"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"חזרה לדף הקודם"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"להשתמש במפתח גישה שנשמר עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"להשתמש בפרטי הכניסה שנשמרו עבור <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"בחירת פרטי כניסה שמורים עבור <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"כניסה בדרך אחרת"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"לא תודה"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"המשך"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"אפשרויות כניסה לחשבון"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"עבור <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"מנהלי סיסמאות נעולים"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"יש להקיש כדי לבטל את הנעילה"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ניהול כניסות"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ממכשיר אחר"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"צריך להשתמש במכשיר אחר"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ja/strings.xml b/packages/CredentialManager/res/values-ja/strings.xml
new file mode 100644
index 0000000..0340b66
--- /dev/null
+++ b/packages/CredentialManager/res/values-ja/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"認証情報マネージャー"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"キャンセル"</string>
+    <string name="string_continue" msgid="1346732695941131882">"続行"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"別の場所で作成"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"別の場所に保存"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"別のデバイスを使用"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"他のデバイスに保存"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全にログインする簡単な方法"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"忘れたり盗まれたりする可能性がある一意のパスキーと合わせて、ログインに指紋認証、顔認証、画面ロックを使用できます。詳細"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> の保存場所の選択"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"パスワードを保存"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ログイン情報を保存"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> でパスキーを作成しますか?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> にパスワードを保存しますか?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> にログイン情報を保存しますか?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> の <xliff:g id="TYPE">%2$s</xliff:g> はどのデバイスでも使用できます。<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> の <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> に保存されます"</string>
+    <string name="passkey" msgid="632353688396759522">"パスキー"</string>
+    <string name="password" msgid="6738570945182936667">"パスワード"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ログイン"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ログインのたびに <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> を使用しますか?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"デフォルトに設定"</string>
+    <string name="use_once" msgid="9027366575315399714">"1 回使用"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 件のパスワード、<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 件のパスキー"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 件のパスワード"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 件のパスキー"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"パスキー"</string>
+    <string name="another_device" msgid="5147276802037801217">"別のデバイス"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"他のパスワード マネージャー"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"シートを閉じます"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"前のページに戻ります"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したパスキーを使用しますか?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報を使用しますか?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> の保存したログイン情報の選択"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"別の方法でログイン"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"利用しない"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"続行"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ログイン オプション"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 用"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"パスワード マネージャー ロック中"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"タップしてロック解除"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ログインを管理"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"別のデバイスを使う"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"別のデバイスを使用"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ka/strings.xml b/packages/CredentialManager/res/values-ka/strings.xml
new file mode 100644
index 0000000..3da7ea3
--- /dev/null
+++ b/packages/CredentialManager/res/values-ka/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"ავტორიზაციის მონაცემების მმართველი"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"გაუქმება"</string>
+    <string name="string_continue" msgid="1346732695941131882">"გაგრძელება"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"სხვა სივრცეში შექმნა"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"სხვა სივრცეში შენახვა"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"სხვა მოწყობილობის გამოყენება"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"სხვა მოწყობილობაზე შენახვა"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"უსაფრთხოდ შესვლის მარტივი გზა"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"გამოიყენეთ თქვენი თითის ანაბეჭდი, სახის ამოცნობა და ეკრანის დაბლოკვა სისტემაში უნიკალური წვდომის გასაღებით შესასვლელად, რომლის დავიწყება ან მოპარვა შეუძლებელია. შეიტყვეთ მეტი"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"აირჩიეთ, სად უნდა <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"შეინახეთ თქვენი პაროლი"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"შეინახეთ თქვენი სისტემაში შესვლის ინფორმაცია"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"გსურთ წვდომის გასაღების შექმნა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"გსურთ თქვენი პაროლის შენახვა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"გსურთ თქვენი სისტემაში შესვლის მონაცემების შენახვა <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-ში?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"შეგიძლიათ გამოიყენოთ თქვენი <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ნებისმიერ მოწყობილობაზე. ის შეინახება <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-ზე <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-თვის"</string>
+    <string name="passkey" msgid="632353688396759522">"წვდომის გასაღები"</string>
+    <string name="password" msgid="6738570945182936667">"პაროლი"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"სისტემაში შესვლა"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"გსურთ, გამოიყენოთ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> სისტემაში ყველა შესვლისთვის?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ნაგულისხმევად დაყენება"</string>
+    <string name="use_once" msgid="9027366575315399714">"ერთხელ გამოყენება"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> პაროლი, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> წვდომის გასაღები"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> პაროლი"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> წვდომის გასაღები"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"წვდომის გასაღები"</string>
+    <string name="another_device" msgid="5147276802037801217">"სხვა მოწყობილობა"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"პაროლების სხვა მმართველები"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ფურცლის დახურვა"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"წინა გვერდზე დაბრუნება"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"გსურთ თქვენი დამახსოვრებული წვდომის გასაღების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"გსურთ თქვენი დამახსოვრებული სისტემაში შესვლის მონაცემების გამოყენება აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"აირჩიეთ სისტემაში შესვლის ინფორმაცია აპისთვის: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"სხვა ხერხით შესვლა"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"არა, გმადლობთ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"გაგრძელება"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"სისტემაში შესვლის ვარიანტები"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-ისთვის"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ჩაკეტილი პაროლის მმართველები"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"შეეხეთ განსაბლოკად"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"სისტემაში შესვლის მონაცემების მართვა"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"სხვა მოწყობილობიდან"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"გამოიყენეთ სხვა მოწყობილობა"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-kk/strings.xml b/packages/CredentialManager/res/values-kk/strings.xml
new file mode 100644
index 0000000..9491f8e
--- /dev/null
+++ b/packages/CredentialManager/res/values-kk/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Бас тарту"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Жалғастыру"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Басқа орында жасау"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Басқа орынға сақтау"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Басқа құрылғыны пайдалану"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Басқа құрылғыға сақтау"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Қауіпсіз кірудің оңай жолы"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Ұмытылмайтын немесе ұрланбайтын бірегей кіру кілтінің көмегімен кіру үшін саусақ ізін, бетті анықтау функциясын немесе экран құлпын пайдаланыңыз. Толық ақпарат"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> таңдау"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"құпия сөзді сақтау"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"тіркелу деректерін сақтау"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасында кіру кілті жасалсын ба?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасына құпия сөз сақталсын ба?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> қолданбасына тіркелу деректері сақталсын ба?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> кез келген құрылғыда пайдаланылады. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> тіркелу деректері <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> қолданбасында сақталады."</string>
+    <string name="passkey" msgid="632353688396759522">"кіру кілті"</string>
+    <string name="password" msgid="6738570945182936667">"құпия сөз"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"кіру әрекеттері"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Барлық кіру әрекеті үшін <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> пайдаланылсын ба?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Әдепкі етіп орнату"</string>
+    <string name="use_once" msgid="9027366575315399714">"Бір рет пайдалану"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> құпия сөз, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> кіру кілті"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> құпия сөз"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> кіру кілті"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Басқа құрылғы"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Басқа құпия сөз менеджерлері"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Парақты жабу"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Алдыңғы бетке оралу"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған кіру кілті пайдаланылсын ба?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректері пайдаланылсын ба?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> үшін сақталған тіркелу деректерін таңдаңыз"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Басқаша кіру"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Жоқ, рақмет"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Жалғастыру"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Кіру опциялары"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> үшін"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Құлыпталған құпия сөз менеджерлері"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Құлыпты ашу үшін түртіңіз."</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кіру әрекеттерін басқару"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Басқа құрылғыдан жасау"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Басқа құрылғыны пайдалану"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-km/strings.xml b/packages/CredentialManager/res/values-km/strings.xml
new file mode 100644
index 0000000..80167fc
--- /dev/null
+++ b/packages/CredentialManager/res/values-km/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"បោះបង់"</string>
+    <string name="string_continue" msgid="1346732695941131882">"បន្ត"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"បង្កើតនៅកន្លែងផ្សេងទៀត"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"រក្សាទុកក្នុងកន្លែងផ្សេងទៀត"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ប្រើ​ឧបករណ៍​ផ្សេងទៀត"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"រក្សាទុកទៅក្នុងឧបករណ៍ផ្សេង"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"វិធីដ៏សាមញ្ញ ដើម្បីចូលគណនីដោយសុវត្ថិភាព"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ប្រើស្នាមម្រាមដៃ មុខ ឬការចាក់សោអេក្រង់របស់អ្នក ដើម្បីចូលគណនីដោយប្រើកូដសម្ងាត់ខុសប្លែកពីគេដែលមិនអាចភ្លេច ឬត្រូវគេលួច។ ស្វែងយល់បន្ថែម"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"ជ្រើសរើសកន្លែងដែលត្រូវ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"រក្សាទុកពាក្យសម្ងាត់របស់អ្នក"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"រក្សាទុកព័ត៌មានចូលគណនីរបស់អ្នក"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"បង្កើតកូដសម្ងាត់នៅក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"រក្សាទុកពាក្យសម្ងាត់របស់អ្នកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"រក្សាទុកព័ត៌មានចូលគណនីរបស់អ្នកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ឬ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"អ្នកអាចប្រើ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> របស់អ្នកនៅលើឧបករណ៍ណាក៏បាន។ វាត្រូវបានរក្សាទុកក្នុង <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> សម្រាប់ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"កូដសម្ងាត់"</string>
+    <string name="password" msgid="6738570945182936667">"ពាក្យសម្ងាត់"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ការចូល​គណនី"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ប្រើ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> សម្រាប់ការចូលគណនីទាំងអស់របស់អ្នកឬ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"កំណត់ជាលំនាំដើម"</string>
+    <string name="use_once" msgid="9027366575315399714">"ប្រើម្ដង"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"ពាក្យសម្ងាត់ <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> កូដសម្ងាត់ <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"ពាក្យសម្ងាត់ <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"កូដសម្ងាត់ <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"ឧបករណ៍​ផ្សេងទៀត"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ផ្សេងទៀត"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"បិទសន្លឹក"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ត្រឡប់ទៅ​ទំព័រ​មុនវិញ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ប្រើកូដសម្ងាត់ដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ប្រើការចូល​គណនីដែលបានរក្សាទុករបស់អ្នកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g> ឬ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ជ្រើសរើសការចូលគណនីដែលបានរក្សាទុកសម្រាប់ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ចូលគណនីដោយប្រើវិធីផ្សេងទៀត"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ទេ អរគុណ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"បន្ត"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ជម្រើស​ចូលគណនី"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"សម្រាប់ <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"កម្មវិធីគ្រប់គ្រងពាក្យសម្ងាត់ដែលបានចាក់សោ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ចុចដើម្បីដោះសោ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"គ្រប់គ្រងការចូល​គណនី"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ពីឧបករណ៍ផ្សេងទៀត"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ប្រើឧបករណ៍ផ្សេង"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-kn/strings.xml b/packages/CredentialManager/res/values-kn/strings.xml
new file mode 100644
index 0000000..96304ac
--- /dev/null
+++ b/packages/CredentialManager/res/values-kn/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"ರುಜುವಾತು ನಿರ್ವಾಹಕ"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"ರದ್ದುಗೊಳಿಸಿ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ಮುಂದುವರಿಸಿ"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"ಮತ್ತೊಂದು ಸ್ಥಳದಲ್ಲಿ ರಚಿಸಿ"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"ಮತ್ತೊಂದು ಸ್ಥಳದಲ್ಲಿ ಉಳಿಸಿ"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ಬೇರೊಂದು ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ಬೇರೊಂದು ಸಾಧನದಲ್ಲಿ ಉಳಿಸಿ"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"ಸುರಕ್ಷಿತವಾಗಿ ಸೈನ್ ಇನ್ ಮಾಡುವ ಸುಲಭ ವಿಧಾನ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ಮರೆಯಲಾಗದ ಅಥವಾ ಕದಿಯಲಾಗದ ಅನನ್ಯ ಪಾಸ್‌ಕೀ ಮೂಲಕ ಸೈನ್ ಇನ್ ಮಾಡಲು ನಿಮ್ಮ ಫಿಂಗರ್‌ಪ್ರಿಂಟ್, ಫೇಸ್ ಲಾಕ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಬಳಸಿ. ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ಅನ್ನು ಎಲ್ಲಿ ಉಳಿಸಬೇಕು ಎಂದು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್‌ ಉಳಿಸಿ"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಮಾಹಿತಿ ಉಳಿಸಿ"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ನಲ್ಲಿ ಪಾಸ್‌ಕೀ ರಚಿಸಬೇಕೆ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಗೆ ಉಳಿಸಬೇಕೆ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ನಿಮ್ಮ ಸೈನ್ ಇನ್ ಮಾಹಿತಿಯನ್ನು <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಗೆ ಉಳಿಸಬೇಕೆ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"ನೀವು ಯಾವುದೇ ಸಾಧನದಲ್ಲಿ ನಿಮ್ಮ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ಅನ್ನು ಬಳಸಬಹುದು. ಇದನ್ನು <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ಗೆ ಉಳಿಸಲಾಗಿದೆ"</string>
+    <string name="passkey" msgid="632353688396759522">"ಪಾಸ್‌ಕೀ"</string>
+    <string name="password" msgid="6738570945182936667">"ಪಾಸ್‌ವರ್ಡ್"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ಸೈನ್-ಇನ್‌ಗಳು"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ನಿಮ್ಮ ಎಲ್ಲಾ ಸೈನ್-ಇನ್‌ಗಳಿಗಾಗಿ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ಅನ್ನು ಬಳಸುವುದೇ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ಡೀಫಾಲ್ಟ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
+    <string name="use_once" msgid="9027366575315399714">"ಒಂದು ಬಾರಿ ಬಳಸಿ"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ಪಾಸ್‌ವರ್ಡ್‌ಗಳು, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ಪಾಸ್‌ಕೀಗಳು"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ಪಾಸ್‌ವರ್ಡ್‌ಗಳು"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ಪಾಸ್‌ಕೀಗಳು"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"ಪಾಸ್‌ಕೀ"</string>
+    <string name="another_device" msgid="5147276802037801217">"ಮತ್ತೊಂದು ಸಾಧನ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"ಇತರ ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕರು"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ಶೀಟ್ ಮುಚ್ಚಿರಿ"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ಹಿಂದಿನ ಪುಟಕ್ಕೆ ಹಿಂದಿರುಗಿ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಪಾಸ್‌ಕೀ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ನಿಮ್ಮ ಸೈನ್-ಇನ್ ಅನ್ನು ಬಳಸಬೇಕೆ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಗಾಗಿ ಉಳಿಸಲಾದ ಸೈನ್-ಇನ್ ಮಾಹಿತಿಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ಬೇರೆ ವಿಧಾನದಲ್ಲಿ ಸೈನ್ ಇನ್ ಮಾಡಿ"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ಬೇಡ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ಮುಂದುವರಿಸಿ"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ಸೈನ್ ಇನ್ ಆಯ್ಕೆಗಳು"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> ಗಾಗಿ"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ಪಾಸ್‌ವರ್ಡ್ ನಿರ್ವಾಹಕರನ್ನು ಲಾಕ್ ಮಾಡಲಾಗಿದೆ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ಅನ್‌ಲಾಕ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ಸೈನ್-ಇನ್‌ಗಳನ್ನು ನಿರ್ವಹಿಸಿ"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ಮತ್ತೊಂದು ಸಾಧನದಿಂದ"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ಬೇರೆ ಸಾಧನವನ್ನು ಬಳಸಿ"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ko/strings.xml b/packages/CredentialManager/res/values-ko/strings.xml
new file mode 100644
index 0000000..58518c1
--- /dev/null
+++ b/packages/CredentialManager/res/values-ko/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"취소"</string>
+    <string name="string_continue" msgid="1346732695941131882">"계속"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"다른 위치에 만들기"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"다른 위치에 저장"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"다른 기기 사용"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"다른 기기에 저장"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"안전하게 로그인하는 간단한 방법"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"지문, 얼굴 인식 또는 화면 잠금을 통해 잊어버리거나 분실할 염려가 없는 고유한 패스키로 로그인하세요. 자세히 알아보기"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> 작업을 위한 위치 선택"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"비밀번호 저장"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"로그인 정보 저장"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 패스키를 만드시겠습니까?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 비밀번호를 저장하시겠습니까?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>에 로그인 정보를 저장하시겠습니까?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"기기에서 <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>을(를) 사용할 수 있습니다. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>을(를) 위해 <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>에 저장되어 있습니다."</string>
+    <string name="passkey" msgid="632353688396759522">"패스키"</string>
+    <string name="password" msgid="6738570945182936667">"비밀번호"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"로그인 정보"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"모든 로그인에 <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>을(를) 사용하시겠습니까?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"기본값으로 설정"</string>
+    <string name="use_once" msgid="9027366575315399714">"한 번 사용"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"비밀번호 <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>개, 패스키 <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>개"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"비밀번호 <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>개"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"패스키 <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>개"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"다른 기기"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"기타 비밀번호 관리자"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"시트 닫기"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"이전 페이지로 돌아가기"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 패스키를 사용하시겠습니까?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 로그인 정보를 사용하시겠습니까?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱용 저장된 로그인 정보 선택"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"다른 방법으로 로그인"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"아니요"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"계속"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"로그인 옵션"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>님의 로그인 정보"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"잠긴 비밀번호 관리자"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"잠금 해제하려면 탭하세요."</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"로그인 관리"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"다른 기기에서"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"다른 기기 사용"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ky/strings.xml b/packages/CredentialManager/res/values-ky/strings.xml
new file mode 100644
index 0000000..298657e
--- /dev/null
+++ b/packages/CredentialManager/res/values-ky/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Жок"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Улантуу"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Башка жерде түзүү"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Башка жерге сактоо"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Башка түзмөк колдонуу"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Башка түзмөккө сактоо"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Коопсуз кирүүнүн жөнөкөй жолу"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Унутуп калууга же уурдатууга мүмкүн эмес болгон уникалдуу ачкыч менен манжа изин, жүзүнөн таанып ачуу же экранды кулпулоо функцияларын колдонуп өзүңүздү ырастай аласыз. Кененирээк"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> үчүн жер тандаңыз"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"сырсөзүңүздү сактаңыз"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"кирүү маалыматын сактаңыз"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда мүмкүндүк алуу ачкычын түзөсүзбү?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Сырсөзүңүздү <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда сактайсызбы?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Кирүү маалыматын <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> колдонмосунда сактайсызбы?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> каалаган түзмөктө колдонулат. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> байланыштуу маалыматтар <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> колдонмосунда сакталат"</string>
+    <string name="passkey" msgid="632353688396759522">"мүмкүндүк алуу ачкычы"</string>
+    <string name="password" msgid="6738570945182936667">"сырсөз"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"кирүүлөр"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> бардык аккаунттарга кирүү үчүн колдонулсунбу?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Демейки катары коюу"</string>
+    <string name="use_once" msgid="9027366575315399714">"Бир жолу колдонуу"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> сырсөз, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> мүмкүндүк алуу ачкычы"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> сырсөз"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> мүмкүндүк алуу ачкычы"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Башка түзмөк"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Башка сырсөздөрдү башкаргычтар"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Баракты жабуу"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Мурунку бетке кайтуу"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган мүмкүндүк алуу ачкычын колдоносузбу?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн сакталган кирүү параметрин колдоносузбу?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> үчүн кирүү маалыматын тандаңыз"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Башка жол менен кирүү"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Жок, рахмат"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Улантуу"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Аккаунтка кирүү параметрлери"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> үчүн"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Кулпуланган сырсөздөрдү башкаргычтар"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Кулпусун ачуу үчүн таптаңыз"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Кирүү параметрлерин тескөө"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Башка түзмөктөн"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Башка түзмөктү колдонуу"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-lo/strings.xml b/packages/CredentialManager/res/values-lo/strings.xml
new file mode 100644
index 0000000..215262b
--- /dev/null
+++ b/packages/CredentialManager/res/values-lo/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"ຍົກເລີກ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ສືບຕໍ່"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"ສ້າງໃນບ່ອນອື່ນ"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"ບັນທຶກໃສ່ບ່ອນອື່ນ"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ໃຊ້ອຸປະກອນອື່ນ"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ບັນທຶກໃສ່ອຸປະກອນອື່ນ"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"ວິທີງ່າຍໆໃນການເຂົ້າສູ່ລະບົບຢ່າງປອດໄພ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ໃຊ້ລາຍນິ້ວມື, ໃບໜ້າ ຫຼື ລັອກໜ້າຈໍຂອງທ່ານເພື່ອເຂົ້າສູ່ລະບົບດ້ວຍກະແຈຜ່ານທີ່ບໍ່ຊ້ຳກັນເພື່ອບໍ່ໃຫ້ລືມ ຫຼື ຖືກລັກໄດ້. ສຶກສາເພີ່ມເຕີມ"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"ເລືອກບ່ອນທີ່ຈະ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ບັນທຶກລະຫັດຜ່ານຂອງທ່ານ"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບຂອງທ່ານ"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ສ້າງກະແຈຜ່ານໃນ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"ບັນທຶກລະຫັດຜ່ານຂອງທ່ານໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ບັນທຶກຂໍ້ມູນການເຂົ້າສູ່ລະບົບຂອງທ່ານໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ບໍ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"ທ່ານສາມາດໃຊ້ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ຂອງທ່ານຢູ່ອຸປະກອນໃດກໍໄດ້. ມັນຈະຖືກບັນທຶກໃສ່ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ສຳລັບ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"ກະແຈຜ່ານ"</string>
+    <string name="password" msgid="6738570945182936667">"ລະຫັດຜ່ານ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ການເຂົ້າສູ່ລະບົບ"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ໃຊ້ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ສຳລັບການເຂົ້າສູ່ລະບົບທັງໝົດຂອງທ່ານບໍ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ຕັ້ງເປັນຄ່າເລີ່ມຕົ້ນ"</string>
+    <string name="use_once" msgid="9027366575315399714">"ໃຊ້ເທື່ອດຽວ"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ລະຫັດຜ່ານ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ກະແຈຜ່ານ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ລະຫັດຜ່ານ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ກະແຈຜ່ານ"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"ອຸປະກອນອື່ນ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"ຕົວຈັດການລະຫັດຜ່ານອື່ນໆ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ປິດຊີດ"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ກັບຄືນໄປຫາໜ້າກ່ອນໜ້ານີ້"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ໃຊ້ກະແຈຜ່ານທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ໃຊ້ການເຂົ້າສູ່ລະບົບທີ່ບັນທຶກໄວ້ຂອງທ່ານສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"ເລືອກການເຂົ້າສູ່ລະບົບທີ່ບັນທຶກໄວ້ສຳລັບ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ເຂົ້າສູ່ລະບົບດ້ວຍວິທີອື່ນ"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ບໍ່, ຂອບໃຈ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ສືບຕໍ່"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ຕົວເລືອກການເຂົ້າສູ່ລະບົບ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"ສຳລັບ <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ຕົວຈັດການລະຫັດຜ່ານທີ່ລັອກໄວ້"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ແຕະເພື່ອປົດລັອກ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ຈັດການການເຂົ້າສູ່ລະບົບ"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ຈາກອຸປະກອນອື່ນ"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ໃຊ້ອຸປະກອນອື່ນ"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-lt/strings.xml b/packages/CredentialManager/res/values-lt/strings.xml
new file mode 100644
index 0000000..6125fe3
--- /dev/null
+++ b/packages/CredentialManager/res/values-lt/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Prisijungimo duomenų tvarkytuvė"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Atšaukti"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Tęsti"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Sukurti kitoje vietoje"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Išsaugoti kitoje vietoje"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Naudoti kitą įrenginį"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Išsaugoti kitame įrenginyje"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Paprastas saugaus prisijungimo metodas"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Naudodami piršto atspaudą, veidą ar ekrano užraktą prisijunkite su unikaliu „passkey“, kurio neįmanoma pamiršti ar pavogti. Sužinokite daugiau"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Pasirinkite, kur <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"išsaugoti slaptažodį"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"išsaugoti prisijungimo informaciją"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Sukurti „passkey“ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Išsaugoti slaptažodį <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Išsaugoti prisijungimo informaciją <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Galite naudoti <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> bet kuriame įrenginyje. Jis išsaugomas <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)"</string>
+    <string name="passkey" msgid="632353688396759522">"„passkey“"</string>
+    <string name="password" msgid="6738570945182936667">"slaptažodis"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prisijungimo informacija"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Naudoti <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> visada prisijungiant?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Nustatyti kaip numatytąjį"</string>
+    <string name="use_once" msgid="9027366575315399714">"Naudoti vieną kartą"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"slaptažodžių: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, „passkey“: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"slaptažodžių: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"„passkey“: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Slaptažodis"</string>
+    <string name="another_device" msgid="5147276802037801217">"Kitas įrenginys"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Kitos slaptažodžių tvarkyklės"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Uždaryti lapą"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Grįžti į ankstesnį puslapį"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Naudoti išsaugotą „passkey“ programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Naudoti išsaugotą prisijungimo informaciją programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pasirinkite išsaugotą prisijungimo informaciją programai „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prisijungti kitu būdu"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, ačiū"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Tęsti"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Prisijungimo parinktys"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Skirta <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Užrakintos slaptažodžių tvarkyklės"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Palieskite, kad atrakintumėte"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Tvarkyti prisijungimo informaciją"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Naudojant kitą įrenginį"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Naudoti kitą įrenginį"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-lv/strings.xml b/packages/CredentialManager/res/values-lv/strings.xml
new file mode 100644
index 0000000..43c036f
--- /dev/null
+++ b/packages/CredentialManager/res/values-lv/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Akreditācijas datu pārvaldnieks"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Atcelt"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Turpināt"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Izveidot citur"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Saglabāt citur"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Izmantot citu ierīci"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Saglabāt citā ierīcē"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Vienkāršs veids, kā droši pierakstīties"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Izmantojiet pirksta nospiedumu, autorizāciju pēc sejas vai ekrāna bloķēšanu, lai pierakstītos ar unikālu piekļuves atslēgu, ko nevar aizmirst vai nozagt. Uzziniet vairāk."</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Izvēlieties, kur: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"saglabāt paroli"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"saglabāt pierakstīšanās informāciju"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vai izveidot piekļuves atslēgu šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vai saglabāt paroli šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vai saglabāt pierakstīšanās informāciju šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Jebkurā ierīcē varat izmantot šo: <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>. Tas tiek saglabāt šeit: <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>; mērķis: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"piekļuves atslēga"</string>
+    <string name="password" msgid="6738570945182936667">"parole"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"pierakstīšanās informācija"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vai vienmēr izmantot <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>, lai pierakstītos?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Iestatīt kā noklusējumu"</string>
+    <string name="use_once" msgid="9027366575315399714">"Izmantot vienreiz"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> paroles, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> piekļuves atslēgas"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> paroles"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> piekļuves atslēgas"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Piekļuves atslēga"</string>
+    <string name="another_device" msgid="5147276802037801217">"Cita ierīce"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Citi paroļu pārvaldnieki"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Aizvērt lapu"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Atgriezties iepriekšējā lapā"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vai izmantot saglabāto piekļuves atslēgu lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vai izmantot saglabāto pierakstīšanās informāciju lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Saglabātas pierakstīšanās informācijas izvēle lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Pierakstīties citā veidā"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nē, paldies"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Turpināt"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Pierakstīšanās opcijas"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Lietotājam <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Paroļu pārvaldnieki, kuros nepieciešams autentificēties"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Pieskarieties, lai atbloķētu"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pierakstīšanās informācijas pārvaldība"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"No citas ierīces"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Izmantot citu ierīci"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-mk/strings.xml b/packages/CredentialManager/res/values-mk/strings.xml
new file mode 100644
index 0000000..059f042
--- /dev/null
+++ b/packages/CredentialManager/res/values-mk/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Управник на акредитиви"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Откажи"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Продолжи"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Создајте на друго место"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Зачувајте на друго место"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Употребете друг уред"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Зачувајте на друг уред"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Едноставен начин за безбедно најавување"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користете го отпечатокот, заклучувањето со лик или заклучувањето екран за да се најавите со единствен криптографски клуч што не може да се заборави или украде. Дознајте повеќе"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Изберете каде да <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"се зачува лозинката"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"се зачуваат податоците за најавување"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Да се создаде криптографски клуч во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Да се зачува вашата лозинка во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Да се зачуваат вашите податоци за најавување во <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Вашиот <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> од типот <xliff:g id="TYPE">%2$s</xliff:g> може да го користите на секој уред. Зачуван е на <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"криптографски клуч"</string>
+    <string name="password" msgid="6738570945182936667">"лозинка"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"најавувања"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Да се користи <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> за сите ваши најавувања?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Постави како стандардна опција"</string>
+    <string name="use_once" msgid="9027366575315399714">"Употребете еднаш"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> лозинки, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> криптографски клучеви"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> лозинки"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> криптографски клучеви"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Криптографски клуч"</string>
+    <string name="another_device" msgid="5147276802037801217">"Друг уред"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Други управници со лозинки"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Затворете го листот"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Врати се на претходната страница"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Да се користи вашиот зачуван криптографски клуч за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Да се користи вашето зачувано најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Изберете зачувано најавување за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Најавете се на друг начин"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Не, фала"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продолжи"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опции за најавување"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заклучени управници со лозинки"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Допрете за да отклучите"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управувајте со најавувањата"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Од друг уред"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Употребете друг уред"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ml/strings.xml b/packages/CredentialManager/res/values-ml/strings.xml
new file mode 100644
index 0000000..e4f6d69
--- /dev/null
+++ b/packages/CredentialManager/res/values-ml/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"ക്രെഡൻഷ്യൽ മാനേജർ"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"റദ്ദാക്കുക"</string>
+    <string name="string_continue" msgid="1346732695941131882">"തുടരുക"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"മറ്റൊരു സ്ഥലത്ത് സൃഷ്‌ടിക്കുക"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"മറ്റൊരു സ്ഥലത്തേക്ക് സംരക്ഷിക്കുക"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"മറ്റൊരു ഉപകരണത്തിലേക്ക് സംരക്ഷിക്കുക"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"സുരക്ഷിതമായി സൈൻ ഇൻ ചെയ്യാനുള്ള ലളിതമായ മാർഗ്ഗം"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"മറന്നുപോകാനും മോഷ്‌ടിക്കാനും സാധ്യതയില്ലാത്ത തനത് പാസ്‌കീ ഉപയോഗിച്ച് സൈൻ ഇൻ ചെയ്യാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റോ മുഖമോ സ്‌ക്രീൻ ലോക്കോ ഉപയോഗിക്കുക. കൂടുതലറിയുക"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"എവിടെ <xliff:g id="CREATETYPES">%1$s</xliff:g> എന്ന് തിരഞ്ഞെടുക്കുക"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"നിങ്ങളുടെ പാസ്‌വേഡ് സംരക്ഷിക്കുക"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"നിങ്ങളുടെ സൈൻ ഇൻ വിവരങ്ങൾ സംരക്ഷിക്കുക"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിൽ ഒരു പാസ്‌കീ സൃഷ്‌ടിക്കണോ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"പാസ്‌വേഡ് <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"സൈൻ ഇൻ വിവരങ്ങൾ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിക്കണോ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"നിങ്ങളുടെ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ഏത് ഉപകരണത്തിലും നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഇത് <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> എന്നതിനായി <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> എന്നതിലേക്ക് സംരക്ഷിച്ചു"</string>
+    <string name="passkey" msgid="632353688396759522">"പാസ്‌കീ"</string>
+    <string name="password" msgid="6738570945182936667">"പാസ്‌വേഡ്"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"സൈൻ ഇന്നുകൾ"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"നിങ്ങളുടെ എല്ലാ സൈൻ ഇന്നുകൾക്കും <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ഉപയോഗിക്കണോ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ഡിഫോൾട്ടായി സജ്ജീകരിക്കുക"</string>
+    <string name="use_once" msgid="9027366575315399714">"ഒരു തവണ ഉപയോഗിക്കുക"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> പാസ്‌വേഡുകൾ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> പാസ്‌കീകൾ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> പാസ്‌വേഡുകൾ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> പാസ്‌കീകൾ"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"പാസ്‌കീ"</string>
+    <string name="another_device" msgid="5147276802037801217">"മറ്റൊരു ഉപകരണം"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"മറ്റ് പാസ്‌വേഡ് മാനേജർമാർ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ഷീറ്റ് അടയ്ക്കുക"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"മുമ്പത്തെ പേജിലേക്ക് മടങ്ങുക"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച പാസ്‌കീ ഉപയോഗിക്കണോ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി നിങ്ങൾ സംരക്ഷിച്ച സൈൻ ഇൻ ഉപയോഗിക്കണോ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിനായി ഒരു സംരക്ഷിച്ച സൈൻ ഇൻ തിരഞ്ഞെടുക്കുക"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"മറ്റൊരു രീതിയിൽ സൈൻ ഇൻ ചെയ്യുക"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"വേണ്ട"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"തുടരുക"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"സൈൻ ഇൻ ഓപ്ഷനുകൾ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> എന്നയാൾക്ക്"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ലോക്ക് ചെയ്‌ത പാസ്‌വേഡ് സൈൻ ഇൻ മാനേജർമാർ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"അൺലോക്ക് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"സൈൻ ഇന്നുകൾ മാനേജ് ചെയ്യുക"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"മറ്റൊരു ഉപകരണത്തിൽ നിന്ന്"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"മറ്റൊരു ഉപകരണം ഉപയോഗിക്കുക"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-mn/strings.xml b/packages/CredentialManager/res/values-mn/strings.xml
new file mode 100644
index 0000000..3f8d4ca
--- /dev/null
+++ b/packages/CredentialManager/res/values-mn/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Мандат үнэмлэхийн менежер"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Цуцлах"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Үргэлжлүүлэх"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Өөр газар үүсгэх"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Өөр газар хадгалах"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Өөр төхөөрөмж ашиглах"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Өөр төхөөрөмжид хадгалах"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Аюулгүй нэвтрэх энгийн арга"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Мартах эсвэл хулгайд алдах боломжгүй өвөрмөц passkey-н хамт нэвтрэх хурууны хээ, царай эсвэл дэлгэцийн түгжээгээ ашиглана уу. Нэмэлт мэдээлэл авах"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Хаана <xliff:g id="CREATETYPES">%1$s</xliff:g>-г сонгоно уу"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"нууц үгээ хадгалах"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"нэвтрэх мэдээллээ хадгалах"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д passkey үүсгэх үү?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Нууц үгээ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д хадгалах уу?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Нэвтрэх мэдээллээ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-д хадгалах уу?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Та өөрийн <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>-г дурын төхөөрөмж дээр ашиглах боломжтой. Үүнийг <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>-д <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>-д зориулж хадгалсан"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"нууц үг"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"нэвтрэлт"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>-г бүх нэвтрэлтдээ ашиглах уу?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Өгөгдмөлөөр тохируулах"</string>
+    <string name="use_once" msgid="9027366575315399714">"Нэг удаа ашиглах"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> нууц үг, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> passkey"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> нууц үг"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> passkey"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Өөр төхөөрөмж"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Нууц үгний бусад менежер"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Хүснэгтийг хаах"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Өмнөх хуудас руу буцах"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д өөрийн хадгалсан passkey-г ашиглах уу?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д хадгалсан нэвтрэх мэдээллээ ашиглах уу?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g>-д зориулж хадгалсан нэвтрэх мэдээллийг сонгоно уу"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Өөр аргаар нэвтрэх"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Үгүй, баярлалаа"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Үргэлжлүүлэх"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Нэвтрэх сонголт"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>-д"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Түгжээтэй нууц үгний менежерүүд"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Түгжээг тайлахын тулд товшино уу"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Нэвтрэлтийг удирдах"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Өөр төхөөрөмжөөс"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Өөр төхөөрөмж ашиглах"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-mr/strings.xml b/packages/CredentialManager/res/values-mr/strings.xml
new file mode 100644
index 0000000..aa6f253
--- /dev/null
+++ b/packages/CredentialManager/res/values-mr/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"रद्द करा"</string>
+    <string name="string_continue" msgid="1346732695941131882">"पुढे सुरू ठेवा"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"दुसऱ्या ठिकाणी तयार करा"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"दुसऱ्या ठिकाणी सेव्ह करा"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"दुसरे डिव्‍हाइस वापरा"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"दुसऱ्या डिव्हाइसवर सेव्ह करा"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षितपणे साइन इन करण्याचा सोपा मार्ग"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"युनिक पासकीसह साइन इन करण्यासाठी तुमचे फिंगरप्रिंट, फेस किंवा स्क्रीन लॉक वापरा, जे विसरता येणार नाही किंवा चोरीला जाणार नाही. अधिक जाणून घ्या"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> कुठे करायचे ते निवडा"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"तुमचा पासवर्ड सेव्ह करा"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"तुमची साइन-इन माहिती सेव्ह करा"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मध्ये पासकी तयार करायची का?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"तुमचा पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> वर सेव्ह करायचा का?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"तुमची साइन-इन माहिती <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> वर सेव्ह करायची का?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"तुम्ही कोणत्याही डिव्हाइसवर तुमचे <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> वापरू शकता. ते <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> साठी <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> वर सेव्ह केले जाते"</string>
+    <string name="passkey" msgid="632353688396759522">"पासकी"</string>
+    <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"साइन-इन"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"तुमच्या सर्व साइन-इन साठी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>वापरायचे का?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"डिफॉल्ट म्हणून सेट करा"</string>
+    <string name="use_once" msgid="9027366575315399714">"एकदा वापरा"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> पासकी"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> पासवर्ड"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> पासकी"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"इतर डिव्हाइस"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"इतर पासवर्ड व्यवस्थापक"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"शीट बंद करा"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"मागील पेजवर परत जा"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमची सेव्ह केलेली पासकी वापरायची का?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी तुमचे सेव्ह केलेले साइन-इन वापरायचे का?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> साठी सेव्ह केलेले साइन-इन निवडा"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"दुसऱ्या मार्गाने साइन इन करा"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"नाही, नको"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"पुढे सुरू ठेवा"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन इन पर्याय"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> साठी"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लॉक केलेले पासवर्ड व्यवस्थापक"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"अनलॉक करण्यासाठी टॅप करा"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन-इन व्यवस्थापित करा"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"दुसऱ्या डिव्हाइस वरून"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"वेगळे डिव्हाइस वापरा"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ms/strings.xml b/packages/CredentialManager/res/values-ms/strings.xml
new file mode 100644
index 0000000..d5f8c0e
--- /dev/null
+++ b/packages/CredentialManager/res/values-ms/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Pengurus Bukti Kelayakan"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Batal"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Teruskan"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Buat di tempat lain"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Simpan di tempat lain"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Gunakan peranti lain"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Simpan kepada peranti lain"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cara mudah untuk log masuk dengan selamat"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gunakan cap jari, wajah atau kunci skrin anda untuk log masuk menggunakan kunci laluan unik yang tidak boleh dilupakan atau dicuri. Ketahui lebih lanjut"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Pilih tempat untuk <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"simpan kata laluan anda"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"simpan maklumat log masuk anda"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Buat kunci laluan dalam <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Simpan kata laluan anda pada <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Simpan maklumat log masuk anda pada <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Anda boleh menggunakan <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> anda pada mana-mana peranti. Ia disimpan pada <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> untuk <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"kunci laluan"</string>
+    <string name="password" msgid="6738570945182936667">"kata laluan"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"log masuk"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Gunakan <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> untuk semua log masuk anda?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Tetapkan sebagai lalai"</string>
+    <string name="use_once" msgid="9027366575315399714">"Gunakan sekali"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Kata laluan <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, kunci laluan <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Kata laluan <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Kunci laluan <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Kunci laluan"</string>
+    <string name="another_device" msgid="5147276802037801217">"Peranti lain"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Password Manager lain"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Tutup helaian"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kembali ke halaman sebelumnya"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gunakan kunci laluan anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gunakan maklumat log masuk anda yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pilih log masuk yang telah disimpan untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Log masuk menggunakan cara lain"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Tidak perlu"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Teruskan"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Pilihan log masuk"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Untuk <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Password Manager dikunci"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Ketik untuk membuka kunci"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Urus log masuk"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Daripada peranti lain"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gunakan peranti yang lain"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-my/strings.xml b/packages/CredentialManager/res/values-my/strings.xml
new file mode 100644
index 0000000..eda2f741
--- /dev/null
+++ b/packages/CredentialManager/res/values-my/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"မလုပ်တော့"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ရှေ့ဆက်ရန်"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"နောက်တစ်နေရာတွင် ပြုလုပ်ရန်"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"နောက်တစ်နေရာတွင် သိမ်းရန်"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"စက်နောက်တစ်ခု သုံးရန်"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"စက်နောက်တစ်ခုတွင် သိမ်းရန်"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"လုံခြုံစွာလက်မှတ်ထိုးဝင်ရန် ရိုးရှင်းသောနည်း"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"မေ့မသွား (သို့) ခိုးမသွားနိုင်သော သီးခြားလျှို့ဝှက်ကီးဖြင့် လက်မှတ်ထိုးဝင်ရန် သင့်လက်ဗွေ၊ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ် သုံးနိုင်သည်။ ပိုမိုလေ့လာရန်"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ရန် နေရာရွေးပါ"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"သင့်စကားဝှက် သိမ်းရန်"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"သင်၏ လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို သိမ်းရန်"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် လျှို့ဝှက်ကီး ပြုလုပ်မလား။"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"သင့်စကားဝှက်ကို <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် သိမ်းမလား။"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"သင်၏ လက်မှတ်ထိုးဝင်သည့်အချက်အလက်ကို <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> တွင် သိမ်းမလား။"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"မည်သည့်စက်တွင်မဆို သင်၏ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ကို သုံးနိုင်သည်။ ၎င်းကို <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> အတွက် <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> တွင် သိမ်းလိုက်သည်"</string>
+    <string name="passkey" msgid="632353688396759522">"လျှို့ဝှက်ကီး"</string>
+    <string name="password" msgid="6738570945182936667">"စကားဝှက်"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"လက်မှတ်ထိုးဝင်မှုများ"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"သင်၏လက်မှတ်ထိုးဝင်မှု အားလုံးအတွက် <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> သုံးမလား။"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"မူရင်းအဖြစ် သတ်မှတ်ရန်"</string>
+    <string name="use_once" msgid="9027366575315399714">"တစ်ကြိမ်သုံးရန်"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"စကားဝှက် <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ခု၊ လျှို့ဝှက်ကီး <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ခု"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"စကားဝှက် <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ခု"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"လျှို့ဝှက်ကီး <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ခု"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"စက်နောက်တစ်ခု"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"အခြားစကားဝှက်မန်နေဂျာများ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"စာမျက်နှာ ပိတ်ရန်"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ယခင်စာမျက်နှာကို ပြန်သွားပါ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသောလျှို့ဝှက်ကီး သုံးမလား။"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသောလက်မှတ်ထိုးဝင်မှု သုံးမလား။"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် သိမ်းထားသော လက်မှတ်ထိုးဝင်မှုကို ရွေးပါ"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"နောက်တစ်နည်းဖြင့် လက်မှတ်ထိုးဝင်ရန်"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"မလိုပါ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ရှေ့ဆက်ရန်"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"လက်မှတ်ထိုးဝင်ရန် နည်းလမ်းများ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> အတွက်"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"လော့ခ်ချထားသည့် စကားဝှက်မန်နေဂျာများ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ဖွင့်ရန် တို့ပါ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"လက်မှတ်ထိုးဝင်မှုများ စီမံခြင်း"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"စက်နောက်တစ်ခုမှ"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"အခြားစက်သုံးရန်"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-nb/strings.xml b/packages/CredentialManager/res/values-nb/strings.xml
new file mode 100644
index 0000000..82854b8
--- /dev/null
+++ b/packages/CredentialManager/res/values-nb/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Avbryt"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Fortsett"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Opprett på et annet sted"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Lagre på et annet sted"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Bruk en annen enhet"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Lagre på en annen enhet"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"En enkel og trygg påloggingsmåte"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Bruk fingeravtrykk, ansiktet eller en skjermlås til å logge på med en unik tilgangsnøkkel du verken kan glemme eller miste. Finn ut mer"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Velg hvor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"lagre passordet ditt"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"lagre påloggingsinformasjonen din"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vil du opprette en tilgangsnøkkel i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vil du lagre passordet i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vil du lagre påloggingsinformasjonen i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Du kan bruke <xliff:g id="TYPE">%2$s</xliff:g>-elementet for <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> på alle slags enheter. Den lagres i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> for <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"tilgangsnøkkel"</string>
+    <string name="password" msgid="6738570945182936667">"passord"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"pålogginger"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vil du bruke <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> for alle pålogginger?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Angi som standard"</string>
+    <string name="use_once" msgid="9027366575315399714">"Bruk én gang"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passord, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> tilgangsnøkler"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> passord"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> tilgangsnøkler"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"En annen enhet"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Andre løsninger for passordlagring"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Lukk arket"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tilbake til den forrige siden"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vil du bruke den lagrede tilgangsnøkkelen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vil du bruke den lagrede påloggingen for <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Velg en lagret pålogging for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Bruk en annen påloggingsmetode"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nei takk"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsett"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Påloggingsalternativer"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"For <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låste løsninger for passordlagring"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Trykk for å låse opp"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Administrer pålogginger"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Fra en annen enhet"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Bruk en annen enhet"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ne/strings.xml b/packages/CredentialManager/res/values-ne/strings.xml
new file mode 100644
index 0000000..23f4f43
--- /dev/null
+++ b/packages/CredentialManager/res/values-ne/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"रद्द गर्नुहोस्"</string>
+    <string name="string_continue" msgid="1346732695941131882">"जारी राख्नुहोस्"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"अर्को ठाउँमा बनाउनुहोस्"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"अर्को ठाउँमा सेभ गर्नुहोस्"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"अर्को डिभाइस प्रयोग गर्नुहोस्"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"अर्को डिभाइसमा सेभ गर्नुहोस्"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"सुरक्षित तरिकाले साइन इन गर्ने सरल तरिका"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"नभुलिने वा चोरी नहुने खालको अद्वितीय पासकीका साथै आफ्ना फिंगरप्रिन्ट, अनुहार वा स्क्रिन लक प्रयोग गरी साइन इन गर्नुहोस्। थप जान्नुहोस्"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> सेभ गर्ने ठाउँ छनौट गर्नुहोस्"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"आफ्नो पासवर्ड सेभ गर्नुहोस्"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"आफ्नो साइन इनसम्बन्धी जानकारी सेभ गर्नुहोस्"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा पासकी बनाउने हो?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"तपाईंको पासवर्ड <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा सेभ गर्ने हो?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"तपाईंको साइन इनसम्बन्धी जानकारी <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> मा सेभ गर्ने हो?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"तपाईं जुनसुकै डिभाइसमा आफ्नो <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> प्रयोग गर्न सक्नुहुन्छ। यसलाई <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> का लागि <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> मा सेभ गरिएको छ"</string>
+    <string name="passkey" msgid="632353688396759522">"पासकी"</string>
+    <string name="password" msgid="6738570945182936667">"पासवर्ड"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"साइन इनसम्बन्धी जानकारी"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"तपाईंले साइन इन गर्ने सबै डिभाइसहरूमा <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> प्रयोग गर्ने हो?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"डिफल्ट जानकारीका रूपमा सेट गर्नुहोस्"</string>
+    <string name="use_once" msgid="9027366575315399714">"एक पटक प्रयोग गर्नुहोस्"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> वटा पासवर्ड, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> वटा पासकी"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> वटा पासवर्ड"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> वटा पासकी"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"अर्को डिभाइस"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"अन्य पासवर्ड म्यानेजरहरू"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"पाना बन्द गर्नुहोस्"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"अघिल्लो पेजमा फर्कनुहोस्"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"आफूले सेभ गरेको पासकी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"आफूले सेभ गरेको साइन इनसम्बन्धी जानकारी प्रयोग गरी <xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्ने हो?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा साइन इन गर्नका लागि सेभ गरिएका साइन इनसम्बन्धी जानकारी छनौट गर्नुहोस्"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"अर्कै विधि प्रयोग गरी साइन इन गर्नुहोस्"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"पर्दैन, धन्यवाद"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"जारी राख्नुहोस्"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"साइन‍ इनसम्बन्धी विकल्पहरू"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> का लागि"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"लक गरिएका पासवर्ड म्यानेजरहरू"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"अनलक गर्न ट्याप गर्नुहोस्"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"साइन इनसम्बन्धी विकल्पहरू व्यवस्थापन गर्नुहोस्"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"अर्को डिभाइसका लागि"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"अर्कै डिभाइस प्रयोग गरी हेर्नुहोस्"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-nl/strings.xml b/packages/CredentialManager/res/values-nl/strings.xml
new file mode 100644
index 0000000..c91a318
--- /dev/null
+++ b/packages/CredentialManager/res/values-nl/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Annuleren"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Doorgaan"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Op een andere locatie maken"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Op een andere locatie opslaan"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Een ander apparaat gebruiken"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Opslaan op een ander apparaat"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Een makkelijke manier om beveiligd in te loggen"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gebruik je vingerafdruk, gezichtsvergrendeling of schermvergrendeling om in te loggen met een unieke toegangssleutel die je niet kunt vergeten en die anderen niet kunnen stelen. Meer informatie"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Een locatie kiezen voor <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"je wachtwoord opslaan"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"je inloggegevens opslaan"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Een toegangssleutel maken in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Je wachtwoord opslaan in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Je inloggegevens opslaan in <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Je kunt je <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> op elk apparaat gebruiken. Het wordt opgeslagen in <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> voor <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"toegangssleutel"</string>
+    <string name="password" msgid="6738570945182936667">"wachtwoord"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"inloggegevens"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> elke keer gebruiken als je inlogt?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Instellen als standaard"</string>
+    <string name="use_once" msgid="9027366575315399714">"Eén keer gebruiken"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wachtwoorden, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> toegangssleutels"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> wachtwoorden"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> toegangssleutels"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Toegangssleutel"</string>
+    <string name="another_device" msgid="5147276802037801217">"Een ander apparaat"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Andere wachtwoordmanagers"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Blad sluiten"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Ga terug naar de vorige pagina"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Je opgeslagen toegangssleutel voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Je opgeslagen inloggegevens voor <xliff:g id="APP_NAME">%1$s</xliff:g> gebruiken?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Opgeslagen inloggegevens kiezen voor <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Inloggen via een andere methode"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nee, bedankt"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Doorgaan"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opties voor inloggen"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Voor <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vergrendelde wachtwoordmanagers"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tik om te ontgrendelen"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Inloggegevens beheren"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via een ander apparaat"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Een ander apparaat gebruiken"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-or/strings.xml b/packages/CredentialManager/res/values-or/strings.xml
new file mode 100644
index 0000000..838ddfe
--- /dev/null
+++ b/packages/CredentialManager/res/values-or/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"ବାତିଲ କରନ୍ତୁ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ଜାରି ରଖନ୍ତୁ"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ତିଆରି କରନ୍ତୁ"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"ଅନ୍ୟ ଏକ ସ୍ଥାନରେ ସେଭ କରନ୍ତୁ"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ଅନ୍ୟ ଏହି ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ଅନ୍ୟ ଏକ ଡିଭାଇସରେ ସେଭ କରନ୍ତୁ"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"ସୁରକ୍ଷିତ ଭାବେ ସାଇନ ଇନ କରିବାର ଏକ ସରଳ ଉପାୟ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ଏକ ସ୍ୱତନ୍ତ୍ର ପାସକୀ ମାଧ୍ୟମରେ ସାଇନ ଇନ କରିବା ପାଇଁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ, ଫେସ କିମ୍ବା ସ୍କ୍ରିନ ଲକ ବ୍ୟବହାର କରନ୍ତୁ ଯାହାକୁ ଭୁଲି ପାରିବେ ନାହିଁ କିମ୍ବା ଚୋରି ହୋଇପାରିବ ନାହିଁ। ଅଧିକ ଜାଣନ୍ତୁ"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"କେଉଁଠି <xliff:g id="CREATETYPES">%1$s</xliff:g> କରିବେ, ତାହା ବାଛନ୍ତୁ"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ଆପଣଙ୍କ ପାସୱାର୍ଡ ସେଭ କରନ୍ତୁ"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ଆପଣଙ୍କ ସାଇନ-ଇନ ସୂଚନା ସେଭ କରନ୍ତୁ"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ଏକ ପାସକୀ ତିଆରି କରିବେ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"ଆପଣଙ୍କ ପାସୱାର୍ଡକୁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ସେଭ କରିବେ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ଆପଣଙ୍କ ସାଇନ-ଇନ ସୂଚନାକୁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ରେ ସେଭ କରିବେ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"ଆପଣ ଯେ କୌଣସି ଡିଭାଇସରେ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>କୁ ବ୍ୟବହାର କରିପାରିବେ। ଏହାକୁ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ପାଇଁ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>ରେ ସେଭ କରାଯାଏ"</string>
+    <string name="passkey" msgid="632353688396759522">"ପାସକୀ"</string>
+    <string name="password" msgid="6738570945182936667">"ପାସୱାର୍ଡ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ସାଇନ-ଇନ"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ଆପଣଙ୍କ ସମସ୍ତ ସାଇନ-ଇନ ପାଇଁ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ବ୍ୟବହାର କରିବେ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ଡିଫଲ୍ଟ ଭାବେ ସେଟ କରନ୍ତୁ"</string>
+    <string name="use_once" msgid="9027366575315399714">"ଥରେ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ଟି ପାସକୀ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ଟି ପାସୱାର୍ଡ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>ଟି ପାସକୀ"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"ଅନ୍ୟ ଏକ ଡିଭାଇସ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"ଅନ୍ୟ Password Manager"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ସିଟ ବନ୍ଦ କରନ୍ତୁ"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ପୂର୍ବବର୍ତ୍ତୀ ପୃଷ୍ଠାକୁ ଫେରନ୍ତୁ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ପାସକୀ ବ୍ୟବହାର କରିବେ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଆପଣଙ୍କ ସାଇନ-ଇନ ବ୍ୟବହାର କରିବେ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ପାଇଁ ସେଭ କରାଯାଇଥିବା ଏକ ସାଇନ-ଇନ ବାଛନ୍ତୁ"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ଅନ୍ୟ ଏକ ଉପାୟରେ ସାଇନ ଇନ କରନ୍ତୁ"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ନା, ଧନ୍ୟବାଦ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ଜାରି ରଖନ୍ତୁ"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ସାଇନ ଇନ ବିକଳ୍ପଗୁଡ଼ିକ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>ରେ"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ଲକ ଥିବା Password Manager"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ଅନଲକ କରିବାକୁ ଟାପ କରନ୍ତୁ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ସାଇନ-ଇନ ପରିଚାଳନା କରନ୍ତୁ"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ଅନ୍ୟ ଏକ ଡିଭାଇସରୁ"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ଏକ ଭିନ୍ନ ଡିଭାଇସ ବ୍ୟବହାର କରନ୍ତୁ"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-pa/strings.xml b/packages/CredentialManager/res/values-pa/strings.xml
new file mode 100644
index 0000000..74b2ab1
--- /dev/null
+++ b/packages/CredentialManager/res/values-pa/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"ਰੱਦ ਕਰੋ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ਜਾਰੀ ਰੱਖੋ"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਬਣਾਓ"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"ਕਿਸੇ ਹੋਰ ਥਾਂ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ਕੋਈ ਹੋਰ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ਕਿਸੇ ਹੋਰ ਡੀਵਾਈਸ \'ਤੇ ਰੱਖਿਅਤ ਕਰੋ"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"ਸੁਰੱਖਿਅਤ ਢੰਗ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਦਾ ਆਸਾਨ ਤਰੀਕਾ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ਵਿਲੱਖਣ ਪਾਸਕੀ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰਨ ਵਾਸਤੇ ਆਪਣੇ ਫਿੰਗਰਪ੍ਰਿੰਟ, ਚਿਹਰੇ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਦੀ ਵਰਤੋਂ ਕਰੋ ਜਿਸਨੂੰ ਭੁੱਲਿਆ ਜਾਂ ਚੋਰੀ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ। ਹੋਰ ਜਾਣੋ"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> ਲਈ ਕੋਈ ਥਾਂ ਚੁਣੋ"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ਆਪਣਾ ਪਾਸਵਰਡ ਰੱਖਿਅਤ ਕਰੋ"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ਆਪਣੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਰੱਖਿਅਤ ਕਰੋ"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"ਕੀ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਪਾਸਕੀ ਨੂੰ ਬਣਾਉਣਾ ਹੈ?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"ਕੀ ਆਪਣੇ ਪਾਸਵਰਡ ਨੂੰ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ਕੀ ਆਪਣੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਨੂੰ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕਰਨਾ ਹੈ?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"ਤੁਸੀਂ ਕਿਸੇ ਵੀ ਡੀਵਾਈਸ \'ਤੇ ਆਪਣੀ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। ਇਸਨੂੰ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ਲਈ <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> ਵਿੱਚ ਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ"</string>
+    <string name="passkey" msgid="632353688396759522">"ਪਾਸਕੀ"</string>
+    <string name="password" msgid="6738570945182936667">"ਪਾਸਵਰਡ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ਸਾਈਨ-ਇਨਾਂ ਦੀ ਜਾਣਕਾਰੀ"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ਕੀ ਆਪਣੇ ਸਾਰੇ ਸਾਈਨ-ਇਨਾਂ ਲਈ<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਵਜੋਂ ਸੈੱਟ ਕਰੋ"</string>
+    <string name="use_once" msgid="9027366575315399714">"ਇੱਕ ਵਾਰ ਵਰਤੋ"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ਪਾਸਵਰਡ, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ਪਾਸਕੀਆਂ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ਪਾਸਵਰਡ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ਪਾਸਕੀਆਂ"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"ਹੋਰ ਡੀਵਾਈਸ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"ਹੋਰ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ਸ਼ੀਟ ਬੰਦ ਕਰੋ"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"ਪਿਛਲੇ ਪੰਨੇ \'ਤੇ ਵਾਪਸ ਜਾਓ"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਪਾਸਕੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ਕੀ <xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਆਪਣੀ ਰੱਖਿਅਤ ਕੀਤੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਦੀ ਵਰਤੋਂ ਕਰਨੀ ਹੈ?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਲਈ ਰੱਖਿਅਤ ਕੀਤੀ ਸਾਈਨ-ਇਨ ਜਾਣਕਾਰੀ ਚੁਣੋ"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ਕਿਸੇ ਹੋਰ ਤਰੀਕੇ ਨਾਲ ਸਾਈਨ-ਇਨ ਕਰੋ"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ਜਾਰੀ ਰੱਖੋ"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ਸਾਈਨ-ਇਨ ਕਰਨ ਦੇ ਵਿਕਲਪ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> ਲਈ"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"ਲਾਕ ਕੀਤੇ ਪਾਸਵਰਡ ਪ੍ਰਬੰਧਕ"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"ਅਣਲਾਕ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"ਸਾਈਨ-ਇਨਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"ਹੋਰ ਡੀਵਾਈਸ ਤੋਂ"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ਵੱਖਰੇ ਡੀਵਾਈਸ ਦੀ ਵਰਤੋਂ ਕਰੋ"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-pl/strings.xml b/packages/CredentialManager/res/values-pl/strings.xml
new file mode 100644
index 0000000..af6bc9d
--- /dev/null
+++ b/packages/CredentialManager/res/values-pl/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Anuluj"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Dalej"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Utwórz w innym miejscu"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Zapisz w innym miejscu"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Użyj innego urządzenia"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Zapisz na innym urządzeniu"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Prosty sposób na bezpieczne logowanie"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Używaj odcisku palca, rozpoznawania twarzy lub blokady ekranu, aby logować się z wykorzystaniem unikalnego klucza, którego nie można zapomnieć ani utracić w wyniku kradzieży. Więcej informacji"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Wybierz, gdzie chcesz <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"zapisać hasło"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"zapisać dane logowania"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Utworzyć klucz w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Zapisać hasło w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Zapisać dane logowania w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Elementu <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> typu <xliff:g id="TYPE">%2$s</xliff:g> możesz używać na każdym urządzeniu. Jest zapisany w usłudze <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> (<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>)"</string>
+    <string name="passkey" msgid="632353688396759522">"klucz"</string>
+    <string name="password" msgid="6738570945182936667">"hasło"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"dane logowania"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Używać usługi <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> w przypadku wszystkich danych logowania?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Ustaw jako domyślną"</string>
+    <string name="use_once" msgid="9027366575315399714">"Użyj raz"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, klucze: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Hasła: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Klucze: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Inne urządzenie"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Inne menedżery haseł"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zamknij arkusz"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Wróć do poprzedniej strony"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Użyć zapisanego klucza dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Użyć zapisanych danych logowania dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Wybierz zapisane dane logowania dla aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Zaloguj się w inny sposób"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nie, dziękuję"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Dalej"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opcje logowania"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zablokowane menedżery haseł"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Kliknij, aby odblokować"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Zarządzanie danymi logowania"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Na innym urządzeniu"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Użyj innego urządzenia"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-pt-rBR/strings.xml b/packages/CredentialManager/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..d950bb4
--- /dev/null
+++ b/packages/CredentialManager/res/values-pt-rBR/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Criar em outro lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma maneira simples de fazer login com segurança"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a impressão digital, o reconhecimento facial ou um bloqueio de tela para fazer login com uma única chave de acesso que não pode ser esquecida ou perdida. Saiba mais"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Criar uma chave de acesso em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvar sua senha em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvar suas informações de login em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Você pode usar seu <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> em qualquer dispositivo. Ele está salvo em <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
+    <string name="password" msgid="6738570945182936667">"senha"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"logins"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
+    <string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Outros gerenciadores de senha"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Fechar página"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Fazer login de outra forma"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Agora não"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de login"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gerenciadores de senha bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toque para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gerenciar logins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-pt-rPT/strings.xml b/packages/CredentialManager/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..c46143c
--- /dev/null
+++ b/packages/CredentialManager/res/values-pt-rPT/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Criar noutro lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Guardar noutro lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Guardar noutro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma forma simples de iniciar sessão em segurança"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a sua impressão digital, rosto ou bloqueio de ecrã para iniciar sessão com uma chave de acesso única que não pode ser esquecida nem perdida. Saiba mais"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde quer guardar <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"criar as suas chaves de acesso"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"guardar a sua palavra-passe"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"guardar as suas informações de início de sessão"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Defina um gestor de palavras-passe predefinido para guardar as suas palavras-passe e chaves de acesso e iniciar sessão mais rapidamente da próxima vez."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Criar uma chave de acesso em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Guardar a sua palavra-passe em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Guardar as suas informações de início de sessão em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Pode usar <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> em qualquer dispositivo. É guardado em <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
+    <string name="password" msgid="6738570945182936667">"palavra-passe"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"inícios de sessão"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Criar chave de acesso em"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Guardar palavra-passe em"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Guardar início de sessão em"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Criar uma chave de acesso noutro dispositivo?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus inícios de sessão?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"Este gestor de palavras-passe armazena as suas palavras-passe e chaves de acesso para ajudar a iniciar sessão facilmente."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Definir como predefinição"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> palavras-passe, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> palavras-passe"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
+    <string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Outros gestores de palavras-passe"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Fechar folha"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Volte à página anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar a sua chave de acesso guardada na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar o seu início de sessão guardado na app <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolha um início de sessão guardado para a app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Iniciar sessão de outra forma"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Não"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de início de sessão"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gestores de palavras-passe bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toque para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Faça a gestão dos inícios de sessão"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Use um dispositivo diferente"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-pt/strings.xml b/packages/CredentialManager/res/values-pt/strings.xml
new file mode 100644
index 0000000..d950bb4
--- /dev/null
+++ b/packages/CredentialManager/res/values-pt/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Gerenciador de credenciais"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Cancelar"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuar"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Criar em outro lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvar em outro lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Usar outro dispositivo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvar em outro dispositivo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Uma maneira simples de fazer login com segurança"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Use a impressão digital, o reconhecimento facial ou um bloqueio de tela para fazer login com uma única chave de acesso que não pode ser esquecida ou perdida. Saiba mais"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Escolha onde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"salvar sua senha"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvar suas informações de login"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Criar uma chave de acesso em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvar sua senha em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvar suas informações de login em <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Você pode usar seu <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> em qualquer dispositivo. Ele está salvo em <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"chave de acesso"</string>
+    <string name="password" msgid="6738570945182936667">"senha"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"logins"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Usar <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para todos os seus logins?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Definir como padrão"</string>
+    <string name="use_once" msgid="9027366575315399714">"Usar uma vez"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chaves de acesso"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> senhas"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chaves de acesso"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Chave de acesso"</string>
+    <string name="another_device" msgid="5147276802037801217">"Outro dispositivo"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Outros gerenciadores de senha"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Fechar página"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Voltar à página anterior"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Usar sua chave de acesso salva para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Usar suas informações de login salvas para <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Escolher um login salvo para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Fazer login de outra forma"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Agora não"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuar"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opções de login"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Gerenciadores de senha bloqueados"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Toque para desbloquear"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gerenciar logins"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De outro dispositivo"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Usar um dispositivo diferente"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ro/strings.xml b/packages/CredentialManager/res/values-ro/strings.xml
new file mode 100644
index 0000000..6947281
--- /dev/null
+++ b/packages/CredentialManager/res/values-ro/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Anulează"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Continuă"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Creează în alt loc"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Salvează în alt loc"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Folosește alt dispozitiv"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Salvează pe alt dispozitiv"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Un mod simplu de a te conecta în siguranță"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Folosește-ți amprenta, fața sau blocarea ecranului ca să te conectezi cu o cheie de acces unică, pe care nu o poți uita și care nu poate fi furată. Află mai multe"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Alege unde <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"salvează parola"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"salvează informațiile de conectare"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Creezi o cheie de acces în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Salvezi parola în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Salvezi informațiile de conectare în <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Poți folosi <xliff:g id="TYPE">%2$s</xliff:g> <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> pe orice dispozitiv. Se salvează în <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pentru <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"cheie de acces"</string>
+    <string name="password" msgid="6738570945182936667">"parolă"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"date de conectare"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Folosești <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> pentru toate conectările?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Setează ca prestabilite"</string>
+    <string name="use_once" msgid="9027366575315399714">"Folosește o dată"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parole, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> chei de acces"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> parole"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> chei de acces"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Alt dispozitiv"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Alți manageri de parole"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Închide foaia"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Revino la pagina precedentă"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Folosești cheia de acces salvată pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Folosești datele de conectare salvate pentru <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Alege o conectare salvată pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Conectează-te altfel"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nu, mulțumesc"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Continuă"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opțiuni de conectare"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pentru <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Manageri de parole blocate"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Atinge pentru a debloca"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Gestionează acreditările"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"De pe alt dispozitiv"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Folosește alt dispozitiv"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ru/strings.xml b/packages/CredentialManager/res/values-ru/strings.xml
new file mode 100644
index 0000000..dcc643e
--- /dev/null
+++ b/packages/CredentialManager/res/values-ru/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Менеджер учетных данных"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Отмена"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Продолжить"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Создать в другом месте"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Сохранить в другом месте"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Использовать другое устройство"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Сохранить на другом устройстве"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Простой и безопасный способ входа"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"С уникальным ключом доступа, который невозможно украсть или забыть, вы можете подтверждать свою личность по отпечатку пальца, с помощью фейсконтроля или блокировки экрана. Подробнее…"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Выберите, где <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"сохранить пароль"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"сохранить данные для входа"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Создать ключ доступа в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Сохранить пароль в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Сохранить учетные данные в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Вы можете использовать <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> на любом устройстве. Данные <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> сохраняются в приложении \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\"."</string>
+    <string name="passkey" msgid="632353688396759522">"ключ доступа"</string>
+    <string name="password" msgid="6738570945182936667">"пароль"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"входы"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Всегда входить с помощью приложения \"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>\"?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Использовать по умолчанию"</string>
+    <string name="use_once" msgid="9027366575315399714">"Использовать один раз"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Пароли (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>) и ключи доступа (<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>)"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Пароли (<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>)"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Ключи доступа (<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>)"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ключ доступа"</string>
+    <string name="another_device" msgid="5147276802037801217">"Другое устройство"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Другие менеджеры паролей"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Закрыть лист"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вернуться на предыдущую страницу"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Использовать сохраненный ключ доступа для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Использовать сохраненные учетные данные для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Выберите сохраненные данные для приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Войти другим способом"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Нет, спасибо"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продолжить"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Варианты входа"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для пользователя <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблокированные менеджеры паролей"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Нажмите для разблокировки"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управление входом"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"С другого устройства"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Использовать другое устройство"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-si/strings.xml b/packages/CredentialManager/res/values-si/strings.xml
new file mode 100644
index 0000000..bf885a9
--- /dev/null
+++ b/packages/CredentialManager/res/values-si/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"අවලංගු කරන්න"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ඉදිරියට යන්න"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"වෙනත් ස්ථානයක තනන්න"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"වෙනත් ස්ථානයකට සුරකින්න"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"වෙනත් උපාංගයක් භාවිතා කරන්න"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"වෙනත් උපාංගයකට සුරකින්න"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"සුරක්ෂිතව පුරනය වීමට සරල ක්‍රමයක්"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"අමතක කළ නොහැකි හෝ සොරකම් කළ නොහැකි අනන්‍ය මුරයතුරක් සමග පුරනය වීමට ඔබේ ඇඟිලි සලකුණ, මුහුණ හෝ තිර අගුල භාවිතා කරන්න. තව දැන ගන්න⁠"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> කොතැනක ද යන්න තෝරා ගන්න"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ඔබේ මුරපදය සුරකින්න"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ඔබේ පුරනය වීමේ තතු සුරකින්න"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> තුළ මුරයතුරක් තනන්න ද?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"ඔබේ මුරපදය <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> වෙත සුරකින්න ද?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"ඔබේ පුරනය වීමේ තතු <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> වෙත සුරකින්න ද?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"ඔබට ඕනෑම උපාංගයක ඔබේ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> භාවිතා කළ හැක. එය <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> සඳහා <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> වෙත සුරැකෙයි"</string>
+    <string name="passkey" msgid="632353688396759522">"මුරයතුර"</string>
+    <string name="password" msgid="6738570945182936667">"මුරපදය"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"පුරනය වීම්"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ඔබේ සියලු පුරනය වීම් සඳහා <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> භාවිතා කරන්න ද?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"පෙරනිමි ලෙස සකසන්න"</string>
+    <string name="use_once" msgid="9027366575315399714">"වරක් භාවිතා කරන්න"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"මුරපද <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ක්, මුරයතුරු <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>ක්"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"මුරපද <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>ක්"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"මුරයතුරු <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>ක්"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"වෙනත් උපාංගයක්"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"වෙනත් මුරපද කළමනාකරුවන්"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"පත්‍රය වසන්න"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"පෙර පිටුවට ආපසු යන්න"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි මුරයතුර භාවිතා කරන්න ද?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා ඔබේ සුරැකි පුරනය භාවිතා කරන්න ද?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා සුරැකි පුරනයක් තෝරා ගන්න"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"වෙනත් ආකාරයකින් පුරන්න"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"එපා ස්තුතියි"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ඉදිරියට යන්න"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"පුරනය වීමේ විකල්ප"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> සඳහා"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"අගුළු දැමූ මුරපද කළමනාකරුවන්"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"අගුළු හැරීමට තට්ටු කරන්න"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"පුරනය වීම් කළමනාකරණය කරන්න"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"වෙනත් උපාංගයකින්"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"වෙනස් උපාංගයක් භාවිතා කරන්න"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sk/strings.xml b/packages/CredentialManager/res/values-sk/strings.xml
new file mode 100644
index 0000000..1c73c57
--- /dev/null
+++ b/packages/CredentialManager/res/values-sk/strings.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Správca prihlasovacích údajov"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Zrušiť"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Pokračovať"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Vytvoriť inde"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Uložiť inde"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Použiť iné zariadenie"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Uložiť do iného zariadenia"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Jednoduchý spôsob bezpečného prihlasovania"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Použite odtlačok prsta, tvár alebo zámku obrazovky a prihláste sa jedinečným prístupovým kľúčom, ktorý sa nedá zabudnúť ani ukradnúť. Ďalšie informácie"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Vyberte, kam <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <string name="create_your_passkeys" msgid="8901224153607590596">"vytvoriť prístupové kľúče"</string>
+    <string name="save_your_password" msgid="6597736507991704307">"uložiť heslo"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"uložiť prihlasovacie údaje"</string>
+    <string name="choose_provider_body" msgid="8045759834416308059">"Nastavte predvoleného správcu hesiel, aby ukladal vaše heslá aj prístupové kľúče, a nabudúce sa prihláste rýchlejšie."</string>
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Chcete vytvoriť prístupový kľúč v službe <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Chcete uložiť heslo do služby <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Chcete uložiť svoje prihlasovacie údaje do služby <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> môžete používať v ľubovoľnom zariadení. Ukladá sa do služby <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> pre <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"prístupový kľúč"</string>
+    <string name="password" msgid="6738570945182936667">"heslo"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prihlasovacie údaje"</string>
+    <string name="create_passkey_in_title" msgid="2714306562710897785">"Vytvorenie prístupového kľúča v umiestnení"</string>
+    <string name="save_password_to_title" msgid="3450480045270186421">"Uloženie hesla do umiestnenia"</string>
+    <string name="save_sign_in_to_title" msgid="8328143607671760232">"Uloženie prihlasovacích údajov do umiestnenia"</string>
+    <string name="create_passkey_in_other_device_title" msgid="6372952459932674632">"Chcete vytvoriť prístupový kľúč v inom zariadení?"</string>
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Chcete pre všetky svoje prihlasovacie údaje použiť <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="use_provider_for_all_description" msgid="6560593199974037820">"Tento správca hesiel uchová vaše heslá a prístupové kľúče, aby vám pomohol ľahšie sa prihlasovať."</string>
+    <string name="set_as_default" msgid="4415328591568654603">"Nastaviť ako predvolené"</string>
+    <string name="use_once" msgid="9027366575315399714">"Použiť raz"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Počet hesiel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, počet prístupových kľúčov <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Počet hesiel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Počet prístupových kľúčov: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Prístupový kľúč"</string>
+    <string name="another_device" msgid="5147276802037801217">"Iné zariadenie"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Iní správcovia hesiel"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zavrieť hárok"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Prejsť späť na predchádzajúcu stránku"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložený prístupový kľúč?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Chcete pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g> použiť uložené prihlasovacie údaje?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Vyberte uložené prihlasovacie údaje pre aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prihláste sa inak"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nie, vďaka"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Pokračovať"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti prihlásenia"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Pre používateľa <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Správcovia uzamknutých hesiel"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Odomknite klepnutím"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Spravovať prihlasovacie údaje"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Z iného zariadenia"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Použiť iné zariadenie"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sl/strings.xml b/packages/CredentialManager/res/values-sl/strings.xml
new file mode 100644
index 0000000..969f290
--- /dev/null
+++ b/packages/CredentialManager/res/values-sl/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Upravitelj poverilnic"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Prekliči"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Naprej"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Ustvarjanje na drugem mestu"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Shranjevanje na drugo mesto"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Uporabi drugo napravo"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Shrani v drugo napravo"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Preprost način za varno prijavo"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Če se želite prijaviti z enoličnim ključem za dostop, ki ga ni mogoče pozabiti ali ukrasti, uporabite prstni odtis, obraz ali nastavljeni način za odklepanje zaslona. Več o tem"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Izberite mesto za <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"shranjevanje gesla"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"shranjevanje podatkov za prijavo"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Želite ustvariti ključ za dostop pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Želite shraniti geslo pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Želite shraniti podatke za prijavo pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="TYPE">%2$s</xliff:g> za <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> lahko uporabite v kateri koli napravi. Shranjeno je pod »<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>« za <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>."</string>
+    <string name="passkey" msgid="632353688396759522">"ključ za dostop"</string>
+    <string name="password" msgid="6738570945182936667">"geslo"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"prijave"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Želite za vse prijave uporabiti »<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>«?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Nastavi kot privzeto"</string>
+    <string name="use_once" msgid="9027366575315399714">"Uporabi enkrat"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Št. gesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, št. ključev za dostop: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Št. gesel: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Št. ključev za dostop: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Ključ za dostop"</string>
+    <string name="another_device" msgid="5147276802037801217">"Druga naprava"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Drugi upravitelji gesel"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Zapri list"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Nazaj na prejšnjo stran"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Želite uporabiti shranjeni ključ za dostop do aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Želite uporabiti shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Izberite shranjene podatke za prijavo v aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Prijava na drug način"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ne, hvala"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Naprej"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Možnosti prijave"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Za uporabnika <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Zaklenjeni upravitelji gesel"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Dotaknite se, da odklenete"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Upravljanje podatkov za prijavo"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Iz druge naprave"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Uporaba druge naprave"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sq/strings.xml b/packages/CredentialManager/res/values-sq/strings.xml
new file mode 100644
index 0000000..bce0683
--- /dev/null
+++ b/packages/CredentialManager/res/values-sq/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Anulo"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Vazhdo"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Krijo në një vend tjetër"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Ruaj në një vend tjetër"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Përdor një pajisje tjetër"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Ruaj në një pajisje tjetër"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Një mënyrë e thjeshtë për t\'u identifikuar në mënyrë të sigurt"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Përdor gjurmën e gishtit, fytyrën ose kyçjen e ekranit për t\'u identifikuar me një çelës unik kalimi i cili nuk mund të harrohet ose të vidhet. Mëso më shumë"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Zgjidh se ku të <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"ruaj fjalëkalimin"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"ruaj informacionet e tua të identifikimit"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Të krijohet një çelës kalimi në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Të ruhet fjalëkalimi në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Të ruhen informacionet e tua të identifikimit në <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Mund të përdorësh <xliff:g id="TYPE">%2$s</xliff:g> të <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> në çdo pajisje. Ai është i ruajtur te <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> për <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"çelësi i kalimit"</string>
+    <string name="password" msgid="6738570945182936667">"fjalëkalimi"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"identifikimet"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Të përdoret <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> për të gjitha identifikimet?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Cakto si parazgjedhje"</string>
+    <string name="use_once" msgid="9027366575315399714">"Përdor një herë"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> fjalëkalime, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> çelësa kalimi"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> fjalëkalime"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> çelësa kalimi"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Një pajisje tjetër"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Menaxherët e tjerë të fjalëkalimeve"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Mbyll fletën"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Kthehu te faqja e mëparshme"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Të përdoret fjalëkalimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Të përdoret identifikimi yt i ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Zgjidh një identifikim të ruajtur për <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Identifikohu me një mënyrë tjetër"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Jo, faleminderit"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Vazhdo"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Opsionet e identifikimit"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Për <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Menaxherët e fjalëkalimeve të kyçura"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Trokit për të shkyçur"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Identifikimet e menaxhimit"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Nga një pajisje tjetër"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Përdor një pajisje tjetër"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sr/strings.xml b/packages/CredentialManager/res/values-sr/strings.xml
new file mode 100644
index 0000000..6a5235c
--- /dev/null
+++ b/packages/CredentialManager/res/values-sr/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Откажи"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Настави"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Направи на другом месту"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Сачувај на другом месту"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Користи други уређај"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Сачувај на други уређај"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Једноставан начин да се безбедно пријављујете"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користите отисак прста, закључавање лицем или закључавање екрана да бисте се пријавили помоћу јединственог приступног кода који не може да се заборави или украде. Сазнајте више"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Одаберите локацију за: <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"сачувајте лозинку"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"сачувајте податке о пријављивању"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Желите да направите приступни кôд код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Желите да сачувате лозинку код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Желите да сачувате податке о пријављивању код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Можете да користите тип домена <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> на било ком уређају. Чува се код корисника <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> за: <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"приступни кôд"</string>
+    <string name="password" msgid="6738570945182936667">"лозинка"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"пријављивања"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Желите да за сва пријављивања користите: <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Подеси као подразумевано"</string>
+    <string name="use_once" msgid="9027366575315399714">"Користи једном"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, приступних кодова:<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Лозинки: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Приступних кодова: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Други уређај"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Други менаџери лозинки"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Затворите табелу"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Вратите се на претходну страницу"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Желите да користите сачувани приступни кôд за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Желите да користите сачуване податке за пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Одаберите сачувано пријављивање за: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Пријавите се на други начин"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Не, хвала"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Настави"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опције за пријављивање"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"За: <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Менаџери закључаних лозинки"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Додирните да бисте откључали"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Управљајте пријављивањима"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Са другог уређаја"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Користи други уређај"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sv/strings.xml b/packages/CredentialManager/res/values-sv/strings.xml
new file mode 100644
index 0000000..a4fffb9
--- /dev/null
+++ b/packages/CredentialManager/res/values-sv/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Credential Manager"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Avbryt"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Fortsätt"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Skapa på en annan plats"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Spara på en annan plats"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Använd en annan enhet"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Spara på en annan enhet"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Ett enkelt sätt att logga in säkert på"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Använd ditt fingeravtryck, ansikte eller skärmlås om du vill logga in med en unik nyckel som inte kan glömmas bort eller bli stulen. Läs mer"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Välj var du <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"spara lösenordet"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"spara inloggningsuppgifterna"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Vill du skapa en nyckel i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Vill du spara ditt lösenord i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Vill du spara dina inloggningsuppgifter i <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Du kan använda <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> på alla enheter. Du kan spara det i <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> för <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"nyckel"</string>
+    <string name="password" msgid="6738570945182936667">"lösenord"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"inloggningar"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Vill du använda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> för alla dina inloggningar?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Ange som standard"</string>
+    <string name="use_once" msgid="9027366575315399714">"Använd en gång"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> lösenord, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> nycklar"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> lösenord"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> nycklar"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Nyckel"</string>
+    <string name="another_device" msgid="5147276802037801217">"En annan enhet"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Andra lösenordshanterare"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Stäng kalkylarket"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Gå tillbaka till föregående sida"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Vill du använda din sparade nyckel för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Vill du använda dina sparade inloggningsuppgifter för <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Välj en sparad inloggning för <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Logga in på ett annat sätt"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Nej tack"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Fortsätt"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Inloggningsalternativ"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"För <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Låsta lösenordshanterare"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Tryck för att låsa upp"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Hantera inloggningar"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Via en annan enhet"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Använd en annan enhet"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-sw/strings.xml b/packages/CredentialManager/res/values-sw/strings.xml
new file mode 100644
index 0000000..bfd1074
--- /dev/null
+++ b/packages/CredentialManager/res/values-sw/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Ghairi"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Endelea"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Unda katika sehemu nyingine"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Hifadhi sehemu nyingine"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Tumia kifaa kingine"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Hifadhi kwenye kifaa kingine"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Njia rahisi ya kuingia katika akaunti kwa usalama"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Tumia alama ya vidole, uso au kipengele cha kufunga skrini ili uingie katika kaunti kwa kutumia nenosiri la kipekee ambalo haliwezi kusahaulika au kuibiwa. Pata maelezo zaidi"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Chagua mahali pa <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"hifadhi nenosiri lako"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"hifadhi maelezo yako ya kuingia katika akaunti"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Ungependa kuunda ufunguo wa siri katika <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Ungependa kuhifadhi nenosiri lako kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Ungependa kuhifadhi maelezo yako ya kuingia katika akaunti kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Unaweza kutumia <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> yako ya <xliff:g id="TYPE">%2$s</xliff:g> kwenye kifaa chochote. Imehifadhiwa kwenye <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> kwa ajili ya <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"ufunguo wa siri"</string>
+    <string name="password" msgid="6738570945182936667">"nenosiri"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"michakato ya kuingia katika akaunti"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Ungependa kutumia <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kwa ajili ya michakato yako yote ya kuingia katika akaunti?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Weka iwe chaguomsingi"</string>
+    <string name="use_once" msgid="9027366575315399714">"Tumia mara moja"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Manenosiri <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, funguo <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> za siri"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Manenosiri <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Funguo <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> za siri"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Kifaa kingine"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Vidhibiti vinginevyo vya manenosiri"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Funga laha"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Rudi kwenye ukurasa uliotangulia"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Ungependa kutumia ufunguo wa siri uliohifadhiwa wa<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Ungependa kutumia kitambulisho kilichohifadhiwa cha kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Chagua vitambulisho vilivyohifadhiwa kwa ajili ya kuingia katika akaunti ya <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Ingia katika akaunti kwa kutumia njia nyingine"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Hapana"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Endelea"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Chaguo za kuingia katika akaunti"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Kwa ajili ya <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Vidhibiti vya manenosiri vilivyofungwa"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Gusa ili ufungue"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Dhibiti michakato ya kuingia katika akaunti"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kutoka kwenye kifaa kingine"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Tumia kifaa tofauti"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ta/strings.xml b/packages/CredentialManager/res/values-ta/strings.xml
new file mode 100644
index 0000000..10c5259
--- /dev/null
+++ b/packages/CredentialManager/res/values-ta/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"ரத்துசெய்"</string>
+    <string name="string_continue" msgid="1346732695941131882">"தொடர்க"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"மற்றொரு இடத்தில் உருவாக்கவும்"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"மற்றொரு இடத்தில் சேமிக்கவும்"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"மற்றொரு சாதனத்தைப் பயன்படுத்தவும்"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"வேறொரு சாதனத்தில் சேமியுங்கள்"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"பாதுகாப்பாக உள்நுழைவதற்கான எளிய வழி"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"தனித்துவமான கடவுக்குறியீடு (மறக்காதவை அல்லது திருடமுடியாதவை) மூலம் உள்நுழைய, உங்கள் கைரேகை, முகம் அல்லது திரைப்பூட்டைப் பயன்படுத்தி உள்நுழையவும். மேலும் அறிக"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> எங்கே காட்டப்பட வேண்டும் என்பதைத் தேர்வுசெய்தல்"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"உங்கள் கடவுச்சொல்லைச் சேமிக்கவும்"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"உங்கள் உள்நுழைவு தகவலைச் சேமிக்கவும்"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் கடவுக்குறியீட்டை உருவாக்க வேண்டுமா?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"உங்கள் கடவுச்சொல்லை <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் சேமிக்க வேண்டுமா?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"உங்கள் உள்நுழைவுத் தகவலை <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ல் சேமிக்க வேண்டுமா?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"உங்கள் <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ஐ எந்தச் சாதனத்தில் வேண்டுமானாலும் பயன்படுத்தலாம். <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>ல் <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>க்காகச் சேமிக்கப்பட்டது"</string>
+    <string name="passkey" msgid="632353688396759522">"கடவுக்குறியீடு"</string>
+    <string name="password" msgid="6738570945182936667">"கடவுச்சொல்"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"உள்நுழைவுகள்"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"உங்கள் அனைத்து உள்நுழைவுகளுக்கும் <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ஐப் பயன்படுத்தவா?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"இயல்பானதாக அமை"</string>
+    <string name="use_once" msgid="9027366575315399714">"ஒருமுறை பயன்படுத்தவும்"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> கடவுச்சொற்கள், <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> கடவுக்குறியீடுகள்"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> கடவுச்சொற்கள்"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> கடவுக்குறியீடுகள்"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"மற்றொரு சாதனம்"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"பிற கடவுச்சொல் நிர்வாகிகள்"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ஷீட்டை மூடும்"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"முந்தைய பக்கத்திற்குச் செல்லும்"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட கடவுக்குறியீட்டைப் பயன்படுத்தவா?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட உள்நுழைவுத் தகவலைப் பயன்படுத்தவா?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸுக்கு ஏற்கெனவே சேமிக்கப்பட்ட உள்நுழைவுத் தகவலைத் தேர்வுசெய்யவும்"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"வேறு முறையில் உள்நுழைக"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"வேண்டாம்"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"தொடர்க"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"உள்நுழைவு விருப்பங்கள்"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g>க்கு"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"பூட்டப்பட்ட கடவுச்சொல் நிர்வாகிகள்"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"அன்லாக் செய்ய தட்டவும்"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"உள்நுழைவுகளை நிர்வகித்தல்"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"மற்றொரு சாதனத்திலிருந்து பயன்படுத்து"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"வேறு சாதனத்தைப் பயன்படுத்து"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-te/strings.xml b/packages/CredentialManager/res/values-te/strings.xml
new file mode 100644
index 0000000..f7617b3
--- /dev/null
+++ b/packages/CredentialManager/res/values-te/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"రద్దు చేయండి"</string>
+    <string name="string_continue" msgid="1346732695941131882">"కొనసాగించండి"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"మరొక స్థలంలో క్రియేట్ చేయండి"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"మరొక స్థలంలో సేవ్ చేయండి"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"మరొక పరికరాన్ని ఉపయోగించండి"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"మరొక పరికరంలో సేవ్ చేయండి"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"సురక్షితంగా సైన్ ఇన్ చేయడానికి సులభమైన మార్గం"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"మర్చిపోలేని లేదా దొంగిలించలేని ప్రత్యేకమైన పాస్-కీతో సైన్ ఇన్ చేయడానికి మీ వేలిముద్ర, ముఖం లేదా స్క్రీన్ లాక్‌ను ఉపయోగించండి. మరింత తెలుసుకోండి"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"ఎక్కడ <xliff:g id="CREATETYPES">%1$s</xliff:g> చేయాలో ఎంచుకోండి"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"మీ పాస్‌వర్డ్‌ను సేవ్ చేయండి"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"మీ సైన్ ఇన్ సమాచారాన్ని సేవ్ చేయండి"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>లో పాస్-కీని క్రియేట్ చేయాలా?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"మీ పాస్‌వర్డ్‌ను <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>కు సేవ్ చేయాలా?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"మీ సైన్ ఇన్ సమాచారాన్ని <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>కు సేవ్ చేయాలా?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"మీరు మీ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>ని ఏ పరికరంలోనైనా ఉపయోగించవచ్చు. ఇది <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> కోసం <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>లో సేవ్ చేయబడింది"</string>
+    <string name="passkey" msgid="632353688396759522">"పాస్-కీ"</string>
+    <string name="password" msgid="6738570945182936667">"పాస్‌వర్డ్"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"సైన్‌ ఇన్‌లు"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"మీ అన్ని సైన్-ఇన్ వివరాల కోసం <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>ను ఉపయోగించాలా?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ఆటోమేటిక్ సెట్టింగ్‌గా సెట్ చేయండి"</string>
+    <string name="use_once" msgid="9027366575315399714">"ఒకసారి ఉపయోగించండి"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> పాస్‌వర్డ్‌లు, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> పాస్-కీలు"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> పాస్‌వర్డ్‌లు"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> పాస్-కీలు"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"మరొక పరికరం"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"ఇతర పాస్‌వర్డ్ మేనేజర్‌లు"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"షీట్‌ను మూసివేయండి"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"మునుపటి పేజీకి తిరిగి వెళ్లండి"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీ సేవ్ చేసిన పాస్-కీ వివరాలను ఉపయోగించాలా?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం మీరు సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఉపయోగించాలా?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> కోసం సేవ్ చేసిన సైన్ ఇన్ వివరాలను ఎంచుకోండి"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"మరొక పద్ధతిలో సైన్ ఇన్ చేయండి"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"వద్దు, థ్యాంక్స్"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"కొనసాగించండి"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"సైన్ ఇన్ ఆప్షన్‌లు"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> కోసం"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"లాక్ చేయబడిన పాస్‌వర్డ్ మేనేజర్‌లు"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"అన్‌లాక్ చేయడానికి ట్యాప్ చేయండి"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"సైన్‌ ఇన్‌లను మేనేజ్ చేయండి"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"మరొక పరికరం నుండి"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"వేరే పరికరాన్ని ఉపయోగించండి"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-th/strings.xml b/packages/CredentialManager/res/values-th/strings.xml
new file mode 100644
index 0000000..d70e94a
--- /dev/null
+++ b/packages/CredentialManager/res/values-th/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"เครื่องมือจัดการข้อมูลเข้าสู่ระบบ"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"ยกเลิก"</string>
+    <string name="string_continue" msgid="1346732695941131882">"ต่อไป"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"สร้างในตำแหน่งอื่น"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"บันทึกลงในตำแหน่งอื่น"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"ใช้อุปกรณ์อื่น"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"ย้ายไปยังอุปกรณ์อื่น"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"วิธีง่ายๆ ในการลงชื่อเข้าใช้อย่างปลอดภัย"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"ใช้ลายนิ้วมือ ใบหน้า หรือล็อกหน้าจอในการลงชื่อเข้าใช้ด้วยพาสคีย์ที่ไม่ซ้ำกันเพื่อไม่ให้ลืมหรือถูกขโมยได้ ดูข้อมูลเพิ่มเติม"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"เลือกตำแหน่งที่จะ <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"บันทึกรหัสผ่าน"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"บันทึกข้อมูลการลงชื่อเข้าใช้"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"สร้างพาสคีย์ใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"บันทึกรหัสผ่านลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"บันทึกข้อมูลการลงชื่อเข้าใช้ลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ใช่ไหม"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"คุณใช้ <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> ในอุปกรณ์ใดก็ได้ โดยจะบันทึกลงใน <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> สำหรับ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"พาสคีย์"</string>
+    <string name="password" msgid="6738570945182936667">"รหัสผ่าน"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"การลงชื่อเข้าใช้"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"ใช้ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> สำหรับการลงชื่อเข้าใช้ทั้งหมดใช่ไหม"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"ตั้งเป็นค่าเริ่มต้น"</string>
+    <string name="use_once" msgid="9027366575315399714">"ใช้ครั้งเดียว"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"รหัสผ่าน <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> รายการ พาสคีย์ <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> รายการ"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"รหัสผ่าน <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> รายการ"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"พาสคีย์ <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> รายการ"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"พาสคีย์"</string>
+    <string name="another_device" msgid="5147276802037801217">"อุปกรณ์อื่น"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"เครื่องมือจัดการรหัสผ่านอื่นๆ"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"ปิดชีต"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"กลับไปยังหน้าก่อนหน้า"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"ใช้พาสคีย์ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ใช่ไหม"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"ใช้การลงชื่อเข้าใช้ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" ใช่ไหม"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"เลือกการลงชื่อเข้าใช้ที่บันทึกไว้สำหรับ \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"ลงชื่อเข้าใช้ด้วยวิธีอื่น"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"ไม่เป็นไร"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"ต่อไป"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"ตัวเลือกการลงชื่อเข้าใช้"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"สำหรับ <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"เครื่องมือจัดการรหัสผ่านที่ล็อกไว้"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"แตะเพื่อปลดล็อก"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"จัดการการลงชื่อเข้าใช้"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"จากอุปกรณ์อื่น"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ใช้อุปกรณ์อื่น"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-tl/strings.xml b/packages/CredentialManager/res/values-tl/strings.xml
new file mode 100644
index 0000000..01fd2f0
--- /dev/null
+++ b/packages/CredentialManager/res/values-tl/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"Manager ng Kredensyal"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"Kanselahin"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Magpatuloy"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Gumawa sa ibang lugar"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"I-save sa ibang lugar"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Gumamit ng ibang device"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"I-save sa ibang device"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Simpleng paraan para mag-sign in lang ligtas"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Gamitin ang iyong fingerprint, mukha, o lock ng screen para mag-sign in gamit ang natatanging passkey na hindi makakalimutan o mananakaw. Matuto pa"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Piliin kung saan <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"i-save ang iyong password"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"i-save ang iyong impormasyon sa pag-sign in"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Gumawa ng passkey sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"I-save ang iyong password sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"I-save ang iyong impormasyon sa pag-sign in sa <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Magagamit mo ang iyong <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> sa anumang device. Naka-save ito sa <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> para sa <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"passkey"</string>
+    <string name="password" msgid="6738570945182936667">"password"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"mga sign-in"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Gamitin ang <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> para sa lahat ng iyong pag-sign in?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Itakda bilang default"</string>
+    <string name="use_once" msgid="9027366575315399714">"Gamitin nang isang beses"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> (na) password, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> (na) passkey"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> (na) password"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> (na) passkey"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"Passkey"</string>
+    <string name="another_device" msgid="5147276802037801217">"Ibang device"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Iba pang password manager"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Isara ang sheet"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Bumalik sa nakaraang page"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Gamitin ang iyong naka-save na passkey para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Gamitin ang iyong naka-save na sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Pumili ng naka-save na sign-in para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Mag-sign in sa ibang paraan"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Hindi, salamat na lang"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Magpatuloy"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Mga opsyon sa pag-sign in"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Para kay <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Mga naka-lock na password manager"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"I-tap para i-unlock"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Pamahalaan ang mga sign-in"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Mula sa ibang device"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Gumamit ng ibang device"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-tr/strings.xml b/packages/CredentialManager/res/values-tr/strings.xml
new file mode 100644
index 0000000..30ed43e
--- /dev/null
+++ b/packages/CredentialManager/res/values-tr/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"İptal"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Devam"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Başka bir yerde oluşturun"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Başka bir yere kaydedin"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Başka bir cihaz kullan"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Başka bir cihaza kaydet"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Güvenli bir şekilde oturum açmanın basit yolu"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Parmak iziniz, yüzünüz ya da ekran kilidinizi kullanarak unutması veya çalınması mümkün olmayan benzersiz bir şifre anahtarıyla oturum açın. Daha fazla bilgi"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> yerini seçin"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"şifrenizi kaydedin"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"oturum açma bilgilerinizi kaydedin"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içinde şifre anahtarı oluşturulsun mu?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Şifreniz <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içine kaydedilsin mi?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Oturum açma bilgileriniz <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> içine kaydedilsin mi?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> herhangi bir cihazda kullanılabilir. <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> için <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> içine kaydedilir"</string>
+    <string name="passkey" msgid="632353688396759522">"şifre anahtarı"</string>
+    <string name="password" msgid="6738570945182936667">"şifre"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"oturum aç"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Tüm oturum açma işlemlerinizde <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kullanılsın mı?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Varsayılan olarak ayarla"</string>
+    <string name="use_once" msgid="9027366575315399714">"Bir kez kullanın"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> şifre, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> şifre anahtarı"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> şifre"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> şifre anahtarı"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Başka bir cihaz"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Diğer şifre yöneticileri"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Sayfayı kapat"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Önceki sayfaya geri dön"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı şifre anahtarınız kullanılsın mı?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı oturum açma bilgileriniz kullanılsın mı?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> için kayıtlı oturum açma bilgilerini kullanın"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Başka bir yöntemle oturum aç"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Hayır, teşekkürler"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Devam"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Oturum açma seçenekleri"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> için"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Kilitli şifre yöneticileri"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Kilidi açmak için dokunun"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Oturum açma bilgilerini yönetin"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Başka bir cihazdan"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Farklı bir cihaz kullan"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-uk/strings.xml b/packages/CredentialManager/res/values-uk/strings.xml
new file mode 100644
index 0000000..69d4612
--- /dev/null
+++ b/packages/CredentialManager/res/values-uk/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Скасувати"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Продовжити"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Створити в іншому місці"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Зберегти в іншому місці"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Скористатись іншим пристроєм"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Зберегти на іншому пристрої"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Зручний спосіб для безпечного входу"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Користуйтеся відбитком пальця, фейсконтролем або іншим способом розблокування екрана, щоб входити в обліковий запис за допомогою унікального ключа доступу, який неможливо забути чи викрасти. Докладніше"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Виберіть, де <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"зберегти пароль"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"зберегти дані для входу"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Створити ключ доступу в сервісі <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Зберегти ваш пароль у сервісі <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Зберегти ваші дані для входу в сервіс <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Ви можете використовувати <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> на будь-якому пристрої. Його збережено в постачальника послуг \"<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>\" для <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"ключ доступу"</string>
+    <string name="password" msgid="6738570945182936667">"пароль"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"дані для входу"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Використовувати сервіс <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> в усіх випадках входу?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Вибрати за умовчанням"</string>
+    <string name="use_once" msgid="9027366575315399714">"Скористатися раз"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Кількість паролів: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>; кількість ключів доступу: <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Кількість паролів: <xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Кількість ключів доступу: <xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Інший пристрій"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Інші менеджери паролів"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Закрити аркуш"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Повернутися на попередню сторінку"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Використати збережений ключ доступу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Використати збережені дані для входу для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Виберіть збережені дані для входу в додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Увійти іншим способом"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Ні, дякую"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Продовжити"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Опції входу"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Для користувача <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Заблоковані менеджери паролів"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Торкніться, щоб розблокувати"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Керування даними для входу"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"З іншого пристрою"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Використовувати інший пристрій"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-ur/strings.xml b/packages/CredentialManager/res/values-ur/strings.xml
new file mode 100644
index 0000000..2d66079
--- /dev/null
+++ b/packages/CredentialManager/res/values-ur/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"سند سے متعلق مینیجر"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"منسوخ کریں"</string>
+    <string name="string_continue" msgid="1346732695941131882">"جاری رکھیں"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"دوسرے مقام میں تخلیق کریں"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"دوسرے مقام میں محفوظ کریں"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"کوئی دوسرا آلہ استعمال کریں"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"دوسرے آلے میں محفوظ کریں"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"محفوظ طریقے سے سائن ان کرنے کا آسان طریقہ"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"اپنے فنگر پرنٹ، چہرے یا اسکرین لاک کا استعمال کریں تاکہ ایک ایسی منفرد پاس کی سے سائن ان کیا جا سکے جسے بھولا یا چوری نہیں کیا جا سکتا۔ مزید جانیں"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> کی جگہ منتخب کریں"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"اپنا پاس ورڈ محفوظ کریں"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"اپنے سائن ان کی معلومات محفوظ کریں"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں پاس کی تخلیق کریں؟"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"اپنا پاس ورڈ <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں محفوظ کریں؟"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"اپنے سائن ان کی معلومات کو <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> میں محفوظ کریں؟"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"آپ کسی بھی آلے پر اپنا <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> استعمال کر سکتے ہیں۔ یہ <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> کے <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> میں محفوظ ہو جاتا ہے"</string>
+    <string name="passkey" msgid="632353688396759522">"پاس کی"</string>
+    <string name="password" msgid="6738570945182936667">"پاس ورڈ"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"سائن انز"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"اپنے سبھی سائن انز کے لیے <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> کا استعمال کریں؟"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"بطور ڈیفالٹ سیٹ کریں"</string>
+    <string name="use_once" msgid="9027366575315399714">"ایک بار استعمال کریں"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> پاس ورڈز، <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> پاس کیز"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> پاس ورڈز"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> پاس کیز"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"پاس کی"</string>
+    <string name="another_device" msgid="5147276802037801217">"دوسرا آلہ"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"دیگر پاس ورڈ مینیجرز"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"شیٹ بند کریں"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"گزشتہ صفحے پر واپس جائیں"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنی محفوظ کردہ پاس کی استعمال کریں؟"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے اپنے محفوظ کردہ سائن ان کو استعمال کریں؟"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لیے محفوظ کردہ سائن انز منتخب کریں"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"دوسرے طریقے سے سائن ان کریں"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"نہیں شکریہ"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"جاری رکھیں"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"سائن ان کے اختیارات"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> کے لیے"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"مقفل کردہ پاس ورڈ مینیجرز"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"غیر مقفل کرنے کے لیے تھپتھپائیں"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"سائن انز کا نظم کریں"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"دوسرے آلے سے"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"ایک مختلف آلہ استعمال کریں"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-uz/strings.xml b/packages/CredentialManager/res/values-uz/strings.xml
new file mode 100644
index 0000000..4ac35b2
--- /dev/null
+++ b/packages/CredentialManager/res/values-uz/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Bekor qilish"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Davom etish"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Boshqa joyda yaratish"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Boshqa joyga saqlash"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Boshqa qurilmadan foydalaning"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Boshqa qurilmaga saqlash"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Xavfsiz kirishning oddiy usuli"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Esda qoladigan maxsus kalit bilan kirishda barmoq izi, yuz axboroti yoki ekran qulfidan foydalaning. Batafsil"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"<xliff:g id="CREATETYPES">%1$s</xliff:g> joyini tanlang"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"Parolni saqlash"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"kirish axborotini saqlang"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Kalit <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida yaratilsinmi?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Parol <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida saqlansinmi?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Hisob maʼlumotlari <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> xizmatida saqlansinmi?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> istalgan qurilmada ishlatilishi mumkin. U <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> uchun <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> xizmatiga saqlandi"</string>
+    <string name="passkey" msgid="632353688396759522">"kalit"</string>
+    <string name="password" msgid="6738570945182936667">"parol"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"kirishlar"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Hamma kirishlarda <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> ishlatilsinmi?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Birlamchi deb belgilash"</string>
+    <string name="use_once" msgid="9027366575315399714">"Bir marta ishlatish"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ta parol, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> ta kalit"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> ta parol"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> ta kalit"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Boshqa qurilma"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Boshqa parol menejerlari"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Varaqni yopish"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Avvalgi sahifaga qaytish"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan kalit ishlatilsinmi?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"<xliff:g id="APP_NAME">%1$s</xliff:g> uchun saqlangan maʼlumotlar ishlatilsinmi?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"<xliff:g id="APP_NAME">%1$s</xliff:g> hisob maʼlumotlarini tanlang"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Boshqa usul orqali kirish"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Kerak emas"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Davom etish"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Kirish parametrlari"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> uchun"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Qulfli parol menejerlari"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Qulfni ochish uchun bosing"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Hisob maʼlumotlarini boshqarish"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Boshqa qurilmada"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Boshqa qurilmadan foydalanish"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-vi/strings.xml b/packages/CredentialManager/res/values-vi/strings.xml
new file mode 100644
index 0000000..fd5b986
--- /dev/null
+++ b/packages/CredentialManager/res/values-vi/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Huỷ"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Tiếp tục"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Tạo ở vị trí khác"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Lưu vào vị trí khác"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Dùng thiết bị khác"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Lưu vào thiết bị khác"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Cách đơn giản để đăng nhập an toàn"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Dùng vân tay, khuôn mặt hoặc phương thức khoá màn hình để đăng nhập bằng một mã xác thực duy nhất mà bạn không lo sẽ quên hay bị đánh cắp. Tìm hiểu thêm"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Chọn vị trí <xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"lưu mật khẩu của bạn"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"lưu thông tin đăng nhập của bạn"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Tạo một mã xác thực trong <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Lưu mật khẩu của bạn vào <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Lưu thông tin đăng nhập của bạn vào <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Bạn có thể sử dụng <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> trên mọi thiết bị. Thông tin này được lưu vào <xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g> cho <xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"mã xác thực"</string>
+    <string name="password" msgid="6738570945182936667">"mật khẩu"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"thông tin đăng nhập"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Dùng <xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> cho mọi thông tin đăng nhập của bạn?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Đặt làm mặc định"</string>
+    <string name="use_once" msgid="9027366575315399714">"Dùng một lần"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mật khẩu, <xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> mã xác thực"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> mật khẩu"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> mã xác thực"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Thiết bị khác"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Trình quản lý mật khẩu khác"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Đóng trang tính"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Quay lại trang trước"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Dùng mã xác thực bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Dùng thông tin đăng nhập bạn đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Chọn thông tin đăng nhập đã lưu cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Đăng nhập bằng cách khác"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Không, cảm ơn"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Tiếp tục"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Tuỳ chọn đăng nhập"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Cho <xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Trình quản lý mật khẩu đã khoá"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Nhấn để mở khoá"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Quản lý thông tin đăng nhập"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Từ một thiết bị khác"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Dùng thiết bị khác"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-zh-rCN/strings.xml b/packages/CredentialManager/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..a14dd2f
--- /dev/null
+++ b/packages/CredentialManager/res/values-zh-rCN/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"取消"</string>
+    <string name="string_continue" msgid="1346732695941131882">"继续"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"在另一位置创建"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"保存到另一位置"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"使用另一台设备"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"保存到其他设备"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"简单又安全的登录方式"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"借助指纹、人脸识别或屏幕锁定功能,使用不会被忘记或被盗且具有唯一性的通行密钥登录。了解详情"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"选择<xliff:g id="CREATETYPES">%1$s</xliff:g>的位置"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"保存您的密码"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"保存您的登录信息"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"在“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”中创建通行密钥?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"将您的密码保存至“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"将您的登录信息保存至“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"您可以在任意设备上使用 <xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g>。它会保存到“<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>”的<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"通行密钥"</string>
+    <string name="password" msgid="6738570945182936667">"密码"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"登录"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"将“<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>”用于您的所有登录信息?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"设为默认项"</string>
+    <string name="use_once" msgid="9027366575315399714">"使用一次"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 个密码,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 个通行密钥"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 个密码"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 个通行密钥"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"另一台设备"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"其他密码管理工具"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"关闭工作表"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一页"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"将您已保存的通行密钥用于<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"将您已保存的登录信息用于<xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"为<xliff:g id="APP_NAME">%1$s</xliff:g>选择已保存的登录信息"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"以另一种方式登录"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"不用了"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"继续"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登录选项"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"用户:<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已锁定的密码管理工具"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"点按即可解锁"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登录信息"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"通过另一台设备"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他设备"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-zh-rHK/strings.xml b/packages/CredentialManager/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..71dfa1a
--- /dev/null
+++ b/packages/CredentialManager/res/values-zh-rHK/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"憑證管理工具"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"取消"</string>
+    <string name="string_continue" msgid="1346732695941131882">"繼續"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"在其他位置建立"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全又簡便的登入方式"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"使用指紋、面孔或螢幕鎖定配合密鑰登入。密鑰獨一無二,您不用擔心忘記密鑰或密鑰被盜。瞭解詳情"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資料"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"要在「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」建立密鑰嗎?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"要將密碼儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"要將登入資料儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"您可以在任何裝置上使用「<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>」<xliff:g id="TYPE">%2$s</xliff:g>。系統會將此資料儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>」,供「<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>」使用"</string>
+    <string name="passkey" msgid="632353688396759522">"密鑰"</string>
+    <string name="password" msgid="6738570945182936667">"密碼"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"登入資料"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"要將「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」用於所有的登入資料嗎?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"設定為預設"</string>
+    <string name="use_once" msgid="9027366575315399714">"單次使用"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 個密鑰"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 個密鑰"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"密碼金鑰"</string>
+    <string name="another_device" msgid="5147276802037801217">"其他裝置"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"其他密碼管理工具"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"閂工作表"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一頁"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密鑰嗎?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料嗎?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資料"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"使用其他方式登入"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"不用了,謝謝"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"繼續"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登入選項"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 專用"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"輕按即可解鎖"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資料"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-zh-rTW/strings.xml b/packages/CredentialManager/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..0d636c2
--- /dev/null
+++ b/packages/CredentialManager/res/values-zh-rTW/strings.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="app_name" msgid="4539824758261855508">"憑證管理工具"</string>
+    <string name="string_cancel" msgid="6369133483981306063">"取消"</string>
+    <string name="string_continue" msgid="1346732695941131882">"繼續"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"在其他位置建立"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"儲存至其他位置"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"改用其他裝置"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"儲存至其他裝置"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"安全又簡單的登入方式"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"登入帳戶時,你可以使用指紋、人臉或螢幕鎖定功能搭配不重複的密碼金鑰,不必擔心忘記密碼金鑰或遭人竊取。瞭解詳情"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"選擇「<xliff:g id="CREATETYPES">%1$s</xliff:g>」的位置"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"儲存密碼"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"儲存登入資訊"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"要在「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」建立密碼金鑰嗎?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"要將密碼儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"要將登入資訊儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」嗎?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"你可以在任何裝置上使用「<xliff:g id="APPDOMAINNAME">%1$s</xliff:g>」<xliff:g id="TYPE">%2$s</xliff:g>。系統會將這項資料儲存至「<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>」,以供「<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g>」使用"</string>
+    <string name="passkey" msgid="632353688396759522">"密碼金鑰"</string>
+    <string name="password" msgid="6738570945182936667">"密碼"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"登入資訊"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"要將「<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>」用於所有的登入資訊嗎?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"設為預設"</string>
+    <string name="use_once" msgid="9027366575315399714">"單次使用"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼,<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g> 個密碼金鑰"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g> 個密碼"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g> 個密碼金鑰"</string>
+    <string name="passkey_before_subtitle" msgid="2448119456208647444">"密碼金鑰"</string>
+    <string name="another_device" msgid="5147276802037801217">"其他裝置"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"其他密碼管理工具"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"關閉功能表"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"返回上一頁"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」密碼金鑰嗎?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"要使用已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資訊嗎?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"選擇已儲存的「<xliff:g id="APP_NAME">%1$s</xliff:g>」登入資訊"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"使用其他方式登入"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"不用了,謝謝"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"繼續"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"登入選項"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"<xliff:g id="USERNAME">%1$s</xliff:g> 專用"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"已鎖定的密碼管理工具"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"輕觸即可解鎖"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"管理登入資訊"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"透過其他裝置"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"使用其他裝置"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values-zu/strings.xml b/packages/CredentialManager/res/values-zu/strings.xml
new file mode 100644
index 0000000..a35c6d2
--- /dev/null
+++ b/packages/CredentialManager/res/values-zu/strings.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- no translation found for app_name (4539824758261855508) -->
+    <skip />
+    <string name="string_cancel" msgid="6369133483981306063">"Khansela"</string>
+    <string name="string_continue" msgid="1346732695941131882">"Qhubeka"</string>
+    <string name="string_create_in_another_place" msgid="1033635365843437603">"Sungula kwenye indawo"</string>
+    <string name="string_save_to_another_place" msgid="7590325934591079193">"Londoloza kwenye indawo"</string>
+    <string name="string_use_another_device" msgid="8754514926121520445">"Sebenzisa enye idivayisi"</string>
+    <string name="string_save_to_another_device" msgid="1959562542075194458">"Londoloza kwenye idivayisi"</string>
+    <string name="passkey_creation_intro_title" msgid="402553911484409884">"Indlela elula yokungena ngemvume ngokuphephile"</string>
+    <string name="passkey_creation_intro_body" msgid="7493320456005579290">"Sebenzisa isigxivizo somunwe, ubuso noma ukukhiya isikrini ukuze ungene ngemvume ngokhiye wokudlula oyingqayizivele ongenakulibaleka noma owebiwe. Funda kabanzi"</string>
+    <string name="choose_provider_title" msgid="7245243990139698508">"Khetha lapho onga-<xliff:g id="CREATETYPES">%1$s</xliff:g>"</string>
+    <!-- no translation found for create_your_passkeys (8901224153607590596) -->
+    <skip />
+    <string name="save_your_password" msgid="6597736507991704307">"Londoloza iphasiwedi yakho"</string>
+    <string name="save_your_sign_in_info" msgid="7213978049817076882">"londoloza ulwazi lwakho lokungena ngemvume"</string>
+    <!-- no translation found for choose_provider_body (8045759834416308059) -->
+    <skip />
+    <string name="choose_create_option_passkey_title" msgid="4146408187146573131">"Sungula ukhiye wokungena ku-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_password_title" msgid="8812546498357380545">"Londoloza ulwazi lwakho lwephasiwedi ku-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_sign_in_title" msgid="6318246378475961834">"Londoloza ulwazi lwakho lokungena ngemvume ku-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g>?"</string>
+    <string name="choose_create_option_description" msgid="4419171903963100257">"Ungasebenzisa i-<xliff:g id="APPDOMAINNAME">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> kunoma iyiphi idivayisi. Ilondolozelwe i-<xliff:g id="CREATEINFODISPLAYNAME">%4$s</xliff:g> ku-<xliff:g id="PROVIDERINFODISPLAYNAME">%3$s</xliff:g>"</string>
+    <string name="passkey" msgid="632353688396759522">"ukhiye wokudlula"</string>
+    <string name="password" msgid="6738570945182936667">"iphasiwedi"</string>
+    <string name="sign_ins" msgid="4710739369149469208">"ukungena ngemvume"</string>
+    <!-- no translation found for create_passkey_in_title (2714306562710897785) -->
+    <skip />
+    <!-- no translation found for save_password_to_title (3450480045270186421) -->
+    <skip />
+    <!-- no translation found for save_sign_in_to_title (8328143607671760232) -->
+    <skip />
+    <!-- no translation found for create_passkey_in_other_device_title (6372952459932674632) -->
+    <skip />
+    <string name="use_provider_for_all_title" msgid="4201020195058980757">"Sebenzisa i-<xliff:g id="PROVIDERINFODISPLAYNAME">%1$s</xliff:g> kukho konke ukungena kwakho ngemvume?"</string>
+    <!-- no translation found for use_provider_for_all_description (6560593199974037820) -->
+    <skip />
+    <string name="set_as_default" msgid="4415328591568654603">"Setha njengokuzenzakalelayo"</string>
+    <string name="use_once" msgid="9027366575315399714">"Sebenzisa kanye"</string>
+    <string name="more_options_usage_passwords_passkeys" msgid="4794903978126339473">"Amaphasiwedi angu-<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>, okhiye bokudlula abangu-<xliff:g id="PASSKEYSNUMBER">%2$s</xliff:g>"</string>
+    <string name="more_options_usage_passwords" msgid="1632047277723187813">"Amaphasiwedi angu-<xliff:g id="PASSWORDSNUMBER">%1$s</xliff:g>"</string>
+    <string name="more_options_usage_passkeys" msgid="5390320437243042237">"Okhiye bokudlula abangu-<xliff:g id="PASSKEYSNUMBER">%1$s</xliff:g>"</string>
+    <!-- no translation found for passkey_before_subtitle (2448119456208647444) -->
+    <skip />
+    <string name="another_device" msgid="5147276802037801217">"Enye idivayisi"</string>
+    <string name="other_password_manager" msgid="565790221427004141">"Abanye abaphathi bephasiwedi"</string>
+    <string name="close_sheet" msgid="1393792015338908262">"Vala ishidi"</string>
+    <string name="accessibility_back_arrow_button" msgid="3233198183497842492">"Buyela emuva ekhasini langaphambilini"</string>
+    <string name="get_dialog_title_use_passkey_for" msgid="6236608872708021767">"Sebenzisa ukhiye wakho wokungena olondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_use_sign_in_for" msgid="5283099528915572980">"Sebenzisa ukungena kwakho ngemvume okulondoloziwe <xliff:g id="APP_NAME">%1$s</xliff:g>?"</string>
+    <string name="get_dialog_title_choose_sign_in_for" msgid="1361715440877613701">"Khetha ukungena ngemvume okulondoloziwe kwakho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_use_saved_passkey_for" msgid="4618100798664888512">"Ngena ngemvume ngenye indlela"</string>
+    <string name="get_dialog_button_label_no_thanks" msgid="8114363019023838533">"Cha ngiyabonga"</string>
+    <string name="get_dialog_button_label_continue" msgid="6446201694794283870">"Qhubeka"</string>
+    <string name="get_dialog_title_sign_in_options" msgid="2092876443114893618">"Okungakhethwa kukho kokungena ngemvume"</string>
+    <string name="get_dialog_heading_for_username" msgid="3456868514554204776">"Okuka-<xliff:g id="USERNAME">%1$s</xliff:g>"</string>
+    <string name="get_dialog_heading_locked_password_managers" msgid="8911514851762862180">"Abaphathi bephasiwedi abakhiyiwe"</string>
+    <string name="locked_credential_entry_label_subtext" msgid="9213450912991988691">"Thepha ukuze uvule"</string>
+    <string name="get_dialog_heading_manage_sign_ins" msgid="3522556476480676782">"Phatha ukungena ngemvume"</string>
+    <string name="get_dialog_heading_from_another_device" msgid="1166697017046724072">"Kusukela kwenye idivayisi"</string>
+    <string name="get_dialog_option_headline_use_a_different_device" msgid="8201578814988047549">"Sebenzisa idivayisi ehlukile"</string>
+</resources>
diff --git a/packages/CredentialManager/res/values/strings.xml b/packages/CredentialManager/res/values/strings.xml
index 1ee2a26..8c9023c 100644
--- a/packages/CredentialManager/res/values/strings.xml
+++ b/packages/CredentialManager/res/values/strings.xml
@@ -1,43 +1,77 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-  <string name="app_name">CredentialManager</string>
+  <!-- The name of this application. Credential Manager is a service that centralizes and provides
+  access to a user's credentials used to sign in to various apps. [CHAR LIMIT=80] -->
+  <string name="app_name">Credential Manager</string>
+
+  <!-- Strings for the create flow. -->
+  <!-- Button label to close the dialog when the user does not want to create the credential. [CHAR LIMIT=40] -->
   <string name="string_cancel">Cancel</string>
+  <!-- Button label to confirm choosing the default dialog information and continue. [CHAR LIMIT=40] -->
   <string name="string_continue">Continue</string>
-  <string name="string_more_options">More options</string>
+  <!-- This appears as a text button where users can click to create this passkey in other available places. [CHAR LIMIT=80] -->
   <string name="string_create_in_another_place">Create in another place</string>
+  <!-- This appears as a text button where users can click to create this password or other credential types in other available places. [CHAR LIMIT=80] -->
   <string name="string_save_to_another_place">Save to another place</string>
+  <!-- This appears as a text button where users can click to use another device to create this credential. [CHAR LIMIT=80] -->
   <string name="string_use_another_device">Use another device</string>
+  <!-- This appears as a text button where users can click to save this credential to another device. [CHAR LIMIT=80] -->
   <string name="string_save_to_another_device">Save to another device</string>
-  <string name="string_no_thanks">No thanks</string>
+  <!-- This appears as the title of the modal bottom sheet introducing what is passkey to users. [CHAR LIMIT=200] -->
   <string name="passkey_creation_intro_title">A simple way to sign in safely</string>
+  <!-- This appears as the description body of the modal bottom sheet introducing what is passkey to users. [CHAR LIMIT=200] -->
   <string name="passkey_creation_intro_body">Use your fingerprint, face or screen lock to sign in with a unique passkey that can’t be forgotten or stolen. Learn more</string>
-  <string name="choose_provider_title">Choose where to <xliff:g id="createTypes">%1$s</xliff:g></string>
-  <!-- TODO: Change the wording after design is completed. -->
-  <string name="choose_provider_body">This password manager will store your passwords, passkeys, and other sign-in info to help you easily sign in. You can change where to save your sign-in info at any time.</string>
-  <string name="choose_create_option_passkey_title">Create a passkey in <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
-  <string name="choose_create_option_password_title">Save your password to <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
-  <string name="choose_create_option_sign_in_title">Save your sign-in info to <xliff:g id="providerInfoDisplayName">%1$s</xliff:g>?</string>
-  <string name="choose_sign_in_title">Use saved sign in</string>
-  <string name="create_your_passkey">create your passkey</string>
+  <!-- This appears as the title of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
+  <string name="choose_provider_title">Choose where to <xliff:g id="createTypes" example="create your passkeys">%1$s</xliff:g></string>
+  <!-- Create types which are inserted as a placeholder for string choose_provider_title. [CHAR LIMIT=200] -->
+  <string name="create_your_passkeys">create your passkeys</string>
   <string name="save_your_password">save your password</string>
   <string name="save_your_sign_in_info">save your sign-in info</string>
-  <string name="create_passkey_in">Create passkey in</string>
-  <string name="save_password_to">Save password to</string>
-  <string name="save_sign_in_to">Save sign-in to</string>
-  <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName">%1$s</xliff:g> for all your sign-ins?</string>
-  <string name="set_as_default">Set as default</string>
-  <string name="use_once">Use once</string>
-  <string name="choose_create_option_description">You can use your <xliff:g id="appDomainName">%1$s</xliff:g> <xliff:g id="type">%2$s</xliff:g> on any device. It is saved to <xliff:g id="providerInfoDisplayName">%3$s</xliff:g> for <xliff:g id="createInfoDisplayName">%4$s</xliff:g></string>
-  <string name="more_options_usage_passwords_passkeys"><xliff:g id="passwordsNumber">%1$s</xliff:g> passwords, <xliff:g id="passkeysNumber">%2$s</xliff:g> passkeys</string>
-  <string name="more_options_usage_passwords"><xliff:g id="passwordsNumber">%1$s</xliff:g> passwords</string>
-  <string name="more_options_usage_passkeys"><xliff:g id="passkeysNumber">%1$s</xliff:g> passkeys</string>
+
+  <!-- This appears as the description body of the modal bottom sheet which provides all available providers for users to choose. [CHAR LIMIT=200] -->
+  <string name="choose_provider_body">Set a default password manager to save your passwords and passkeys and sign in faster next time.</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is passkey. [CHAR LIMIT=200] -->
+  <string name="choose_create_option_passkey_title">Create a passkey in <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is password. [CHAR LIMIT=200] -->
+  <string name="choose_create_option_password_title">Save your password to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose the create option inside a provider when the credential type is others. [CHAR LIMIT=200] -->
+  <string name="choose_create_option_sign_in_title">Save your sign-in info to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g>?</string>
+  <!-- This appears as the description body of the modal bottom sheet for users to choose the create option inside a provider. [CHAR LIMIT=200] -->
+  <string name="choose_create_option_description">You can use your <xliff:g id="appDomainName" example="Tribank">%1$s</xliff:g> <xliff:g id="type" example="passkey">%2$s</xliff:g> on any device. It is saved to <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%3$s</xliff:g> for <xliff:g id="createInfoDisplayName" example="elisa.beckett@gmail.com">%4$s</xliff:g></string>
+  <!-- Types which are inserted as a placeholder for string choose_create_option_description. [CHAR LIMIT=200] -->
   <string name="passkey">passkey</string>
   <string name="password">password</string>
   <string name="sign_ins">sign-ins</string>
-  <string name="another_device">Another device</string>
-  <string name="other_password_manager">Other password managers</string>
+
+  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created passkey can be created to. [CHAR LIMIT=200] -->
+  <string name="create_passkey_in_title">Create passkey in</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created password can be saved to. [CHAR LIMIT=200] -->
+  <string name="save_password_to_title">Save password to</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose other available places the created other credential types can be saved to. [CHAR LIMIT=200] -->
+  <string name="save_sign_in_to_title">Save sign-in to</string>
+  <!-- This appears as the title of the modal bottom sheet for users to choose to create a passkey on another device. [CHAR LIMIT=200] -->
+  <string name="create_passkey_in_other_device_title">Create a passkey in another device?</string>
+  <!-- This appears as the title of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
+  <string name="use_provider_for_all_title">Use <xliff:g id="providerInfoDisplayName" example="Google Password Manager">%1$s</xliff:g> for all your sign-ins?</string>
   <!-- TODO: Check the wording here. -->
-  <string name="confirm_default_or_use_once_description">This password manager will store your passwords and passkeys to help you easily sign in.</string>
+  <!-- This appears as the description body of the modal bottom sheet for users to confirm whether they should use the selected provider as default or not. [CHAR LIMIT=200] -->
+  <string name="use_provider_for_all_description">This password manager will store your passwords and passkeys to help you easily sign in.</string>
+  <!-- Button label to set the selected provider on the modal bottom sheet as default. [CHAR LIMIT=40] -->
+  <string name="set_as_default">Set as default</string>
+  <!-- Button label to set the selected provider on the modal bottom sheet not as default but just use once. [CHAR LIMIT=40] -->
+  <string name="use_once">Use once</string>
+  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are passwords and passkeys. [CHAR LIMIT=80] -->
+  <string name="more_options_usage_passwords_passkeys"><xliff:g id="passwordsNumber" example="1">%1$s</xliff:g> passwords, <xliff:g id="passkeysNumber" example="2">%2$s</xliff:g> passkeys</string>
+  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are only passwords. [CHAR LIMIT=80] -->
+  <string name="more_options_usage_passwords"><xliff:g id="passwordsNumber" example="3">%1$s</xliff:g> passwords</string>
+  <!-- Appears as an option row subtitle to show how many passwords and passkeys are saved in this option when there are only passkeys. [CHAR LIMIT=80] -->
+  <string name="more_options_usage_passkeys"><xliff:g id="passkeysNumber" example="4">%1$s</xliff:g> passkeys</string>
+  <!-- Appears before a request display name when the credential type is passkey . [CHAR LIMIT=80] -->
+  <string name="passkey_before_subtitle">Passkey</string>
+  <!-- Appears as an option row title that users can choose to use another device for this creation. [CHAR LIMIT=80] -->
+  <string name="another_device">Another device</string>
+  <!-- Appears as an option row title that users can choose to view other disabled providers. [CHAR LIMIT=80] -->
+  <string name="other_password_manager">Other password managers</string>
   <!-- Spoken content description of an element which will close the sheet when clicked. -->
   <string name="close_sheet">"Close sheet"</string>
   <!-- Spoken content description of the back arrow button. -->
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
index 2bede9a..1db1d1c 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt
@@ -39,16 +39,17 @@
 import android.os.Binder
 import android.os.Bundle
 import android.os.ResultReceiver
+import android.service.credentials.CredentialProviderService
 import com.android.credentialmanager.createflow.ActiveEntry
 import com.android.credentialmanager.createflow.CreateCredentialUiState
 import com.android.credentialmanager.createflow.CreateScreenState
 import com.android.credentialmanager.createflow.EnabledProviderInfo
+import com.android.credentialmanager.createflow.RemoteInfo
 import com.android.credentialmanager.createflow.RequestDisplayInfo
 import com.android.credentialmanager.getflow.GetCredentialUiState
 import com.android.credentialmanager.getflow.GetScreenState
-import com.android.credentialmanager.jetpack.developer.CreateCredentialRequest.Companion.createFrom
-import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest
 import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest.Companion.toBundle
+import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
 import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
 
 // Consider repo per screen, similar to view model?
@@ -58,7 +59,7 @@
 ) {
   val requestInfo: RequestInfo
   private val providerEnabledList: List<ProviderData>
-  private val providerDisabledList: List<DisabledProviderData>
+  private val providerDisabledList: List<DisabledProviderData>?
   // TODO: require non-null.
   val resultReceiver: ResultReceiver?
 
@@ -66,7 +67,7 @@
     requestInfo = intent.extras?.getParcelable(
       RequestInfo.EXTRA_REQUEST_INFO,
       RequestInfo::class.java
-    ) ?: testCreateRequestInfo()
+    ) ?: testCreatePasskeyRequestInfo()
 
     providerEnabledList = when (requestInfo.type) {
       RequestInfo.TYPE_CREATE ->
@@ -127,7 +128,7 @@
     // TODO: handle runtime cast error
       providerEnabledList as List<GetCredentialProviderData>, context)
     // TODO: covert from real requestInfo
-    val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo("tribank")
+    val requestDisplayInfo = com.android.credentialmanager.getflow.RequestDisplayInfo("the app")
     return GetCredentialUiState(
       providerEnabledList,
       GetScreenState.PRIMARY_SELECTION,
@@ -136,46 +137,29 @@
   }
 
   fun createCredentialInitialUiState(): CreateCredentialUiState {
+    val requestDisplayInfo = CreateFlowUtils.toRequestDisplayInfo(requestInfo, context)
     val providerEnabledList = CreateFlowUtils.toEnabledProviderList(
       // Handle runtime cast error
-      providerEnabledList as List<CreateCredentialProviderData>, context)
+      providerEnabledList as List<CreateCredentialProviderData>, requestDisplayInfo, context)
     val providerDisabledList = CreateFlowUtils.toDisabledProviderList(
       // Handle runtime cast error
-      providerDisabledList as List<DisabledProviderData>, context)
-    var hasDefault = false
-    var defaultProvider: EnabledProviderInfo = providerEnabledList.first()
+      providerDisabledList, context)
+    var defaultProvider: EnabledProviderInfo? = null
+    var remoteEntry: RemoteInfo? = null
     providerEnabledList.forEach{providerInfo -> providerInfo.createOptions =
       providerInfo.createOptions.sortedWith(compareBy { it.lastUsedTimeMillis }).reversed()
-      if (providerInfo.isDefault) {hasDefault = true; defaultProvider = providerInfo} }
-    // TODO: covert from real requestInfo for create passkey
-    var requestDisplayInfo = RequestDisplayInfo(
-      "beckett-bakert@gmail.com",
-      "Elisa Beckett",
-      TYPE_PUBLIC_KEY_CREDENTIAL,
-      "tribank")
-    val createCredentialRequest = requestInfo.createCredentialRequest
-    val createCredentialRequestJetpack = createCredentialRequest?.let { createFrom(it) }
-    if (createCredentialRequestJetpack is CreatePasswordRequest) {
-      requestDisplayInfo = RequestDisplayInfo(
-        createCredentialRequestJetpack.id,
-        createCredentialRequestJetpack.password,
-        TYPE_PASSWORD_CREDENTIAL,
-        "tribank")
+      if (providerInfo.isDefault) {defaultProvider = providerInfo}
+      if (providerInfo.remoteEntry != null) {
+        remoteEntry = providerInfo.remoteEntry!!
+      }
     }
     return CreateCredentialUiState(
       enabledProviders = providerEnabledList,
       disabledProviders = providerDisabledList,
-      // TODO: Add the screen when defaultProvider has no createOption but
-      //  there's remoteInfo under other providers
-      if (!hasDefault || defaultProvider.createOptions.isEmpty()) {
-        if (requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL)
-        {CreateScreenState.PASSKEY_INTRO} else {CreateScreenState.PROVIDER_SELECTION}
-      } else {CreateScreenState.CREATION_OPTION_SELECTION},
+      toCreateScreenState(requestDisplayInfo, defaultProvider, remoteEntry),
       requestDisplayInfo,
       false,
-      if (hasDefault) {
-        ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
-      } else null
+      toActiveEntry(defaultProvider, remoteEntry),
     )
   }
 
@@ -225,7 +209,7 @@
     )
   }
 
-  private fun testDisabledProviderList(): List<DisabledProviderData> {
+  private fun testDisabledProviderList(): List<DisabledProviderData>? {
     return listOf(
       DisabledProviderData("com.lastpass.lpandroid"),
       DisabledProviderData("com.google.android.youtube")
@@ -390,11 +374,12 @@
       intent, (PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
               or PendingIntent.FLAG_ONE_SHOT))
     val createPasswordRequest = android.service.credentials.CreateCredentialRequest(
-      context.applicationInfo.packageName,
-      "PASSWORD",
-      toBundle("beckett-bakert@gmail.com", "password123")
+            context.applicationInfo.packageName,
+            TYPE_PASSWORD_CREDENTIAL,
+            toBundle("beckett-bakert@gmail.com", "password123")
     )
-    val fillInIntent = Intent().putExtra("create_request_params", createPasswordRequest)
+    val fillInIntent = Intent().putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
+            createPasswordRequest)
 
     val slice = Slice.Builder(
       Entry.CREDENTIAL_MANAGER_ENTRY_URI, SliceSpec(Entry.VERSION, 1)
@@ -438,13 +423,81 @@
     )
   }
 
-  private fun testCreateRequestInfo(): RequestInfo {
-    val data = toBundle("beckett-bakert@gmail.com", "password123")
+  private fun testCreatePasskeyRequestInfo(): RequestInfo {
+    val request = CreatePublicKeyCredentialRequest("{\"extensions\": {\n" +
+            "                     \"webauthn.loc\": true\n" +
+            "                   },\n" +
+            "                   \"attestation\": \"direct\",\n" +
+            "                   \"challenge\": \"-rSQHXSQUdaK1N-La5bE-JPt6EVAW4SxX1K_tXhZ_Gk\",\n" +
+            "                   \"user\": {\n" +
+            "                     \"displayName\": \"testName\",\n" +
+            "                     \"name\": \"credManTesting@gmail.com\",\n" +
+            "                     \"id\": \"eD4o2KoXLpgegAtnM5cDhhUPvvk2\"\n" +
+            "                   },\n" +
+            "                   \"excludeCredentials\": [],\n" +
+            "                   \"rp\": {\n" +
+            "                     \"name\": \"Address Book\",\n" +
+            "                     \"id\": \"addressbook-c7876.uc.r.appspot.com\"\n" +
+            "                   },\n" +
+            "                   \"timeout\": 60000,\n" +
+            "                   \"pubKeyCredParams\": [\n" +
+            "                     {\n" +
+            "                       \"type\": \"public-key\",\n" +
+            "                       \"alg\": -7\n" +
+            "                     },\n" +
+            "                     {\n" +
+            "                       \"type\": \"public-key\",\n" +
+            "                       \"alg\": -257\n" +
+            "                     },\n" +
+            "                     {\n" +
+            "                       \"type\": \"public-key\",\n" +
+            "                       \"alg\": -37\n" +
+            "                     }\n" +
+            "                   ],\n" +
+            "                   \"authenticatorSelection\": {\n" +
+            "                     \"residentKey\": \"required\",\n" +
+            "                     \"requireResidentKey\": true\n" +
+            "                   }}")
+    val credentialData = request.data
     return RequestInfo.newCreateRequestInfo(
       Binder(),
       CreateCredentialRequest(
         TYPE_PUBLIC_KEY_CREDENTIAL,
-        data
+        credentialData,
+        // TODO: populate with actual data
+        /*candidateQueryData=*/ Bundle(),
+        /*requireSystemProvider=*/ false
+      ),
+      /*isFirstUsage=*/false,
+      "tribank"
+    )
+  }
+
+  private fun testCreatePasswordRequestInfo(): RequestInfo {
+    val data = toBundle("beckett-bakert@gmail.com", "password123")
+    return RequestInfo.newCreateRequestInfo(
+      Binder(),
+      CreateCredentialRequest(
+        TYPE_PASSWORD_CREDENTIAL,
+        data,
+        // TODO: populate with actual data
+        /*candidateQueryData=*/ Bundle(),
+        /*requireSystemProvider=*/ false
+      ),
+      /*isFirstUsage=*/false,
+      "tribank"
+    )
+  }
+
+  private fun testCreateOtherCredentialRequestInfo(): RequestInfo {
+    val data = Bundle()
+    return RequestInfo.newCreateRequestInfo(
+      Binder(),
+      CreateCredentialRequest(
+        "other-sign-ins",
+        data,
+        /*candidateQueryData=*/ Bundle(),
+        /*requireSystemProvider=*/ false
       ),
       /*isFirstUsage=*/false,
       "tribank"
@@ -456,11 +509,46 @@
       Binder(),
       GetCredentialRequest.Builder()
         .addGetCredentialOption(
-          GetCredentialOption(TYPE_PUBLIC_KEY_CREDENTIAL, Bundle())
+          GetCredentialOption(
+            TYPE_PUBLIC_KEY_CREDENTIAL, Bundle(), /*requireSystemProvider=*/ false)
         )
         .build(),
       /*isFirstUsage=*/false,
       "tribank.us"
     )
   }
+
+  private fun toCreateScreenState(
+    requestDisplayInfo: RequestDisplayInfo,
+    defaultProvider: EnabledProviderInfo?,
+    remoteEntry: RemoteInfo?,
+  ): CreateScreenState {
+    return if (
+      defaultProvider != null && defaultProvider.createOptions.isEmpty() && remoteEntry != null
+    ){
+      CreateScreenState.EXTERNAL_ONLY_SELECTION
+    } else if (defaultProvider == null || defaultProvider.createOptions.isEmpty()) {
+      if (requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL) {
+        CreateScreenState.PASSKEY_INTRO
+      } else {
+        CreateScreenState.PROVIDER_SELECTION
+      }
+    } else {
+      CreateScreenState.CREATION_OPTION_SELECTION
+    }
+  }
+
+  private fun toActiveEntry(
+    defaultProvider: EnabledProviderInfo?,
+    remoteEntry: RemoteInfo?,
+  ): ActiveEntry? {
+    return if (
+      defaultProvider != null && defaultProvider.createOptions.isNotEmpty()
+    ) {
+      ActiveEntry(defaultProvider, defaultProvider.createOptions.first())
+    } else if (
+      defaultProvider != null && defaultProvider.createOptions.isEmpty() && remoteEntry != null) {
+      ActiveEntry(defaultProvider, remoteEntry)
+    } else null
+  }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
index d324f87..6a4c599 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt
@@ -69,6 +69,7 @@
         )
         providerActivityResult.value?.let {
           viewModel.onProviderActivityResult(it)
+          providerActivityResult.value = null
         }
         CreateCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
       }
@@ -80,6 +81,7 @@
         )
         providerActivityResult.value?.let {
           viewModel.onProviderActivityResult(it)
+          providerActivityResult.value = null
         }
         GetCredentialScreen(viewModel = viewModel, providerActivityLauncher = launcher)
       }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
index 2eb3284..357c55d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/DataConverter.kt
@@ -23,17 +23,23 @@
 import android.credentials.ui.GetCredentialProviderData
 import android.credentials.ui.CreateCredentialProviderData
 import android.credentials.ui.DisabledProviderData
+import android.credentials.ui.RequestInfo
 import android.graphics.drawable.Drawable
 import com.android.credentialmanager.createflow.CreateOptionInfo
 import com.android.credentialmanager.createflow.RemoteInfo
+import com.android.credentialmanager.createflow.RequestDisplayInfo
 import com.android.credentialmanager.getflow.ActionEntryInfo
 import com.android.credentialmanager.getflow.AuthenticationEntryInfo
 import com.android.credentialmanager.getflow.CredentialEntryInfo
 import com.android.credentialmanager.getflow.ProviderInfo
 import com.android.credentialmanager.getflow.RemoteEntryInfo
+import com.android.credentialmanager.jetpack.developer.CreateCredentialRequest
+import com.android.credentialmanager.jetpack.developer.CreatePasswordRequest
+import com.android.credentialmanager.jetpack.developer.CreatePublicKeyCredentialRequest
 import com.android.credentialmanager.jetpack.provider.ActionUi
 import com.android.credentialmanager.jetpack.provider.CredentialEntryUi
 import com.android.credentialmanager.jetpack.provider.SaveEntryUi
+import org.json.JSONObject
 
 /** Utility functions for converting CredentialManager data structures to or from UI formats. */
 class GetFlowUtils {
@@ -172,6 +178,7 @@
 
     fun toEnabledProviderList(
       providerDataList: List<CreateCredentialProviderData>,
+      requestDisplayInfo: RequestDisplayInfo,
       context: Context,
     ): List<com.android.credentialmanager.createflow.EnabledProviderInfo> {
       // TODO: get from the actual service info
@@ -194,7 +201,7 @@
           name = it.providerFlattenedComponentName,
           displayName = pkgInfo.applicationInfo.loadLabel(packageManager).toString(),
           createOptions = toCreationOptionInfoList(
-            it.providerFlattenedComponentName, it.saveEntries, context),
+            it.providerFlattenedComponentName, it.saveEntries, requestDisplayInfo, context),
           isDefault = it.isDefaultProvider,
           remoteEntry = toRemoteInfo(it.providerFlattenedComponentName, it.remoteEntry),
         )
@@ -202,12 +209,12 @@
     }
 
     fun toDisabledProviderList(
-      providerDataList: List<DisabledProviderData>,
+      providerDataList: List<DisabledProviderData>?,
       context: Context,
-    ): List<com.android.credentialmanager.createflow.DisabledProviderInfo> {
+    ): List<com.android.credentialmanager.createflow.DisabledProviderInfo>? {
       // TODO: get from the actual service info
       val packageManager = context.packageManager
-      return providerDataList.map {
+      return providerDataList?.map {
         val pkgInfo = packageManager
           .getPackageInfo(it.providerFlattenedComponentName,
             PackageManager.PackageInfoFlags.of(0))
@@ -219,9 +226,59 @@
       }
     }
 
+    fun toRequestDisplayInfo(
+      requestInfo: RequestInfo,
+      context: Context,
+    ): RequestDisplayInfo {
+      val createCredentialRequest = requestInfo.createCredentialRequest
+      val createCredentialRequestJetpack = createCredentialRequest?.let {
+        CreateCredentialRequest.createFrom(
+          it
+        )
+      }
+      when (createCredentialRequestJetpack) {
+        is CreatePasswordRequest -> {
+          return RequestDisplayInfo(
+            createCredentialRequestJetpack.id,
+            createCredentialRequestJetpack.password,
+            createCredentialRequestJetpack.type,
+            requestInfo.appPackageName,
+            context.getDrawable(R.drawable.ic_password)!!
+          )
+        }
+        is CreatePublicKeyCredentialRequest -> {
+          val requestJson = createCredentialRequestJetpack.requestJson
+          val json = JSONObject(requestJson)
+          var name = ""
+          var displayName = ""
+          if (json.has("user")) {
+            val user: JSONObject = json.getJSONObject("user")
+            name = user.getString("name")
+            displayName = user.getString("displayName")
+          }
+          return RequestDisplayInfo(
+            name,
+            displayName,
+            createCredentialRequestJetpack.type,
+            requestInfo.appPackageName,
+            context.getDrawable(R.drawable.ic_passkey)!!)
+        }
+        // TODO: correctly parsing for other sign-ins
+        else -> {
+          return RequestDisplayInfo(
+            "beckett-bakert@gmail.com",
+            "Elisa Beckett",
+            "other-sign-ins",
+            requestInfo.appPackageName,
+            context.getDrawable(R.drawable.ic_other_sign_in)!!)
+        }
+      }
+    }
+
     private fun toCreationOptionInfoList(
       providerId: String,
       creationEntries: List<Entry>,
+      requestDisplayInfo: RequestDisplayInfo,
       context: Context,
     ): List<CreateOptionInfo> {
       return creationEntries.map {
@@ -236,7 +293,7 @@
           fillInIntent = it.frameworkExtrasIntent,
           userProviderDisplayName = saveEntryUi.userProviderAccountName as String,
           profileIcon = saveEntryUi.profileIcon?.loadDrawable(context)
-            ?: context.getDrawable(R.drawable.ic_profile)!!,
+            ?: requestDisplayInfo.typeIcon,
           passwordCount = saveEntryUi.passwordCount ?: 0,
           passkeyCount = saveEntryUi.passkeyCount ?: 0,
           totalCredentialCount = saveEntryUi.totalCredentialCount ?: 0,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
index 61e11fe..f1f453d 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/material/ModalBottomSheet.kt
@@ -62,7 +62,6 @@
 import com.android.credentialmanager.common.material.ModalBottomSheetValue.Expanded
 import com.android.credentialmanager.common.material.ModalBottomSheetValue.HalfExpanded
 import com.android.credentialmanager.common.material.ModalBottomSheetValue.Hidden
-import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.launch
 import kotlin.math.max
@@ -319,7 +318,7 @@
         rememberModalBottomSheetState(Hidden),
     sheetShape: Shape = MaterialTheme.shapes.large,
     sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
-    sheetBackgroundColor: Color = ModalBottomSheetDefaults.scrimColor,
+    sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
     sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
     scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
     content: @Composable () -> Unit
@@ -477,5 +476,5 @@
      */
     val scrimColor: Color
         @Composable
-        get() = LocalAndroidColorScheme.current.colorSurfaceHighlight
+        get() = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.32f)
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/CancelButton.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/CancelButton.kt
index 177d0e0..80764b5 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/CancelButton.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/CancelButton.kt
@@ -16,13 +16,20 @@
 
 package com.android.credentialmanager.common.ui
 
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.material3.TextButton
 import androidx.compose.runtime.Composable
 
 @Composable
 fun CancelButton(text: String, onClick: () -> Unit) {
-    TextButton(onClick = onClick) {
+    TextButton(
+        onClick = onClick,
+        colors = ButtonDefaults.textButtonColors(
+            contentColor = MaterialTheme.colorScheme.primary,
+        )
+    ) {
         Text(text = text)
     }
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
new file mode 100644
index 0000000..aaabce3
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Cards.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentialmanager.common.ui
+
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.layout.ColumnScope
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
+
+/**
+ * By default the card is filled with surfaceVariant color. This container card instead fills the
+ * background color with surface corlor.
+ */
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ContainerCard(
+    modifier: Modifier = Modifier,
+    shape: Shape = CardDefaults.shape,
+    border: BorderStroke? = null,
+    content: @Composable ColumnScope.() -> Unit,
+) {
+    Card(
+        modifier = modifier,
+        shape = shape,
+        border = border,
+        colors = CardDefaults.cardColors(
+            containerColor = MaterialTheme.colorScheme.surface,
+        ),
+        content = content,
+    )
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ConfirmButton.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ConfirmButton.kt
index b2b0bdc..d8ee750 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ConfirmButton.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ConfirmButton.kt
@@ -16,13 +16,21 @@
 
 package com.android.credentialmanager.common.ui
 
+import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.FilledTonalButton
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.Text
 import androidx.compose.runtime.Composable
 
 @Composable
 fun ConfirmButton(text: String, onClick: () -> Unit) {
-    FilledTonalButton(onClick = onClick) {
+    FilledTonalButton(
+        onClick = onClick,
+        colors = ButtonDefaults.filledTonalButtonColors(
+            containerColor = MaterialTheme.colorScheme.primaryContainer,
+            contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
+        )
+    ) {
         Text(text = text)
     }
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
index 51a1cbb..aefd534 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Entry.kt
@@ -18,13 +18,13 @@
 
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.SuggestionChip
 import androidx.compose.material3.SuggestionChipDefaults
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
 import com.android.credentialmanager.ui.theme.EntryShape
-import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
@@ -42,7 +42,9 @@
         icon = icon,
         border = null,
         colors = SuggestionChipDefaults.suggestionChipColors(
-            containerColor = LocalAndroidColorScheme.current.colorSurface,
+            containerColor = MaterialTheme.colorScheme.surfaceVariant,
+            labelColor = MaterialTheme.colorScheme.onSurfaceVariant,
+            iconContentColor = MaterialTheme.colorScheme.onSurfaceVariant,
         ),
     )
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
new file mode 100644
index 0000000..3a66dda
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/Texts.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.credentialmanager.common.ui
+
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.style.TextAlign
+
+@Composable
+fun TextOnSurface(
+    text: String,
+    modifier: Modifier = Modifier,
+    textAlign: TextAlign? = null,
+    style: TextStyle,
+) {
+    TextInternal(
+        text = text,
+        color = MaterialTheme.colorScheme.onSurface,
+        modifier = modifier,
+        textAlign = textAlign,
+        style = style,
+    )
+}
+
+@Composable
+fun TextSecondary(
+    text: String,
+    modifier: Modifier = Modifier,
+    textAlign: TextAlign? = null,
+    style: TextStyle,
+) {
+    TextInternal(
+        text = text,
+        color = MaterialTheme.colorScheme.secondary,
+        modifier = modifier,
+        textAlign = textAlign,
+        style = style,
+    )
+}
+
+@Composable
+fun TextOnSurfaceVariant(
+    text: String,
+    modifier: Modifier = Modifier,
+    textAlign: TextAlign? = null,
+    style: TextStyle,
+) {
+    TextInternal(
+        text = text,
+        color = MaterialTheme.colorScheme.onSurfaceVariant,
+        modifier = modifier,
+        textAlign = textAlign,
+        style = style,
+    )
+}
+
+@Composable
+private fun TextInternal(
+    text: String,
+    color: Color,
+    modifier: Modifier,
+    textAlign: TextAlign?,
+    style: TextStyle,
+) {
+    Text(text = text, color = color, modifier = modifier, textAlign = textAlign, style = style)
+}
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
index 9f73aef..57e20be 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialComponents.kt
@@ -14,7 +14,7 @@
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.lazy.LazyColumn
-import androidx.compose.material3.Card
+import androidx.compose.material3.ButtonDefaults
 import androidx.compose.material3.Divider
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
@@ -46,6 +46,10 @@
 import com.android.credentialmanager.common.ui.CancelButton
 import com.android.credentialmanager.common.ui.ConfirmButton
 import com.android.credentialmanager.common.ui.Entry
+import com.android.credentialmanager.common.ui.TextOnSurface
+import com.android.credentialmanager.common.ui.TextSecondary
+import com.android.credentialmanager.common.ui.TextOnSurfaceVariant
+import com.android.credentialmanager.common.ui.ContainerCard
 import com.android.credentialmanager.ui.theme.EntryShape
 import com.android.credentialmanager.ui.theme.LocalAndroidColorScheme
 import com.android.credentialmanager.jetpack.developer.PublicKeyCredential.Companion.TYPE_PUBLIC_KEY_CREDENTIAL
@@ -53,619 +57,766 @@
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun CreateCredentialScreen(
-  viewModel: CreateCredentialViewModel,
-  providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+    viewModel: CreateCredentialViewModel,
+    providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
 ) {
-  val selectEntryCallback: (EntryInfo) -> Unit = {
-    viewModel.onEntrySelected(it, providerActivityLauncher)
-  }
-  val confirmEntryCallback: () -> Unit = {
-    viewModel.onConfirmCreationSelected(providerActivityLauncher)
-  }
-  val state = rememberModalBottomSheetState(
-    initialValue = ModalBottomSheetValue.Expanded,
-    skipHalfExpanded = true
-  )
-  ModalBottomSheetLayout(
-    sheetState = state,
-    sheetContent = {
-      val uiState = viewModel.uiState
-      when (uiState.currentScreenState) {
-        CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
-          onConfirm = viewModel::onConfirmIntro,
-          onCancel = viewModel::onCancel,
-        )
-        CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
-          requestDisplayInfo = uiState.requestDisplayInfo,
-          enabledProviderList = uiState.enabledProviders,
-          disabledProviderList = uiState.disabledProviders,
-          onCancel = viewModel::onCancel,
-          onOptionSelected = viewModel::onEntrySelectedFromFirstUseScreen,
-          onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected,
-          onRemoteEntrySelected = selectEntryCallback,
-        )
-        CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
-          requestDisplayInfo = uiState.requestDisplayInfo,
-          enabledProviderList = uiState.enabledProviders,
-          providerInfo = uiState.activeEntry?.activeProvider!!,
-          createOptionInfo = uiState.activeEntry.activeEntryInfo as CreateOptionInfo,
-          showActiveEntryOnly = uiState.showActiveEntryOnly,
-          onOptionSelected = selectEntryCallback,
-          onConfirm = confirmEntryCallback,
-          onCancel = viewModel::onCancel,
-          onMoreOptionsSelected = viewModel::onMoreOptionsSelected,
-        )
-        CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
-          requestDisplayInfo = uiState.requestDisplayInfo,
-          enabledProviderList = uiState.enabledProviders,
-          disabledProviderList = uiState.disabledProviders,
-          onBackButtonSelected = viewModel::onBackButtonSelected,
-          onOptionSelected = viewModel::onEntrySelectedFromMoreOptionScreen,
-          onDisabledPasswordManagerSelected = viewModel::onDisabledPasswordManagerSelected,
-          onRemoteEntrySelected = selectEntryCallback,
-        )
-        CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
-          providerInfo = uiState.activeEntry?.activeProvider!!,
-          onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected
-        )
-      }
-    },
-    scrimColor = MaterialTheme.colorScheme.scrim,
-    sheetShape = EntryShape.TopRoundedCorner,
-  ) {}
-  LaunchedEffect(state.currentValue) {
-    if (state.currentValue == ModalBottomSheetValue.Hidden) {
-      viewModel.onCancel()
+    val state = rememberModalBottomSheetState(
+        initialValue = ModalBottomSheetValue.Expanded,
+        skipHalfExpanded = true
+    )
+    ModalBottomSheetLayout(
+        sheetBackgroundColor = MaterialTheme.colorScheme.surface,
+        sheetState = state,
+        sheetContent = {
+            val uiState = viewModel.uiState
+            if (!uiState.hidden) {
+                when (uiState.currentScreenState) {
+                    CreateScreenState.PASSKEY_INTRO -> ConfirmationCard(
+                        onConfirm = viewModel::onConfirmIntro,
+                        onCancel = viewModel::onCancel,
+                    )
+                    CreateScreenState.PROVIDER_SELECTION -> ProviderSelectionCard(
+                        requestDisplayInfo = uiState.requestDisplayInfo,
+                        enabledProviderList = uiState.enabledProviders,
+                        disabledProviderList = uiState.disabledProviders,
+                        onCancel = viewModel::onCancel,
+                        onOptionSelected = viewModel::onEntrySelectedFromFirstUseScreen,
+                        onDisabledPasswordManagerSelected =
+                        viewModel::onDisabledPasswordManagerSelected,
+                        onRemoteEntrySelected = viewModel::onEntrySelected,
+                    )
+                    CreateScreenState.CREATION_OPTION_SELECTION -> CreationSelectionCard(
+                        requestDisplayInfo = uiState.requestDisplayInfo,
+                        enabledProviderList = uiState.enabledProviders,
+                        providerInfo = uiState.activeEntry?.activeProvider!!,
+                        createOptionInfo = uiState.activeEntry.activeEntryInfo as CreateOptionInfo,
+                        showActiveEntryOnly = uiState.showActiveEntryOnly,
+                        onOptionSelected = viewModel::onEntrySelected,
+                        onConfirm = viewModel::onConfirmEntrySelected,
+                        onCancel = viewModel::onCancel,
+                        onMoreOptionsSelected = viewModel::onMoreOptionsSelected,
+                    )
+                    CreateScreenState.MORE_OPTIONS_SELECTION -> MoreOptionsSelectionCard(
+                        requestDisplayInfo = uiState.requestDisplayInfo,
+                        enabledProviderList = uiState.enabledProviders,
+                        disabledProviderList = uiState.disabledProviders,
+                        onBackButtonSelected = viewModel::onBackButtonSelected,
+                        onOptionSelected = viewModel::onEntrySelectedFromMoreOptionScreen,
+                        onDisabledPasswordManagerSelected =
+                        viewModel::onDisabledPasswordManagerSelected,
+                        onRemoteEntrySelected = viewModel::onEntrySelected,
+                    )
+                    CreateScreenState.MORE_OPTIONS_ROW_INTRO -> MoreOptionsRowIntroCard(
+                        providerInfo = uiState.activeEntry?.activeProvider!!,
+                        onDefaultOrNotSelected = viewModel::onDefaultOrNotSelected
+                    )
+                    CreateScreenState.EXTERNAL_ONLY_SELECTION -> ExternalOnlySelectionCard(
+                        requestDisplayInfo = uiState.requestDisplayInfo,
+                        activeRemoteEntry = uiState.activeEntry?.activeEntryInfo!!,
+                        onOptionSelected = viewModel::onEntrySelected,
+                        onConfirm = viewModel::onConfirmEntrySelected,
+                        onCancel = viewModel::onCancel,
+                    )
+                }
+            } else if (uiState.hidden && uiState.selectedEntry != null) {
+                viewModel.launchProviderUi(providerActivityLauncher)
+            }
+        },
+        scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
+        sheetShape = EntryShape.TopRoundedCorner,
+    ) {}
+    LaunchedEffect(state.currentValue) {
+        if (state.currentValue == ModalBottomSheetValue.Hidden) {
+            viewModel.onCancel()
+        }
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun ConfirmationCard(
-  onConfirm: () -> Unit,
-  onCancel: () -> Unit,
+    onConfirm: () -> Unit,
+    onCancel: () -> Unit,
 ) {
-  Card() {
-    Column() {
-      Icon(
-        painter = painterResource(R.drawable.ic_passkey),
-        contentDescription = null,
-        tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
-        modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
-          .padding(top = 24.dp, bottom = 12.dp)
-      )
-      Text(
-        text = stringResource(R.string.passkey_creation_intro_title),
-        style = MaterialTheme.typography.titleMedium,
-        modifier = Modifier
-          .padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-        textAlign = TextAlign.Center
-      )
-      Divider(
-        thickness = 16.dp,
-        color = Color.Transparent
-      )
-      Text(
-        text = stringResource(R.string.passkey_creation_intro_body),
-        style = MaterialTheme.typography.bodyLarge,
-        modifier = Modifier.padding(horizontal = 28.dp)
-      )
-      Divider(
-        thickness = 32.dp,
-        color = Color.Transparent
-      )
-      Row(
-        horizontalArrangement = Arrangement.SpaceBetween,
-        modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
-      ) {
-        CancelButton(
-          stringResource(R.string.string_cancel),
-          onClick = onCancel
-        )
-        ConfirmButton(
-          stringResource(R.string.string_continue),
-          onClick = onConfirm
-        )
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 18.dp)
-      )
+    ContainerCard() {
+        Column() {
+            Icon(
+                painter = painterResource(R.drawable.ic_passkey),
+                contentDescription = null,
+                tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+                modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
+                    .padding(top = 24.dp, bottom = 12.dp)
+            )
+            TextOnSurface(
+                text = stringResource(R.string.passkey_creation_intro_title),
+                style = MaterialTheme.typography.titleMedium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+                textAlign = TextAlign.Center,
+            )
+            Divider(
+                thickness = 16.dp,
+                color = Color.Transparent
+            )
+            TextSecondary(
+                text = stringResource(R.string.passkey_creation_intro_body),
+                style = MaterialTheme.typography.bodyLarge,
+                modifier = Modifier.padding(horizontal = 28.dp),
+            )
+            Divider(
+                thickness = 32.dp,
+                color = Color.Transparent
+            )
+            Row(
+                horizontalArrangement = Arrangement.SpaceBetween,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(
+                    stringResource(R.string.string_cancel),
+                    onClick = onCancel
+                )
+                ConfirmButton(
+                    stringResource(R.string.string_continue),
+                    onClick = onConfirm
+                )
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 18.dp)
+            )
+        }
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun ProviderSelectionCard(
-  requestDisplayInfo: RequestDisplayInfo,
-  enabledProviderList: List<EnabledProviderInfo>,
-  disabledProviderList: List<DisabledProviderInfo>?,
-  onOptionSelected: (ActiveEntry) -> Unit,
-  onDisabledPasswordManagerSelected: () -> Unit,
-  onCancel: () -> Unit,
-  onRemoteEntrySelected: (EntryInfo) -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    enabledProviderList: List<EnabledProviderInfo>,
+    disabledProviderList: List<DisabledProviderInfo>?,
+    onOptionSelected: (ActiveEntry) -> Unit,
+    onDisabledPasswordManagerSelected: () -> Unit,
+    onCancel: () -> Unit,
+    onRemoteEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Card() {
-    Column() {
-      // TODO: Change the icon for create passwords and sign-ins
-      Icon(
-        painter = painterResource(R.drawable.ic_passkey),
-        contentDescription = null,
-        tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
-        modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
-          .padding(top = 24.dp, bottom = 16.dp)
-      )
-      Text(
-        text = stringResource(
-          R.string.choose_provider_title,
-          when (requestDisplayInfo.type) {
-            TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.create_your_passkey)
-            TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.save_your_password)
-            else -> stringResource(R.string.save_your_sign_in_info)
-          },
-        ),
-        style = MaterialTheme.typography.titleMedium,
-        modifier = Modifier.padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-        textAlign = TextAlign.Center
-      )
-      Divider(
-        thickness = 16.dp,
-        color = Color.Transparent
-      )
-      Text(
-        text = stringResource(R.string.choose_provider_body),
-        style = MaterialTheme.typography.bodyLarge,
-        modifier = Modifier.padding(horizontal = 28.dp)
-      )
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent
-      )
-      Card(
-        shape = MaterialTheme.shapes.medium,
-        modifier = Modifier
-          .padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-      ) {
-        LazyColumn(
-          verticalArrangement = Arrangement.spacedBy(2.dp)
-        ) {
-          enabledProviderList.forEach { enabledProviderInfo ->
-            enabledProviderInfo.createOptions.forEach { createOptionInfo ->
-              item {
-                MoreOptionsInfoRow(
-                  providerInfo = enabledProviderInfo,
-                  createOptionInfo = createOptionInfo,
-                  onOptionSelected = {
-                    onOptionSelected(ActiveEntry(enabledProviderInfo, createOptionInfo))
-                  })
-              }
-            }
-          }
-          if (disabledProviderList != null) {
-            item {
-              MoreOptionsDisabledProvidersRow(
-                disabledProviders = disabledProviderList,
-                onDisabledPasswordManagerSelected = onDisabledPasswordManagerSelected,
-              )
-            }
-          }
-        }
-      }
-      // TODO: handle the error situation that if multiple remoteInfos exists
-      enabledProviderList.forEach { enabledProvider ->
-        if (enabledProvider.remoteEntry != null) {
-          TextButton(
-            onClick = {
-              onRemoteEntrySelected(enabledProvider.remoteEntry!!) },
-            modifier = Modifier
-              .padding(horizontal = 24.dp)
-              .align(alignment = Alignment.CenterHorizontally)
-          ) {
-            Text(
-              text = stringResource(R.string.string_save_to_another_device),
-              textAlign = TextAlign.Center,
+    ContainerCard() {
+        Column() {
+            Icon(
+                bitmap = requestDisplayInfo.typeIcon.toBitmap().asImageBitmap(),
+                contentDescription = null,
+                tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+                modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
+                    .padding(top = 24.dp, bottom = 16.dp).size(32.dp)
             )
-          }
+            TextOnSurface(
+                text = stringResource(
+                    R.string.choose_provider_title,
+                    when (requestDisplayInfo.type) {
+                        TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.create_your_passkeys)
+                        TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.save_your_password)
+                        else -> stringResource(R.string.save_your_sign_in_info)
+                    },
+                ),
+                style = MaterialTheme.typography.titleMedium,
+                modifier = Modifier.padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+                textAlign = TextAlign.Center,
+            )
+            Divider(
+                thickness = 16.dp,
+                color = Color.Transparent
+            )
+            TextSecondary(
+                text = stringResource(R.string.choose_provider_body),
+                style = MaterialTheme.typography.bodyLarge,
+                modifier = Modifier.padding(horizontal = 28.dp),
+            )
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent
+            )
+            ContainerCard(
+                shape = MaterialTheme.shapes.medium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+            ) {
+                LazyColumn(
+                    verticalArrangement = Arrangement.spacedBy(2.dp)
+                ) {
+                    enabledProviderList.forEach { enabledProviderInfo ->
+                        enabledProviderInfo.createOptions.forEach { createOptionInfo ->
+                            item {
+                                MoreOptionsInfoRow(
+                                    providerInfo = enabledProviderInfo,
+                                    createOptionInfo = createOptionInfo,
+                                    onOptionSelected = {
+                                        onOptionSelected(
+                                            ActiveEntry(
+                                                enabledProviderInfo,
+                                                createOptionInfo
+                                            )
+                                        )
+                                    })
+                            }
+                        }
+                    }
+                    if (disabledProviderList != null) {
+                        item {
+                            MoreOptionsDisabledProvidersRow(
+                                disabledProviders = disabledProviderList,
+                                onDisabledPasswordManagerSelected =
+                                onDisabledPasswordManagerSelected,
+                            )
+                        }
+                    }
+                }
+            }
+            // TODO: handle the error situation that if multiple remoteInfos exists
+            enabledProviderList.forEach { enabledProvider ->
+                if (enabledProvider.remoteEntry != null) {
+                    TextButton(
+                        onClick = {
+                            onRemoteEntrySelected(enabledProvider.remoteEntry!!)
+                        },
+                        modifier = Modifier
+                            .padding(horizontal = 24.dp)
+                            .align(alignment = Alignment.CenterHorizontally),
+                        colors = ButtonDefaults.textButtonColors(
+                            contentColor = MaterialTheme.colorScheme.primary,
+                        )
+                    ) {
+                        Text(
+                            text = stringResource(R.string.string_save_to_another_device),
+                            textAlign = TextAlign.Center,
+                        )
+                    }
+                }
+            }
+            Divider(
+                thickness = 24.dp,
+                color = Color.Transparent
+            )
+            Row(
+                horizontalArrangement = Arrangement.Start,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(stringResource(R.string.string_cancel), onCancel)
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 16.dp)
+            )
         }
-      }
-      Row(
-        horizontalArrangement = Arrangement.Start,
-        modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
-      ) {
-        CancelButton(stringResource(R.string.string_cancel), onCancel)
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 16.dp)
-      )
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionsSelectionCard(
-  requestDisplayInfo: RequestDisplayInfo,
-  enabledProviderList: List<EnabledProviderInfo>,
-  disabledProviderList: List<DisabledProviderInfo>?,
-  onBackButtonSelected: () -> Unit,
-  onOptionSelected: (ActiveEntry) -> Unit,
-  onDisabledPasswordManagerSelected: () -> Unit,
-  onRemoteEntrySelected: (EntryInfo) -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    enabledProviderList: List<EnabledProviderInfo>,
+    disabledProviderList: List<DisabledProviderInfo>?,
+    onBackButtonSelected: () -> Unit,
+    onOptionSelected: (ActiveEntry) -> Unit,
+    onDisabledPasswordManagerSelected: () -> Unit,
+    onRemoteEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Card() {
-    Column() {
-      TopAppBar(
-        title = {
-          Text(
-            text = when (requestDisplayInfo.type) {
-              TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.create_passkey_in)
-              TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.save_password_to)
-              else -> stringResource(R.string.save_sign_in_to)
-            },
-            style = MaterialTheme.typography.titleMedium
-          )
-        },
-        navigationIcon = {
-          IconButton(onClick = onBackButtonSelected) {
-            Icon(
-              Icons.Filled.ArrowBack,
-              stringResource(R.string.accessibility_back_arrow_button))
-          }
-        },
-        colors = TopAppBarDefaults.smallTopAppBarColors
-          (containerColor = Color.Transparent),
-      )
-      Divider(
-         thickness = 8.dp,
-         color = Color.Transparent
-      )
-      Card(
-        shape = MaterialTheme.shapes.medium,
-        modifier = Modifier
-          .padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally)
-      ) {
-        LazyColumn(
-          verticalArrangement = Arrangement.spacedBy(2.dp)
-        ) {
-          enabledProviderList.forEach { enabledProviderInfo ->
-            enabledProviderInfo.createOptions.forEach { createOptionInfo ->
-              item {
-                MoreOptionsInfoRow(
-                  providerInfo = enabledProviderInfo,
-                  createOptionInfo = createOptionInfo,
-                  onOptionSelected = {
-                    onOptionSelected(ActiveEntry(enabledProviderInfo, createOptionInfo))
-                  })
-              }
+    ContainerCard() {
+        Column() {
+            TopAppBar(
+                title = {
+                    TextOnSurface(
+                        text = when (requestDisplayInfo.type) {
+                            TYPE_PUBLIC_KEY_CREDENTIAL ->
+                                stringResource(R.string.create_passkey_in_title)
+                            TYPE_PASSWORD_CREDENTIAL ->
+                                stringResource(R.string.save_password_to_title)
+                            else -> stringResource(R.string.save_sign_in_to_title)
+                        },
+                        style = MaterialTheme.typography.titleMedium,
+                    )
+                },
+                navigationIcon = {
+                    IconButton(onClick = onBackButtonSelected) {
+                        Icon(
+                            Icons.Filled.ArrowBack,
+                            stringResource(R.string.accessibility_back_arrow_button)
+                        )
+                    }
+                },
+                colors = TopAppBarDefaults.smallTopAppBarColors
+                    (containerColor = Color.Transparent),
+            )
+            Divider(
+                thickness = 8.dp,
+                color = Color.Transparent
+            )
+            ContainerCard(
+                shape = MaterialTheme.shapes.medium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally)
+            ) {
+                LazyColumn(
+                    verticalArrangement = Arrangement.spacedBy(2.dp)
+                ) {
+                    enabledProviderList.forEach { enabledProviderInfo ->
+                        enabledProviderInfo.createOptions.forEach { createOptionInfo ->
+                            item {
+                                MoreOptionsInfoRow(
+                                    providerInfo = enabledProviderInfo,
+                                    createOptionInfo = createOptionInfo,
+                                    onOptionSelected = {
+                                        onOptionSelected(
+                                            ActiveEntry(
+                                                enabledProviderInfo,
+                                                createOptionInfo
+                                            )
+                                        )
+                                    })
+                            }
+                        }
+                    }
+                    if (disabledProviderList != null) {
+                        item {
+                            MoreOptionsDisabledProvidersRow(
+                                disabledProviders = disabledProviderList,
+                                onDisabledPasswordManagerSelected =
+                                onDisabledPasswordManagerSelected,
+                            )
+                        }
+                    }
+                    // TODO: handle the error situation that if multiple remoteInfos exists
+                    enabledProviderList.forEach {
+                        if (it.remoteEntry != null) {
+                            item {
+                                RemoteEntryRow(
+                                    remoteInfo = it.remoteEntry!!,
+                                    onRemoteEntrySelected = onRemoteEntrySelected,
+                                )
+                            }
+                        }
+                    }
+                }
             }
-          }
-          if (disabledProviderList != null) {
-            item {
-              MoreOptionsDisabledProvidersRow(
-                disabledProviders = disabledProviderList,
-                onDisabledPasswordManagerSelected = onDisabledPasswordManagerSelected,
-              )
-            }
-          }
-          // TODO: handle the error situation that if multiple remoteInfos exists
-          enabledProviderList.forEach {
-            if (it.remoteEntry != null) {
-              item {
-                RemoteEntryRow(
-                  remoteInfo = it.remoteEntry!!,
-                  onRemoteEntrySelected = onRemoteEntrySelected,
-                )
-              }
-            }
-          }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 40.dp)
+            )
         }
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 40.dp)
-      )
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionsRowIntroCard(
-  providerInfo: EnabledProviderInfo,
-  onDefaultOrNotSelected: () -> Unit,
+    providerInfo: EnabledProviderInfo,
+    onDefaultOrNotSelected: () -> Unit,
 ) {
-  Card() {
-    Column() {
-      Icon(
-        Icons.Outlined.NewReleases,
-        contentDescription = null,
-        modifier = Modifier.align(alignment = Alignment.CenterHorizontally).padding(all = 24.dp)
-      )
-      Text(
-        text = stringResource(R.string.use_provider_for_all_title, providerInfo.displayName),
-        style = MaterialTheme.typography.titleMedium,
-        modifier = Modifier.padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-        textAlign = TextAlign.Center,
-      )
-      Text(
-        text = stringResource(R.string.confirm_default_or_use_once_description),
-        style = MaterialTheme.typography.bodyLarge,
-        modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
-      )
-      Row(
-        horizontalArrangement = Arrangement.SpaceBetween,
-        modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
-      ) {
-        CancelButton(
-          stringResource(R.string.use_once),
-          onClick = onDefaultOrNotSelected
-        )
-        ConfirmButton(
-          stringResource(R.string.set_as_default),
-          onClick = onDefaultOrNotSelected
-        )
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 40.dp)
-      )
+    ContainerCard() {
+        Column() {
+            Icon(
+                Icons.Outlined.NewReleases,
+                contentDescription = null,
+                modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
+                    .padding(all = 24.dp)
+            )
+            TextOnSurface(
+                text = stringResource(
+                    R.string.use_provider_for_all_title,
+                    providerInfo.displayName
+                ),
+                style = MaterialTheme.typography.titleMedium,
+                modifier = Modifier.padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+                textAlign = TextAlign.Center,
+            )
+            TextSecondary(
+                text = stringResource(R.string.use_provider_for_all_description),
+                style = MaterialTheme.typography.bodyLarge,
+                modifier = Modifier.padding(all = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+            )
+            Row(
+                horizontalArrangement = Arrangement.SpaceBetween,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(
+                    stringResource(R.string.use_once),
+                    onClick = onDefaultOrNotSelected
+                )
+                ConfirmButton(
+                    stringResource(R.string.set_as_default),
+                    onClick = onDefaultOrNotSelected
+                )
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 40.dp)
+            )
+        }
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun CreationSelectionCard(
-  requestDisplayInfo: RequestDisplayInfo,
-  enabledProviderList: List<EnabledProviderInfo>,
-  providerInfo: EnabledProviderInfo,
-  createOptionInfo: CreateOptionInfo,
-  showActiveEntryOnly: Boolean,
-  onOptionSelected: (EntryInfo) -> Unit,
-  onConfirm: () -> Unit,
-  onCancel: () -> Unit,
-  onMoreOptionsSelected: () -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    enabledProviderList: List<EnabledProviderInfo>,
+    providerInfo: EnabledProviderInfo,
+    createOptionInfo: CreateOptionInfo,
+    showActiveEntryOnly: Boolean,
+    onOptionSelected: (EntryInfo) -> Unit,
+    onConfirm: () -> Unit,
+    onCancel: () -> Unit,
+    onMoreOptionsSelected: () -> Unit,
 ) {
-  Card() {
-    Column() {
-      Icon(
-        bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
-        contentDescription = null,
-        tint = Color.Unspecified,
-        modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
-          .padding(all = 24.dp).size(32.dp)
-      )
-      Text(
-        text = when (requestDisplayInfo.type) {
-          TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.choose_create_option_passkey_title,
-            providerInfo.displayName)
-          TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.choose_create_option_password_title,
-            providerInfo.displayName)
-          else -> stringResource(R.string.choose_create_option_sign_in_title,
-            providerInfo.displayName)
-        },
-        style = MaterialTheme.typography.titleMedium,
-        modifier = Modifier.padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-        textAlign = TextAlign.Center,
-      )
-      if (createOptionInfo.userProviderDisplayName != null) {
-        Text(
-          text = stringResource(
-            R.string.choose_create_option_description,
-            requestDisplayInfo.appDomainName,
-            when (requestDisplayInfo.type) {
-              TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.passkey)
-              TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.password)
-              else -> stringResource(R.string.sign_ins)
-            },
-            providerInfo.displayName,
-            createOptionInfo.userProviderDisplayName
-          ),
-          style = MaterialTheme.typography.bodyLarge,
-          modifier = Modifier.padding(all = 24.dp).align(alignment = Alignment.CenterHorizontally)
-        )
-      }
-      Card(
-        shape = MaterialTheme.shapes.medium,
-        modifier = Modifier
-          .padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally),
-      ) {
-        PrimaryCreateOptionRow(
-          requestDisplayInfo = requestDisplayInfo,
-          createOptionInfo = createOptionInfo,
-          onOptionSelected = onOptionSelected
-        )
-      }
-      if (!showActiveEntryOnly) {
-        var createOptionsSize = 0
-        enabledProviderList.forEach{
-          enabledProvider -> createOptionsSize += enabledProvider.createOptions.size}
-        if (createOptionsSize > 1) {
-          TextButton(
-            onClick = onMoreOptionsSelected,
-            modifier = Modifier
-            .padding(horizontal = 24.dp)
-            .align(alignment = Alignment.CenterHorizontally)){
-            Text(
-                text =
-                  when (requestDisplayInfo.type) {
-                    TYPE_PUBLIC_KEY_CREDENTIAL ->
-                      stringResource(R.string.string_create_in_another_place)
-                    else -> stringResource(R.string.string_save_to_another_place)},
-              textAlign = TextAlign.Center,
+    ContainerCard() {
+        Column() {
+            Icon(
+                bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
+                contentDescription = null,
+                tint = Color.Unspecified,
+                modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
+                    .padding(all = 24.dp).size(32.dp)
             )
-          }
-        } else if (
-          requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL
-        ) {
-          // TODO: handle the error situation that if multiple remoteInfos exists
-          enabledProviderList.forEach { enabledProvider ->
-            if (enabledProvider.remoteEntry != null) {
-              TextButton(
-                onClick = {
-                  onOptionSelected(enabledProvider.remoteEntry!!) },
-                modifier = Modifier
-                  .padding(horizontal = 24.dp)
-                  .align(alignment = Alignment.CenterHorizontally)
-              ) {
-                Text(
-                  text = stringResource(R.string.string_use_another_device),
-                  textAlign = TextAlign.Center,
+            TextOnSurface(
+                text = when (requestDisplayInfo.type) {
+                    TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(
+                        R.string.choose_create_option_passkey_title,
+                        providerInfo.displayName
+                    )
+                    TYPE_PASSWORD_CREDENTIAL -> stringResource(
+                        R.string.choose_create_option_password_title,
+                        providerInfo.displayName
+                    )
+                    else -> stringResource(
+                        R.string.choose_create_option_sign_in_title,
+                        providerInfo.displayName
+                    )
+                },
+                style = MaterialTheme.typography.titleMedium,
+                modifier = Modifier.padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+                textAlign = TextAlign.Center,
+            )
+            if (createOptionInfo.userProviderDisplayName != null) {
+                TextSecondary(
+                    text = stringResource(
+                        R.string.choose_create_option_description,
+                        requestDisplayInfo.appDomainName,
+                        when (requestDisplayInfo.type) {
+                            TYPE_PUBLIC_KEY_CREDENTIAL -> stringResource(R.string.passkey)
+                            TYPE_PASSWORD_CREDENTIAL -> stringResource(R.string.password)
+                            else -> stringResource(R.string.sign_ins)
+                        },
+                        providerInfo.displayName,
+                        createOptionInfo.userProviderDisplayName
+                    ),
+                    style = MaterialTheme.typography.bodyLarge,
+                    modifier = Modifier.padding(all = 24.dp)
+                        .align(alignment = Alignment.CenterHorizontally),
                 )
-              }
             }
-          }
+            ContainerCard(
+                shape = MaterialTheme.shapes.medium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+            ) {
+                PrimaryCreateOptionRow(
+                    requestDisplayInfo = requestDisplayInfo,
+                    entryInfo = createOptionInfo,
+                    onOptionSelected = onOptionSelected
+                )
+            }
+            if (!showActiveEntryOnly) {
+                var createOptionsSize = 0
+                enabledProviderList.forEach { enabledProvider ->
+                    createOptionsSize += enabledProvider.createOptions.size
+                }
+                if (createOptionsSize > 1) {
+                    TextButton(
+                        onClick = onMoreOptionsSelected,
+                        modifier = Modifier
+                            .padding(horizontal = 24.dp)
+                            .align(alignment = Alignment.CenterHorizontally),
+                        colors = ButtonDefaults.textButtonColors(
+                            contentColor = MaterialTheme.colorScheme.primary,
+                        ),
+                    ) {
+                        Text(
+                            text =
+                            when (requestDisplayInfo.type) {
+                                TYPE_PUBLIC_KEY_CREDENTIAL ->
+                                    stringResource(R.string.string_create_in_another_place)
+                                else -> stringResource(R.string.string_save_to_another_place)
+                            },
+                            textAlign = TextAlign.Center,
+                        )
+                    }
+                } else if (
+                    requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL
+                ) {
+                    // TODO: handle the error situation that if multiple remoteInfos exists
+                    enabledProviderList.forEach { enabledProvider ->
+                        if (enabledProvider.remoteEntry != null) {
+                            TextButton(
+                                onClick = {
+                                    onOptionSelected(enabledProvider.remoteEntry!!)
+                                },
+                                modifier = Modifier
+                                    .padding(horizontal = 24.dp)
+                                    .align(alignment = Alignment.CenterHorizontally),
+                                colors = ButtonDefaults.textButtonColors(
+                                    contentColor = MaterialTheme.colorScheme.primary,
+                                ),
+                            ) {
+                                Text(
+                                    text = stringResource(R.string.string_use_another_device),
+                                    textAlign = TextAlign.Center,
+                                )
+                            }
+                        }
+                    }
+                }
+            }
+            Divider(
+                thickness = 24.dp,
+                color = Color.Transparent
+            )
+            Row(
+                horizontalArrangement = Arrangement.SpaceBetween,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(
+                    stringResource(R.string.string_cancel),
+                    onClick = onCancel
+                )
+                ConfirmButton(
+                    stringResource(R.string.string_continue),
+                    onClick = onConfirm
+                )
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 16.dp)
+            )
         }
-      }
-      Divider(
-        thickness = 24.dp,
-        color = Color.Transparent
-      )
-      Row(
-        horizontalArrangement = Arrangement.SpaceBetween,
-        modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
-      ) {
-        CancelButton(
-          stringResource(R.string.string_cancel),
-          onClick = onCancel
-        )
-        ConfirmButton(
-          stringResource(R.string.string_continue),
-          onClick = onConfirm
-        )
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 16.dp)
-      )
     }
-  }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun ExternalOnlySelectionCard(
+    requestDisplayInfo: RequestDisplayInfo,
+    activeRemoteEntry: EntryInfo,
+    onOptionSelected: (EntryInfo) -> Unit,
+    onConfirm: () -> Unit,
+    onCancel: () -> Unit,
+) {
+    ContainerCard() {
+        Column() {
+            Icon(
+                painter = painterResource(R.drawable.ic_other_devices),
+                contentDescription = null,
+                tint = Color.Unspecified,
+                modifier = Modifier.align(alignment = Alignment.CenterHorizontally)
+                    .padding(all = 24.dp).size(32.dp)
+            )
+            TextOnSurface(
+                text = stringResource(R.string.create_passkey_in_other_device_title),
+                style = MaterialTheme.typography.titleMedium,
+                modifier = Modifier.padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+                textAlign = TextAlign.Center,
+            )
+            Divider(
+                thickness = 24.dp,
+                color = Color.Transparent
+            )
+            ContainerCard(
+                shape = MaterialTheme.shapes.medium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+            ) {
+                PrimaryCreateOptionRow(
+                    requestDisplayInfo = requestDisplayInfo,
+                    entryInfo = activeRemoteEntry,
+                    onOptionSelected = onOptionSelected
+                )
+            }
+            Divider(
+                thickness = 24.dp,
+                color = Color.Transparent
+            )
+            Row(
+                horizontalArrangement = Arrangement.SpaceBetween,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(
+                    stringResource(R.string.string_cancel),
+                    onClick = onCancel
+                )
+                ConfirmButton(
+                    stringResource(R.string.string_continue),
+                    onClick = onConfirm
+                )
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 16.dp)
+            )
+        }
+    }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun PrimaryCreateOptionRow(
-  requestDisplayInfo: RequestDisplayInfo,
-  createOptionInfo: CreateOptionInfo,
-  onOptionSelected: (EntryInfo) -> Unit
+    requestDisplayInfo: RequestDisplayInfo,
+    entryInfo: EntryInfo,
+    onOptionSelected: (EntryInfo) -> Unit
 ) {
-  Entry(
-    onClick = {onOptionSelected(createOptionInfo)},
-    icon = {
-      // TODO: Upload the other two types icons and change it according to request types
-      Icon(
-        painter = painterResource(R.drawable.ic_passkey),
-        contentDescription = null,
-        tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
-        modifier = Modifier.padding(start = 18.dp)
-      )
-    },
-    label = {
-      Column() {
-        // TODO: Add the function to hide/view password when the type is create password
-        if (requestDisplayInfo.type == TYPE_PUBLIC_KEY_CREDENTIAL ||
-          requestDisplayInfo.type == TYPE_PASSWORD_CREDENTIAL) {
-          Text(
-            text = requestDisplayInfo.title,
-            style = MaterialTheme.typography.titleLarge,
-            modifier = Modifier.padding(top = 16.dp)
-          )
-          Text(
-            text = requestDisplayInfo.subtitle,
-            style = MaterialTheme.typography.bodyMedium,
-            modifier = Modifier.padding(bottom = 16.dp)
-          )
-        } else {
-          Text(
-            text = requestDisplayInfo.title,
-            style = MaterialTheme.typography.titleLarge,
-            modifier = Modifier.padding(top = 16.dp, bottom = 16.dp)
-          )
+    Entry(
+        onClick = { onOptionSelected(entryInfo) },
+        icon = {
+            Icon(
+                bitmap = if (entryInfo is CreateOptionInfo) {
+                    entryInfo.profileIcon.toBitmap().asImageBitmap()
+                } else {
+                    requestDisplayInfo.typeIcon.toBitmap().asImageBitmap()
+                },
+                contentDescription = null,
+                tint = LocalAndroidColorScheme.current.colorAccentPrimaryVariant,
+                modifier = Modifier.padding(start = 18.dp).size(32.dp)
+            )
+        },
+        label = {
+            Column() {
+                // TODO: Add the function to hide/view password when the type is create password
+                when (requestDisplayInfo.type) {
+                    TYPE_PUBLIC_KEY_CREDENTIAL -> {
+                        TextOnSurfaceVariant(
+                            text = requestDisplayInfo.title,
+                            style = MaterialTheme.typography.titleLarge,
+                            modifier = Modifier.padding(top = 16.dp),
+                        )
+                        TextSecondary(
+                            text = if (requestDisplayInfo.subtitle != null) {
+                                stringResource(
+                                    R.string.passkey_before_subtitle
+                                ) + " - " + requestDisplayInfo.subtitle
+                            } else {
+                                stringResource(R.string.passkey_before_subtitle)
+                            },
+                            style = MaterialTheme.typography.bodyMedium,
+                            modifier = Modifier.padding(bottom = 16.dp),
+                        )
+                    }
+                    TYPE_PASSWORD_CREDENTIAL -> {
+                        TextOnSurfaceVariant(
+                            text = requestDisplayInfo.title,
+                            style = MaterialTheme.typography.titleLarge,
+                            modifier = Modifier.padding(top = 16.dp),
+                        )
+                        TextSecondary(
+                            // This subtitle would never be null for create password
+                            text = requestDisplayInfo.subtitle ?: "",
+                            style = MaterialTheme.typography.bodyMedium,
+                            modifier = Modifier.padding(bottom = 16.dp),
+                        )
+                    }
+                    else -> {
+                        TextOnSurfaceVariant(
+                            text = requestDisplayInfo.title,
+                            style = MaterialTheme.typography.titleLarge,
+                            modifier = Modifier.padding(top = 16.dp, bottom = 16.dp),
+                        )
+                    }
+                }
+            }
         }
-      }
-    }
-  )
+    )
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionsInfoRow(
-  providerInfo: EnabledProviderInfo,
-  createOptionInfo: CreateOptionInfo,
-  onOptionSelected: () -> Unit
+    providerInfo: EnabledProviderInfo,
+    createOptionInfo: CreateOptionInfo,
+    onOptionSelected: () -> Unit
 ) {
-  Entry(
+    Entry(
         onClick = onOptionSelected,
         icon = {
-            Image(modifier = Modifier.size(32.dp).padding(start = 16.dp),
+            Image(
+                modifier = Modifier.size(32.dp).padding(start = 16.dp),
                 bitmap = providerInfo.icon.toBitmap().asImageBitmap(),
-                contentDescription = null)
+                contentDescription = null
+            )
         },
         label = {
-          Column() {
-              Text(
-                  text = providerInfo.displayName,
-                  style = MaterialTheme.typography.titleLarge,
-                  modifier = Modifier.padding(top = 16.dp, start = 16.dp)
-              )
-            if (createOptionInfo.userProviderDisplayName != null) {
-              Text(
-                text = createOptionInfo.userProviderDisplayName,
-                style = MaterialTheme.typography.bodyMedium,
-                modifier = Modifier.padding(start = 16.dp)
-              )
+            Column() {
+                TextOnSurfaceVariant(
+                    text = providerInfo.displayName,
+                    style = MaterialTheme.typography.titleLarge,
+                    modifier = Modifier.padding(top = 16.dp, start = 16.dp),
+                )
+                if (createOptionInfo.userProviderDisplayName != null) {
+                    TextSecondary(
+                        text = createOptionInfo.userProviderDisplayName,
+                        style = MaterialTheme.typography.bodyMedium,
+                        modifier = Modifier.padding(start = 16.dp),
+                    )
+                }
+                if (createOptionInfo.passwordCount != null &&
+                    createOptionInfo.passkeyCount != null
+                ) {
+                    TextSecondary(
+                        text =
+                        stringResource(
+                            R.string.more_options_usage_passwords_passkeys,
+                            createOptionInfo.passwordCount,
+                            createOptionInfo.passkeyCount
+                        ),
+                        style = MaterialTheme.typography.bodyMedium,
+                        modifier = Modifier.padding(bottom = 16.dp, start = 16.dp),
+                    )
+                } else if (createOptionInfo.passwordCount != null) {
+                    TextSecondary(
+                        text =
+                        stringResource(
+                            R.string.more_options_usage_passwords,
+                            createOptionInfo.passwordCount
+                        ),
+                        style = MaterialTheme.typography.bodyMedium,
+                        modifier = Modifier.padding(bottom = 16.dp, start = 16.dp),
+                    )
+                } else if (createOptionInfo.passkeyCount != null) {
+                    TextSecondary(
+                        text =
+                        stringResource(
+                            R.string.more_options_usage_passkeys,
+                            createOptionInfo.passkeyCount
+                        ),
+                        style = MaterialTheme.typography.bodyMedium,
+                        modifier = Modifier.padding(bottom = 16.dp, start = 16.dp),
+                    )
+                } else if (createOptionInfo.totalCredentialCount != null) {
+                    // TODO: Handle the case when there is total count
+                    // but no passwords and passkeys after design is set
+                }
             }
-            if (createOptionInfo.passwordCount != null && createOptionInfo.passkeyCount != null) {
-              Text(
-                text =
-                  stringResource(
-                    R.string.more_options_usage_passwords_passkeys,
-                    createOptionInfo.passwordCount,
-                    createOptionInfo.passkeyCount
-                  ),
-                style = MaterialTheme.typography.bodyMedium,
-                modifier = Modifier.padding(bottom = 16.dp, start = 16.dp)
-              )
-            } else if (createOptionInfo.passwordCount != null) {
-              Text(
-                text =
-                stringResource(
-                  R.string.more_options_usage_passwords,
-                  createOptionInfo.passwordCount
-                ),
-                style = MaterialTheme.typography.bodyMedium,
-                modifier = Modifier.padding(bottom = 16.dp, start = 16.dp)
-              )
-            } else if (createOptionInfo.passkeyCount != null) {
-              Text(
-                text =
-                stringResource(
-                  R.string.more_options_usage_passkeys,
-                  createOptionInfo.passkeyCount
-                ),
-                style = MaterialTheme.typography.bodyMedium,
-                modifier = Modifier.padding(bottom = 16.dp, start = 16.dp)
-              )
-            } else if (createOptionInfo.totalCredentialCount != null) {
-              // TODO: Handle the case when there is total count
-              // but no passwords and passkeys after design is set
-            }
-          }
         }
     )
 }
@@ -673,61 +824,61 @@
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun MoreOptionsDisabledProvidersRow(
-  disabledProviders: List<ProviderInfo>,
-  onDisabledPasswordManagerSelected: () -> Unit,
+    disabledProviders: List<ProviderInfo>,
+    onDisabledPasswordManagerSelected: () -> Unit,
 ) {
-  Entry(
-    onClick = onDisabledPasswordManagerSelected,
-    icon = {
-      Icon(
-        Icons.Filled.Add,
-        contentDescription = null,
-        modifier = Modifier.padding(start = 16.dp)
-      )
-    },
-    label = {
-      Column() {
-        Text(
-          text = stringResource(R.string.other_password_manager),
-          style = MaterialTheme.typography.titleLarge,
-          modifier = Modifier.padding(top = 16.dp, start = 16.dp)
-        )
-        // TODO: Update the subtitle once design is confirmed
-        Text(
-          text = disabledProviders.joinToString(separator = ", "){ it.displayName },
-          style = MaterialTheme.typography.bodyMedium,
-          modifier = Modifier.padding(bottom = 16.dp, start = 16.dp)
-        )
-      }
-    }
-  )
+    Entry(
+        onClick = onDisabledPasswordManagerSelected,
+        icon = {
+            Icon(
+                Icons.Filled.Add,
+                contentDescription = null,
+                modifier = Modifier.padding(start = 16.dp)
+            )
+        },
+        label = {
+            Column() {
+                TextOnSurfaceVariant(
+                    text = stringResource(R.string.other_password_manager),
+                    style = MaterialTheme.typography.titleLarge,
+                    modifier = Modifier.padding(top = 16.dp, start = 16.dp),
+                )
+                // TODO: Update the subtitle once design is confirmed
+                TextSecondary(
+                    text = disabledProviders.joinToString(separator = ", ") { it.displayName },
+                    style = MaterialTheme.typography.bodyMedium,
+                    modifier = Modifier.padding(bottom = 16.dp, start = 16.dp),
+                )
+            }
+        }
+    )
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun RemoteEntryRow(
-  remoteInfo: RemoteInfo,
-  onRemoteEntrySelected: (RemoteInfo) -> Unit,
+    remoteInfo: RemoteInfo,
+    onRemoteEntrySelected: (RemoteInfo) -> Unit,
 ) {
-  Entry(
-    onClick = {onRemoteEntrySelected(remoteInfo)},
-    icon = {
-      Icon(
-        painter = painterResource(R.drawable.ic_other_devices),
-        contentDescription = null,
-        tint = Color.Unspecified,
-        modifier = Modifier.padding(start = 18.dp)
-      )
-    },
-    label = {
-      Column() {
-        Text(
-          text = stringResource(R.string.another_device),
-          style = MaterialTheme.typography.titleLarge,
-          modifier = Modifier.padding(start = 16.dp, top = 18.dp, bottom = 18.dp)
-            .align(alignment = Alignment.CenterHorizontally)
-        )
-      }
-    }
-  )
+    Entry(
+        onClick = { onRemoteEntrySelected(remoteInfo) },
+        icon = {
+            Icon(
+                painter = painterResource(R.drawable.ic_other_devices),
+                contentDescription = null,
+                tint = Color.Unspecified,
+                modifier = Modifier.padding(start = 18.dp)
+            )
+        },
+        label = {
+            Column() {
+                TextOnSurfaceVariant(
+                    text = stringResource(R.string.another_device),
+                    style = MaterialTheme.typography.titleLarge,
+                    modifier = Modifier.padding(start = 16.dp, top = 18.dp, bottom = 18.dp)
+                        .align(alignment = Alignment.CenterHorizontally),
+                )
+            }
+        }
+    )
 }
\ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
index 0f685a1..6f74998 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateCredentialViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager.createflow
 
+import android.app.Activity
 import android.util.Log
 import androidx.activity.compose.ManagedActivityResultLauncher
 import androidx.activity.result.ActivityResult
@@ -39,6 +40,7 @@
   val showActiveEntryOnly: Boolean,
   val activeEntry: ActiveEntry? = null,
   val selectedEntry: EntryInfo? = null,
+  val hidden: Boolean = false,
 )
 
 class CreateCredentialViewModel(
@@ -128,10 +130,7 @@
     // TODO: implement the if choose as default or not logic later
   }
 
-  fun onEntrySelected(
-    selectedEntry: EntryInfo,
-    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
-  ) {
+  fun onEntrySelected(selectedEntry: EntryInfo) {
     val providerId = selectedEntry.providerId
     val entryKey = selectedEntry.entryKey
     val entrySubkey = selectedEntry.entrySubkey
@@ -139,10 +138,10 @@
       "Account Selector", "Option selected for entry: " +
               " {provider=$providerId, key=$entryKey, subkey=$entrySubkey")
     if (selectedEntry.pendingIntent != null) {
-      uiState = uiState.copy(selectedEntry = selectedEntry)
-      val intentSenderRequest = IntentSenderRequest.Builder(selectedEntry.pendingIntent)
-        .setFillInIntent(selectedEntry.fillInIntent).build()
-      launcher.launch(intentSenderRequest)
+      uiState = uiState.copy(
+        selectedEntry = selectedEntry,
+        hidden = true,
+      )
     } else {
       CredentialManagerRepo.getInstance().onOptionSelected(
         providerId,
@@ -155,12 +154,23 @@
     }
   }
 
-  fun onConfirmCreationSelected(
+  fun launchProviderUi(
     launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
   ) {
+    val entry = uiState.selectedEntry
+    if (entry != null && entry.pendingIntent != null) {
+      val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+        .setFillInIntent(entry.fillInIntent).build()
+      launcher.launch(intentSenderRequest)
+    } else {
+      Log.w("Account Selector", "No provider UI to launch")
+    }
+  }
+
+  fun onConfirmEntrySelected() {
     val selectedEntry = uiState.activeEntry?.activeEntryInfo
     if (selectedEntry != null) {
-      onEntrySelected(selectedEntry, launcher)
+      onEntrySelected(selectedEntry)
     } else {
       Log.w("Account Selector",
         "Illegal state: confirm is pressed but activeEntry isn't set.")
@@ -174,21 +184,29 @@
     val entry = uiState.selectedEntry
     val resultCode = providerActivityResult.resultCode
     val resultData = providerActivityResult.data
-    if (entry != null) {
-      val providerId = entry.providerId
-      Log.d("Account Selector", "Got provider activity result: {provider=" +
-              "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
-              "resultCode=$resultCode, resultData=$resultData}"
-      )
-      CredentialManagerRepo.getInstance().onOptionSelected(
-        providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
+    if (resultCode == Activity.RESULT_CANCELED) {
+      // Re-display the CredMan UI if the user canceled from the provider UI.
+      uiState = uiState.copy(
+        selectedEntry = null,
+        hidden = false,
       )
     } else {
-      Log.w("Account Selector",
-        "Illegal state: received a provider result but found no matching entry.")
+      if (entry != null) {
+        val providerId = entry.providerId
+        Log.d("Account Selector", "Got provider activity result: {provider=" +
+                "$providerId, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
+                "resultCode=$resultCode, resultData=$resultData}"
+        )
+        CredentialManagerRepo.getInstance().onOptionSelected(
+          providerId, entry.entryKey, entry.entrySubkey, resultCode, resultData,
+        )
+      } else {
+        Log.w("Account Selector",
+          "Illegal state: received a provider result but found no matching entry.")
+      }
+      dialogResult.value = DialogResult(
+        ResultState.COMPLETE,
+      )
     }
-    dialogResult.value = DialogResult(
-      ResultState.COMPLETE,
-    )
   }
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
index 6dd6afb..9ac524a 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/createflow/CreateModel.kt
@@ -73,9 +73,10 @@
 
 data class RequestDisplayInfo(
   val title: String,
-  val subtitle: String,
+  val subtitle: String?,
   val type: String,
   val appDomainName: String,
+  val typeIcon: Drawable,
 )
 
 /**
@@ -94,4 +95,5 @@
   CREATION_OPTION_SELECTION,
   MORE_OPTIONS_SELECTION,
   MORE_OPTIONS_ROW_INTRO,
+  EXTERNAL_ONLY_SELECTION,
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
index db0c16c..21342a1 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialComponents.kt
@@ -22,6 +22,7 @@
 import androidx.activity.result.IntentSenderRequest
 
 import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
@@ -31,13 +32,11 @@
 import androidx.compose.foundation.layout.wrapContentHeight
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.items
-import androidx.compose.material3.Card
 import androidx.compose.material3.Divider
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
 import androidx.compose.material3.IconButton
 import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
 import androidx.compose.material3.TopAppBar
 import androidx.compose.material3.TopAppBarDefaults
 import androidx.compose.material.icons.Icons
@@ -59,201 +58,217 @@
 import com.android.credentialmanager.common.material.rememberModalBottomSheetState
 import com.android.credentialmanager.common.ui.CancelButton
 import com.android.credentialmanager.common.ui.Entry
+import com.android.credentialmanager.common.ui.TextOnSurface
+import com.android.credentialmanager.common.ui.TextSecondary
+import com.android.credentialmanager.common.ui.TextOnSurfaceVariant
+import com.android.credentialmanager.common.ui.ContainerCard
 import com.android.credentialmanager.common.ui.TransparentBackgroundEntry
 import com.android.credentialmanager.jetpack.developer.PublicKeyCredential
+import com.android.credentialmanager.ui.theme.EntryShape
 
 @Composable
 fun GetCredentialScreen(
-  viewModel: GetCredentialViewModel,
-  providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+    viewModel: GetCredentialViewModel,
+    providerActivityLauncher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
 ) {
-  val entrySelectionCallback: (EntryInfo) -> Unit = {
-    viewModel.onEntrySelected(it, providerActivityLauncher)
-  }
-  val state = rememberModalBottomSheetState(
-    initialValue = ModalBottomSheetValue.Expanded,
-    skipHalfExpanded = true
-  )
-  ModalBottomSheetLayout(
-    sheetState = state,
-    sheetContent = {
-      val uiState = viewModel.uiState
-      when (uiState.currentScreenState) {
-        GetScreenState.PRIMARY_SELECTION -> PrimarySelectionCard(
-          requestDisplayInfo = uiState.requestDisplayInfo,
-          providerDisplayInfo = uiState.providerDisplayInfo,
-          onEntrySelected = entrySelectionCallback,
-          onCancel = viewModel::onCancel,
-          onMoreOptionSelected = viewModel::onMoreOptionSelected,
-        )
-        GetScreenState.ALL_SIGN_IN_OPTIONS -> AllSignInOptionCard(
-          providerInfoList = uiState.providerInfoList,
-          providerDisplayInfo = uiState.providerDisplayInfo,
-          onEntrySelected = entrySelectionCallback,
-          onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
-        )
-      }
-    },
-    scrimColor = Color.Transparent,
-    sheetShape = MaterialTheme.shapes.medium,
-  ) {}
-  LaunchedEffect(state.currentValue) {
-    if (state.currentValue == ModalBottomSheetValue.Hidden) {
-      viewModel.onCancel()
+    val state = rememberModalBottomSheetState(
+        initialValue = ModalBottomSheetValue.Expanded,
+        skipHalfExpanded = true
+    )
+    ModalBottomSheetLayout(
+        sheetBackgroundColor = MaterialTheme.colorScheme.surface,
+        modifier = Modifier.background(Color.Transparent),
+        sheetState = state,
+        sheetContent = {
+            val uiState = viewModel.uiState
+            if (!uiState.hidden) {
+                when (uiState.currentScreenState) {
+                    GetScreenState.PRIMARY_SELECTION -> PrimarySelectionCard(
+                        requestDisplayInfo = uiState.requestDisplayInfo,
+                        providerDisplayInfo = uiState.providerDisplayInfo,
+                        onEntrySelected = viewModel::onEntrySelected,
+                        onCancel = viewModel::onCancel,
+                        onMoreOptionSelected = viewModel::onMoreOptionSelected,
+                    )
+                    GetScreenState.ALL_SIGN_IN_OPTIONS -> AllSignInOptionCard(
+                        providerInfoList = uiState.providerInfoList,
+                        providerDisplayInfo = uiState.providerDisplayInfo,
+                        onEntrySelected = viewModel::onEntrySelected,
+                        onBackButtonClicked = viewModel::onBackToPrimarySelectionScreen,
+                    )
+                }
+            } else if (uiState.hidden && uiState.selectedEntry != null) {
+                viewModel.launchProviderUi(providerActivityLauncher)
+            }
+        },
+        scrimColor = MaterialTheme.colorScheme.scrim.copy(alpha = 0.8f),
+        sheetShape = EntryShape.TopRoundedCorner,
+    ) {}
+    LaunchedEffect(state.currentValue) {
+        if (state.currentValue == ModalBottomSheetValue.Hidden) {
+            viewModel.onCancel()
+        }
     }
-  }
 }
 
 /** Draws the primary credential selection page. */
 @Composable
 fun PrimarySelectionCard(
-  requestDisplayInfo: RequestDisplayInfo,
-  providerDisplayInfo: ProviderDisplayInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
-  onCancel: () -> Unit,
-  onMoreOptionSelected: () -> Unit,
+    requestDisplayInfo: RequestDisplayInfo,
+    providerDisplayInfo: ProviderDisplayInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
+    onCancel: () -> Unit,
+    onMoreOptionSelected: () -> Unit,
 ) {
-  val sortedUserNameToCredentialEntryList = providerDisplayInfo.sortedUserNameToCredentialEntryList
-  val authenticationEntryList = providerDisplayInfo.authenticationEntryList
-  Card() {
-    Column() {
-      Text(
-        modifier = Modifier.padding(all = 24.dp),
-        textAlign = TextAlign.Center,
-        style = MaterialTheme.typography.headlineSmall,
-        text = stringResource(
-          if (sortedUserNameToCredentialEntryList.size == 1) {
-            if (sortedUserNameToCredentialEntryList.first().sortedCredentialEntryList
-                .first().credentialType == PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL
+    val sortedUserNameToCredentialEntryList =
+        providerDisplayInfo.sortedUserNameToCredentialEntryList
+    val authenticationEntryList = providerDisplayInfo.authenticationEntryList
+    ContainerCard() {
+        Column() {
+            TextOnSurface(
+                modifier = Modifier.padding(all = 24.dp),
+                textAlign = TextAlign.Center,
+                style = MaterialTheme.typography.headlineSmall,
+                text = stringResource(
+                    if (sortedUserNameToCredentialEntryList.size == 1) {
+                        if (sortedUserNameToCredentialEntryList.first().sortedCredentialEntryList
+                                .first().credentialType
+                            == PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL
+                        )
+                            R.string.get_dialog_title_use_passkey_for
+                        else R.string.get_dialog_title_use_sign_in_for
+                    } else R.string.get_dialog_title_choose_sign_in_for,
+                    requestDisplayInfo.appDomainName
+                ),
             )
-              R.string.get_dialog_title_use_passkey_for
-            else R.string.get_dialog_title_use_sign_in_for
-          } else R.string.get_dialog_title_choose_sign_in_for,
-          requestDisplayInfo.appDomainName
-        ),
-      )
 
-      Card(
-        shape = MaterialTheme.shapes.medium,
-        modifier = Modifier
-          .padding(horizontal = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally)
-      ) {
-        LazyColumn(
-          verticalArrangement = Arrangement.spacedBy(2.dp)
-        ) {
-          items(sortedUserNameToCredentialEntryList) {
-            CredentialEntryRow(
-              credentialEntryInfo = it.sortedCredentialEntryList.first(),
-              onEntrySelected = onEntrySelected,
+            ContainerCard(
+                shape = MaterialTheme.shapes.medium,
+                modifier = Modifier
+                    .padding(horizontal = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally)
+            ) {
+                LazyColumn(
+                    verticalArrangement = Arrangement.spacedBy(2.dp)
+                ) {
+                    items(sortedUserNameToCredentialEntryList) {
+                        CredentialEntryRow(
+                            credentialEntryInfo = it.sortedCredentialEntryList.first(),
+                            onEntrySelected = onEntrySelected,
+                        )
+                    }
+                    items(authenticationEntryList) {
+                        AuthenticationEntryRow(
+                            authenticationEntryInfo = it,
+                            onEntrySelected = onEntrySelected,
+                        )
+                    }
+                    item {
+                        SignInAnotherWayRow(onSelect = onMoreOptionSelected)
+                    }
+                }
+            }
+            Divider(
+                thickness = 24.dp,
+                color = Color.Transparent
             )
-          }
-          items(authenticationEntryList) {
-            AuthenticationEntryRow(
-              authenticationEntryInfo = it,
-              onEntrySelected = onEntrySelected,
+            Row(
+                horizontalArrangement = Arrangement.Start,
+                modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
+            ) {
+                CancelButton(stringResource(R.string.get_dialog_button_label_no_thanks), onCancel)
+            }
+            Divider(
+                thickness = 18.dp,
+                color = Color.Transparent,
+                modifier = Modifier.padding(bottom = 16.dp)
             )
-          }
-          item {
-            SignInAnotherWayRow(onSelect = onMoreOptionSelected)
-          }
         }
-      }
-      Divider(
-        thickness = 24.dp,
-        color = Color.Transparent
-      )
-      Row(
-        horizontalArrangement = Arrangement.Start,
-        modifier = Modifier.fillMaxWidth().padding(horizontal = 24.dp)
-      ) {
-        CancelButton(stringResource(R.string.string_no_thanks), onCancel)
-      }
-      Divider(
-        thickness = 18.dp,
-        color = Color.Transparent,
-        modifier = Modifier.padding(bottom = 16.dp)
-      )
     }
-  }
 }
 
 /** Draws the secondary credential selection page, where all sign-in options are listed. */
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun AllSignInOptionCard(
-  providerInfoList: List<ProviderInfo>,
-  providerDisplayInfo: ProviderDisplayInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
-  onBackButtonClicked: () -> Unit,
+    providerInfoList: List<ProviderInfo>,
+    providerDisplayInfo: ProviderDisplayInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
+    onBackButtonClicked: () -> Unit,
 ) {
-  val sortedUserNameToCredentialEntryList = providerDisplayInfo.sortedUserNameToCredentialEntryList
-  val authenticationEntryList = providerDisplayInfo.authenticationEntryList
-  Card() {
-    Column() {
-      TopAppBar(
-        colors = TopAppBarDefaults.smallTopAppBarColors(
-          containerColor = Color.Transparent,
-        ),
-        title = {
-          Text(
-            text = stringResource(R.string.get_dialog_title_sign_in_options),
-            style = MaterialTheme.typography.titleMedium
-          )
-        },
-        navigationIcon = {
-          IconButton(onClick = onBackButtonClicked) {
-            Icon(
-              Icons.Filled.ArrowBack,
-              contentDescription = stringResource(R.string.accessibility_back_arrow_button))
-          }
-        },
-        modifier = Modifier.padding(top = 12.dp)
-      )
-
-      Card(
-        shape = MaterialTheme.shapes.large,
-        modifier = Modifier
-          .padding(start = 24.dp, end = 24.dp, bottom = 24.dp)
-          .align(alignment = Alignment.CenterHorizontally)
-      ) {
-        LazyColumn(
-          verticalArrangement = Arrangement.spacedBy(8.dp)
-        ) {
-          // For username
-          items(sortedUserNameToCredentialEntryList) { item ->
-            PerUserNameCredentials(
-              perUserNameCredentialEntryList = item,
-              onEntrySelected = onEntrySelected,
+    val sortedUserNameToCredentialEntryList =
+        providerDisplayInfo.sortedUserNameToCredentialEntryList
+    val authenticationEntryList = providerDisplayInfo.authenticationEntryList
+    ContainerCard() {
+        Column() {
+            TopAppBar(
+                colors = TopAppBarDefaults.smallTopAppBarColors(
+                    containerColor = Color.Transparent,
+                ),
+                title = {
+                    TextOnSurface(
+                        text = stringResource(R.string.get_dialog_title_sign_in_options),
+                        style = MaterialTheme.typography.titleMedium
+                    )
+                },
+                navigationIcon = {
+                    IconButton(onClick = onBackButtonClicked) {
+                        Icon(
+                            Icons.Filled.ArrowBack,
+                            contentDescription = stringResource(
+                                R.string.accessibility_back_arrow_button)
+                        )
+                    }
+                },
+                modifier = Modifier.padding(top = 12.dp)
             )
-          }
-          // Locked password manager
-          if (!authenticationEntryList.isEmpty()) {
-            item {
-              LockedCredentials(
-                authenticationEntryList = authenticationEntryList,
-                onEntrySelected = onEntrySelected,
-              )
+
+            ContainerCard(
+                shape = MaterialTheme.shapes.large,
+                modifier = Modifier
+                    .padding(start = 24.dp, end = 24.dp, bottom = 24.dp)
+                    .align(alignment = Alignment.CenterHorizontally),
+            ) {
+                LazyColumn(
+                    verticalArrangement = Arrangement.spacedBy(8.dp)
+                ) {
+                    // For username
+                    items(sortedUserNameToCredentialEntryList) { item ->
+                        PerUserNameCredentials(
+                            perUserNameCredentialEntryList = item,
+                            onEntrySelected = onEntrySelected,
+                        )
+                    }
+                    // Locked password manager
+                    if (!authenticationEntryList.isEmpty()) {
+                        item {
+                            LockedCredentials(
+                                authenticationEntryList = authenticationEntryList,
+                                onEntrySelected = onEntrySelected,
+                            )
+                        }
+                    }
+                    // From another device
+                    val remoteEntry = providerDisplayInfo.remoteEntry
+                    if (remoteEntry != null) {
+                        item {
+                            RemoteEntryCard(
+                                remoteEntry = remoteEntry,
+                                onEntrySelected = onEntrySelected,
+                            )
+                        }
+                    }
+                    // Manage sign-ins (action chips)
+                    item {
+                        ActionChips(
+                            providerInfoList = providerInfoList,
+                            onEntrySelected = onEntrySelected
+                        )
+                    }
+                }
             }
-          }
-          // From another device
-          val remoteEntry = providerDisplayInfo.remoteEntry
-          if (remoteEntry != null) {
-            item {
-              RemoteEntryCard(
-                remoteEntry = remoteEntry,
-                onEntrySelected = onEntrySelected,
-              )
-            }
-          }
-          // Manage sign-ins (action chips)
-          item {
-            ActionChips(providerInfoList = providerInfoList, onEntrySelected = onEntrySelected)
-          }
         }
-      }
     }
-  }
 }
 
 // TODO: create separate rows for primary and secondary pages.
@@ -261,236 +276,245 @@
 
 @Composable
 fun ActionChips(
-  providerInfoList: List<ProviderInfo>,
-  onEntrySelected: (EntryInfo) -> Unit,
+    providerInfoList: List<ProviderInfo>,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  val actionChips = providerInfoList.flatMap { it.actionEntryList }
-  if (actionChips.isEmpty()) {
-    return
-  }
-
-  Text(
-    text = stringResource(R.string.get_dialog_heading_manage_sign_ins),
-    style = MaterialTheme.typography.labelLarge,
-    modifier = Modifier.padding(vertical = 8.dp)
-  )
-  // TODO: tweak padding.
-  Card(
-    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-    shape = MaterialTheme.shapes.medium,
-  ) {
-    Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
-      actionChips.forEach {
-        ActionEntryRow(it, onEntrySelected)
-      }
+    val actionChips = providerInfoList.flatMap { it.actionEntryList }
+    if (actionChips.isEmpty()) {
+        return
     }
-  }
+
+    TextSecondary(
+        text = stringResource(R.string.get_dialog_heading_manage_sign_ins),
+        style = MaterialTheme.typography.labelLarge,
+        modifier = Modifier.padding(vertical = 8.dp)
+    )
+    // TODO: tweak padding.
+    ContainerCard(
+        modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+        shape = MaterialTheme.shapes.medium,
+    ) {
+        Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
+            actionChips.forEach {
+                ActionEntryRow(it, onEntrySelected)
+            }
+        }
+    }
 }
 
 @Composable
 fun RemoteEntryCard(
-  remoteEntry: RemoteEntryInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
+    remoteEntry: RemoteEntryInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Text(
-    text = stringResource(R.string.get_dialog_heading_from_another_device),
-    style = MaterialTheme.typography.labelLarge,
-    modifier = Modifier.padding(vertical = 8.dp)
-  )
-  Card(
-    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-    shape = MaterialTheme.shapes.medium,
-  ) {
-    Column(
-      modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-      verticalArrangement = Arrangement.spacedBy(2.dp),
+    TextSecondary(
+        text = stringResource(R.string.get_dialog_heading_from_another_device),
+        style = MaterialTheme.typography.labelLarge,
+        modifier = Modifier.padding(vertical = 8.dp)
+    )
+    ContainerCard(
+        modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+        shape = MaterialTheme.shapes.medium,
     ) {
-      Entry(
-        onClick = {onEntrySelected(remoteEntry)},
-        icon = {
-          Icon(
-            painter = painterResource(R.drawable.ic_other_devices),
-            contentDescription = null,
-            tint = Color.Unspecified,
-            modifier = Modifier.padding(start = 18.dp)
-          )
-        },
-        label = {
-          Text(
-            text = stringResource(R.string.get_dialog_option_headline_use_a_different_device),
-            style = MaterialTheme.typography.titleLarge,
-            modifier = Modifier.padding(start = 16.dp, top = 18.dp, bottom = 18.dp)
-              .align(alignment = Alignment.CenterHorizontally)
-          )
+        Column(
+            modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+            verticalArrangement = Arrangement.spacedBy(2.dp),
+        ) {
+            Entry(
+                onClick = { onEntrySelected(remoteEntry) },
+                icon = {
+                    Icon(
+                        painter = painterResource(R.drawable.ic_other_devices),
+                        contentDescription = null,
+                        tint = Color.Unspecified,
+                        modifier = Modifier.padding(start = 18.dp)
+                    )
+                },
+                label = {
+                    TextOnSurfaceVariant(
+                        text = stringResource(
+                            R.string.get_dialog_option_headline_use_a_different_device),
+                        style = MaterialTheme.typography.titleLarge,
+                        modifier = Modifier.padding(start = 16.dp, top = 18.dp, bottom = 18.dp)
+                            .align(alignment = Alignment.CenterHorizontally)
+                    )
+                }
+            )
         }
-      )
     }
-  }
 }
 
 @Composable
 fun LockedCredentials(
-  authenticationEntryList: List<AuthenticationEntryInfo>,
-  onEntrySelected: (EntryInfo) -> Unit,
+    authenticationEntryList: List<AuthenticationEntryInfo>,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Text(
-    text = stringResource(R.string.get_dialog_heading_locked_password_managers),
-    style = MaterialTheme.typography.labelLarge,
-    modifier = Modifier.padding(vertical = 8.dp)
-  )
-  Card(
-    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-    shape = MaterialTheme.shapes.medium,
-  ) {
-    Column(
-      modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-      verticalArrangement = Arrangement.spacedBy(2.dp),
+    TextSecondary(
+        text = stringResource(R.string.get_dialog_heading_locked_password_managers),
+        style = MaterialTheme.typography.labelLarge,
+        modifier = Modifier.padding(vertical = 8.dp)
+    )
+    ContainerCard(
+        modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+        shape = MaterialTheme.shapes.medium,
     ) {
-      authenticationEntryList.forEach {
-        AuthenticationEntryRow(it, onEntrySelected)
-      }
+        Column(
+            modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+            verticalArrangement = Arrangement.spacedBy(2.dp),
+        ) {
+            authenticationEntryList.forEach {
+                AuthenticationEntryRow(it, onEntrySelected)
+            }
+        }
     }
-  }
 }
 
 @Composable
 fun PerUserNameCredentials(
-  perUserNameCredentialEntryList: PerUserNameCredentialEntryList,
-  onEntrySelected: (EntryInfo) -> Unit,
+    perUserNameCredentialEntryList: PerUserNameCredentialEntryList,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Text(
-    text = stringResource(
-      R.string.get_dialog_heading_for_username, perUserNameCredentialEntryList.userName),
-    style = MaterialTheme.typography.labelLarge,
-    modifier = Modifier.padding(vertical = 8.dp)
-  )
-  Card(
-    modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-    shape = MaterialTheme.shapes.medium,
-  ) {
-    Column(
-      modifier = Modifier.fillMaxWidth().wrapContentHeight(),
-      verticalArrangement = Arrangement.spacedBy(2.dp),
+    TextSecondary(
+        text = stringResource(
+            R.string.get_dialog_heading_for_username, perUserNameCredentialEntryList.userName
+        ),
+        style = MaterialTheme.typography.labelLarge,
+        modifier = Modifier.padding(vertical = 8.dp)
+    )
+    ContainerCard(
+        modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+        shape = MaterialTheme.shapes.medium,
     ) {
-      perUserNameCredentialEntryList.sortedCredentialEntryList.forEach {
-        CredentialEntryRow(it, onEntrySelected)
-      }
+        Column(
+            modifier = Modifier.fillMaxWidth().wrapContentHeight(),
+            verticalArrangement = Arrangement.spacedBy(2.dp),
+        ) {
+            perUserNameCredentialEntryList.sortedCredentialEntryList.forEach {
+                CredentialEntryRow(it, onEntrySelected)
+            }
+        }
     }
-  }
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun CredentialEntryRow(
-  credentialEntryInfo: CredentialEntryInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
+    credentialEntryInfo: CredentialEntryInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Entry(
-    onClick = {onEntrySelected(credentialEntryInfo)},
-    icon = {
-      Image(modifier = Modifier.padding(start = 10.dp).size(32.dp),
-        bitmap = credentialEntryInfo.icon.toBitmap().asImageBitmap(),
-        // TODO: add description.
-        contentDescription = "")
-    },
-    label = {
-      Column() {
-        // TODO: fix the text values.
-        Text(
-          text = credentialEntryInfo.userName,
-          style = MaterialTheme.typography.titleLarge,
-          modifier = Modifier.padding(top = 16.dp)
-        )
-        Text(
-          text =
-          if (TextUtils.isEmpty(credentialEntryInfo.displayName))
-            credentialEntryInfo.credentialTypeDisplayName
-          else
-            credentialEntryInfo.credentialTypeDisplayName +
-                    stringResource(R.string.get_dialog_sign_in_type_username_separator) +
-                    credentialEntryInfo.displayName,
-          style = MaterialTheme.typography.bodyMedium,
-          modifier = Modifier.padding(bottom = 16.dp)
-        )
-      }
-    }
-  )
+    Entry(
+        onClick = { onEntrySelected(credentialEntryInfo) },
+        icon = {
+            Image(
+                modifier = Modifier.padding(start = 10.dp).size(32.dp),
+                bitmap = credentialEntryInfo.icon.toBitmap().asImageBitmap(),
+                // TODO: add description.
+                contentDescription = ""
+            )
+        },
+        label = {
+            Column() {
+                // TODO: fix the text values.
+                TextOnSurfaceVariant(
+                    text = credentialEntryInfo.userName,
+                    style = MaterialTheme.typography.titleLarge,
+                    modifier = Modifier.padding(top = 16.dp)
+                )
+                TextSecondary(
+                    text =
+                    if (TextUtils.isEmpty(credentialEntryInfo.displayName))
+                        credentialEntryInfo.credentialTypeDisplayName
+                    else
+                        credentialEntryInfo.credentialTypeDisplayName +
+                                stringResource(
+                                    R.string.get_dialog_sign_in_type_username_separator) +
+                                credentialEntryInfo.displayName,
+                    style = MaterialTheme.typography.bodyMedium,
+                    modifier = Modifier.padding(bottom = 16.dp)
+                )
+            }
+        }
+    )
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun AuthenticationEntryRow(
-  authenticationEntryInfo: AuthenticationEntryInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
+    authenticationEntryInfo: AuthenticationEntryInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  Entry(
-    onClick = {onEntrySelected(authenticationEntryInfo)},
-    icon = {
-      Image(modifier = Modifier.padding(start = 10.dp).size(32.dp),
-        bitmap = authenticationEntryInfo.icon.toBitmap().asImageBitmap(),
-        // TODO: add description.
-        contentDescription = "")
-    },
-    label = {
-      Column() {
-        // TODO: fix the text values.
-        Text(
-          text = authenticationEntryInfo.title,
-          style = MaterialTheme.typography.titleLarge,
-          modifier = Modifier.padding(top = 16.dp)
-        )
-        Text(
-          text = stringResource(R.string.locked_credential_entry_label_subtext),
-          style = MaterialTheme.typography.bodyMedium,
-          modifier = Modifier.padding(bottom = 16.dp)
-        )
-      }
-    }
-  )
+    Entry(
+        onClick = { onEntrySelected(authenticationEntryInfo) },
+        icon = {
+            Image(
+                modifier = Modifier.padding(start = 10.dp).size(32.dp),
+                bitmap = authenticationEntryInfo.icon.toBitmap().asImageBitmap(),
+                // TODO: add description.
+                contentDescription = ""
+            )
+        },
+        label = {
+            Column() {
+                // TODO: fix the text values.
+                TextOnSurfaceVariant(
+                    text = authenticationEntryInfo.title,
+                    style = MaterialTheme.typography.titleLarge,
+                    modifier = Modifier.padding(top = 16.dp)
+                )
+                TextSecondary(
+                    text = stringResource(R.string.locked_credential_entry_label_subtext),
+                    style = MaterialTheme.typography.bodyMedium,
+                    modifier = Modifier.padding(bottom = 16.dp)
+                )
+            }
+        }
+    )
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun ActionEntryRow(
-  actionEntryInfo: ActionEntryInfo,
-  onEntrySelected: (EntryInfo) -> Unit,
+    actionEntryInfo: ActionEntryInfo,
+    onEntrySelected: (EntryInfo) -> Unit,
 ) {
-  TransparentBackgroundEntry(
-    icon = {
-      Image(modifier = Modifier.padding(start = 10.dp).size(32.dp),
-        bitmap = actionEntryInfo.icon.toBitmap().asImageBitmap(),
-        // TODO: add description.
-        contentDescription = "")
-    },
-    label = {
-      Column() {
-        Text(
-          text = actionEntryInfo.title,
-          style = MaterialTheme.typography.titleLarge,
-        )
-        if (actionEntryInfo.subTitle != null) {
-          Text(
-            text = actionEntryInfo.subTitle,
-            style = MaterialTheme.typography.bodyMedium,
-          )
-        }
-      }
-    },
-    onClick = { onEntrySelected(actionEntryInfo) },
-  )
+    TransparentBackgroundEntry(
+        icon = {
+            Image(
+                modifier = Modifier.padding(start = 10.dp).size(32.dp),
+                bitmap = actionEntryInfo.icon.toBitmap().asImageBitmap(),
+                // TODO: add description.
+                contentDescription = ""
+            )
+        },
+        label = {
+            Column() {
+                TextOnSurfaceVariant(
+                    text = actionEntryInfo.title,
+                    style = MaterialTheme.typography.titleLarge,
+                )
+                if (actionEntryInfo.subTitle != null) {
+                    TextSecondary(
+                        text = actionEntryInfo.subTitle,
+                        style = MaterialTheme.typography.bodyMedium,
+                    )
+                }
+            }
+        },
+        onClick = { onEntrySelected(actionEntryInfo) },
+    )
 }
 
 @OptIn(ExperimentalMaterial3Api::class)
 @Composable
 fun SignInAnotherWayRow(onSelect: () -> Unit) {
-  Entry(
-    onClick = onSelect,
-    label = {
-      Text(
-        text = stringResource(R.string.get_dialog_use_saved_passkey_for),
-        style = MaterialTheme.typography.titleLarge,
-        modifier = Modifier.padding(vertical = 16.dp)
-      )
-    }
-  )
+    Entry(
+        onClick = onSelect,
+        label = {
+            TextOnSurfaceVariant(
+                text = stringResource(R.string.get_dialog_use_saved_passkey_for),
+                style = MaterialTheme.typography.titleLarge,
+                modifier = Modifier.padding(vertical = 16.dp)
+            )
+        }
+    )
 }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
index 6dea9c2..33e7021 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/getflow/GetCredentialViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.credentialmanager.getflow
 
+import android.app.Activity
 import android.util.Log
 import androidx.activity.compose.ManagedActivityResultLauncher
 import androidx.activity.result.ActivityResult
@@ -39,6 +40,7 @@
   val requestDisplayInfo: RequestDisplayInfo,
   val providerDisplayInfo: ProviderDisplayInfo = toProviderDisplayInfo(providerInfoList),
   val selectedEntry: EntryInfo? = null,
+  val hidden: Boolean = false,
 )
 
 class GetCredentialViewModel(
@@ -56,17 +58,14 @@
     return dialogResult
   }
 
-  fun onEntrySelected(
-    entry: EntryInfo,
-    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
-  ) {
+  fun onEntrySelected(entry: EntryInfo) {
     Log.d("Account Selector", "credential selected:" +
             " {provider=${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}}")
     if (entry.pendingIntent != null) {
-      uiState = uiState.copy(selectedEntry = entry)
-      val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
-        .setFillInIntent(entry.fillInIntent).build()
-      launcher.launch(intentSenderRequest)
+      uiState = uiState.copy(
+        selectedEntry = entry,
+        hidden = true,
+      )
     } else {
       CredentialManagerRepo.getInstance().onOptionSelected(
         entry.providerId, entry.entryKey, entry.entrySubkey,
@@ -75,24 +74,45 @@
     }
   }
 
+  fun launchProviderUi(
+    launcher: ManagedActivityResultLauncher<IntentSenderRequest, ActivityResult>
+  ) {
+    val entry = uiState.selectedEntry
+    if (entry != null && entry.pendingIntent != null) {
+      val intentSenderRequest = IntentSenderRequest.Builder(entry.pendingIntent)
+        .setFillInIntent(entry.fillInIntent).build()
+      launcher.launch(intentSenderRequest)
+    } else {
+      Log.w("Account Selector", "No provider UI to launch")
+    }
+  }
+
   fun onProviderActivityResult(providerActivityResult: ProviderActivityResult) {
     val entry = uiState.selectedEntry
     val resultCode = providerActivityResult.resultCode
     val resultData = providerActivityResult.data
-    if (entry != null) {
-      Log.d("Account Selector", "Got provider activity result: {provider=" +
-              "${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
-                "resultCode=$resultCode, resultData=$resultData}"
-      )
-      CredentialManagerRepo.getInstance().onOptionSelected(
-        entry.providerId, entry.entryKey, entry.entrySubkey,
-        resultCode, resultData,
+    if (resultCode == Activity.RESULT_CANCELED) {
+      // Re-display the CredMan UI if the user canceled from the provider UI.
+      uiState = uiState.copy(
+        selectedEntry = null,
+        hidden = false,
       )
     } else {
-      Log.w("Account Selector",
-        "Illegal state: received a provider result but found no matching entry.")
+      if (entry != null) {
+        Log.d("Account Selector", "Got provider activity result: {provider=" +
+                "${entry.providerId}, key=${entry.entryKey}, subkey=${entry.entrySubkey}, " +
+                "resultCode=$resultCode, resultData=$resultData}"
+        )
+        CredentialManagerRepo.getInstance().onOptionSelected(
+          entry.providerId, entry.entryKey, entry.entrySubkey,
+          resultCode, resultData,
+        )
+      } else {
+        Log.w("Account Selector",
+          "Illegal state: received a provider result but found no matching entry.")
+      }
+      dialogResult.value = DialogResult(ResultState.COMPLETE)
     }
-    dialogResult.value = DialogResult(ResultState.COMPLETE)
   }
 
   fun onMoreOptionSelected() {
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
index 7e7dbde..008e1b6 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreateCredentialRequest.kt
@@ -38,14 +38,18 @@
             return try {
                 when (from.type) {
                     Credential.TYPE_PASSWORD_CREDENTIAL ->
-                        CreatePasswordRequest.createFrom(from.data)
+                        CreatePasswordRequest.createFrom(from.credentialData)
                     PublicKeyCredential.TYPE_PUBLIC_KEY_CREDENTIAL ->
-                        CreatePublicKeyCredentialBaseRequest.createFrom(from.data)
+                        CreatePublicKeyCredentialBaseRequest.createFrom(from.credentialData)
                     else ->
-                        CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
+                        CreateCredentialRequest(
+                            from.type, from.credentialData, from.requireSystemProvider()
+                        )
                 }
             } catch (e: FrameworkClassParsingException) {
-                CreateCredentialRequest(from.type, from.data, from.requireSystemProvider())
+                CreateCredentialRequest(
+                    from.type, from.credentialData, from.requireSystemProvider()
+                )
             }
         }
     }
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
index 26d61f9..37a4f76 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/jetpack/developer/CreatePublicKeyCredentialBaseRequest.kt
@@ -47,7 +47,7 @@
             return when (data.getString(BUNDLE_KEY_SUBTYPE)) {
                 CreatePublicKeyCredentialRequest
                         .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST ->
-                    CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
+                    CreatePublicKeyCredentialRequest.createFrom(data)
                 CreatePublicKeyCredentialRequestPrivileged
                         .BUNDLE_VALUE_SUBTYPE_CREATE_PUBLIC_KEY_CREDENTIAL_REQUEST_PRIVILEGED ->
                     CreatePublicKeyCredentialRequestPrivileged.createFrom(data)
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
index 4757513..fe640ad 100644
--- a/packages/PackageInstaller/Android.bp
+++ b/packages/PackageInstaller/Android.bp
@@ -58,6 +58,7 @@
     privileged: true,
     platform_apis: true,
     rename_resources_package: false,
+    overrides: ["PackageInstaller"],
 
     static_libs: [
         "xz-java",
@@ -76,6 +77,7 @@
     privileged: true,
     platform_apis: true,
     rename_resources_package: false,
+    overrides: ["PackageInstaller"],
 
     static_libs: [
         "xz-java",
diff --git a/packages/PackageInstaller/res/values-am/strings.xml b/packages/PackageInstaller/res/values-am/strings.xml
index 2934b01..094ece7 100644
--- a/packages/PackageInstaller/res/values-am/strings.xml
+++ b/packages/PackageInstaller/res/values-am/strings.xml
@@ -83,8 +83,7 @@
     <string name="app_name_unknown" msgid="6881210203354323926">"ያልታወቀ"</string>
     <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"ለእርስዎ ደህንነት ሲባል በአሁኑ ጊዜ ጡባዊዎ ከዚህ ምንጭ ያልታወቁ መተግበሪያዎችን እንዲጭን አይፈቀድለትም። ይህን በቅንብሮች ውስጥ መቀየር ይችላሉ።"</string>
     <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"ለእርስዎ ደህንነት ሲባል በአሁኑ ጊዜ የእርስዎ ቲቪ ከዚህ ምንጭ ያልታወቁ መተግበሪያዎችን እንዲጭን አይፈቀድለትም። ይህን በቅንብሮች ውስጥ መቀየር ይችላሉ።"</string>
-    <!-- no translation found for untrusted_external_source_warning (7195163388090818636) -->
-    <skip />
+    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"ለደህንነትዎ ሲባል በአሁኑ ጊዜ የእጅ ሰዓትዎ ያልታወቁ መተግበሪያዎችን ከዚህ ምንጭ እንዲጭን አይፈቀድለትም። ይህን በቅንብሮች ውስጥ መለወጥ ይችላሉ።"</string>
     <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"ለእርስዎ ደህንነት ሲባል በአሁኑ ጊዜ ስልክዎ ከዚህ ምንጭ ያልታወቁ መተግበሪያዎችን እንዲጭን አልተፈቀደለትም። ይህን በቅንብሮች ውስጥ መቀየር ይችላሉ።"</string>
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"የእርስዎ ስልክ እና የግል ውሂብ በማይታወቁ መተግበሪያዎች ለሚደርሱ ጥቃቶች በይልበልጥ ተጋላጭ ናቸው። ይህን መተግበሪያ በመጫንዎ በእርስዎ ስልክ ላይ ለሚደርስ ማናቸውም ጉዳት ወይም መተግበሪያውን በመጠቀም ለሚከሰት የውሂብ መጥፋት ኃላፊነቱን እንደሚወስዱ ተስማምተዋል።"</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"የእርስዎ ጡባዊ እና የግል ውሂብ በማይታወቁ መተግበሪያዎች ለሚደርሱ ጥቃቶች በይበልጥ ተጋላጭ ናቸው። ይህን መተግበሪያ በመጫንዎ በእርስዎ ጡባዊ ላይ ለሚደርስ ማናቸውም ጉዳት ወይም መተግበሪያውን በመጠቀም ለሚከሰት የውሂብ መጥፋት ኃላፊነቱን እንደሚወስዱ ተስማምተዋል።"</string>
diff --git a/packages/PackageInstaller/res/values-lv/strings.xml b/packages/PackageInstaller/res/values-lv/strings.xml
index 82d3013..f765ba9 100644
--- a/packages/PackageInstaller/res/values-lv/strings.xml
+++ b/packages/PackageInstaller/res/values-lv/strings.xml
@@ -83,8 +83,7 @@
     <string name="app_name_unknown" msgid="6881210203354323926">"Nezināma"</string>
     <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"Drošības apsvērumu dēļ jūsu planšetdatorā pašlaik nav atļauts instalēt nezināmas lietotnes no šī avota. Jūs varat to mainīt iestatījumos."</string>
     <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"Drošības apsvērumu dēļ jūsu televizorā pašlaik nav atļauts instalēt nezināmas lietotnes no šī avota. Jūs varat to mainīt iestatījumos."</string>
-    <!-- no translation found for untrusted_external_source_warning (7195163388090818636) -->
-    <skip />
+    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"Drošības apsvērumu dēļ jūsu pulkstenī pašlaik nav atļauts instalēt nezināmas lietotnes no šī avota. Šo atļauju varat mainīt iestatījumos."</string>
     <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"Drošības apsvērumu dēļ jūsu tālrunī pašlaik nav atļauts instalēt nezināmas lietotnes no šī avota. Jūs varat to mainīt iestatījumos."</string>
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"Jūsu tālrunis un personas dati ir neaizsargātāki pret uzbrukumiem no nezināmām lietotnēm. Instalējot šo lietotni, jūs piekrītat, ka esat atbildīgs par tālruņa bojājumiem vai datu zudumu, kas var rasties lietotnes dēļ."</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"Jūsu planšetdators un personas dati ir neaizsargātāki pret uzbrukumiem no nezināmām lietotnēm. Instalējot šo lietotni, jūs piekrītat, ka esat atbildīgs par planšetdatora bojājumiem vai datu zudumu, kas var rasties lietotnes dēļ."</string>
diff --git a/packages/PackageInstaller/res/values-zh-rHK/strings.xml b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
index 9535153..dcad49c 100644
--- a/packages/PackageInstaller/res/values-zh-rHK/strings.xml
+++ b/packages/PackageInstaller/res/values-zh-rHK/strings.xml
@@ -83,7 +83,7 @@
     <string name="app_name_unknown" msgid="6881210203354323926">"不明"</string>
     <string name="untrusted_external_source_warning" product="tablet" msgid="7067510047443133095">"為安全起見,您的平板電腦目前不得安裝此來源的不明應用程式。您可以在「設定」中變更這項設定。"</string>
     <string name="untrusted_external_source_warning" product="tv" msgid="7057271609532508035">"為安全起見,您的電視目前不得安裝此來源的不明應用程式。您可以在「設定」中變更這項設定。"</string>
-    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"為了安全起見,你的智慧手錶目前禁止安裝這個來源的不明應用程式。如要變更,請前往「設定」。"</string>
+    <string name="untrusted_external_source_warning" product="watch" msgid="7195163388090818636">"為安全起見,您的手錶目前不得安裝此來源的不明應用程式。您可以在「設定」中變更這項設定。"</string>
     <string name="untrusted_external_source_warning" product="default" msgid="8444191224459138919">"為安全起見,您的手機目前不得安裝此來源的不明應用程式。您可以在「設定」中變更這項設定。"</string>
     <string name="anonymous_source_warning" product="default" msgid="2784902545920822500">"來源不明的應用程式可能會侵害您的手機和個人資料。安裝此應用程式,即表示您同意承擔因使用這個應用程式而導致手機損壞或資料遺失的責任。"</string>
     <string name="anonymous_source_warning" product="tablet" msgid="3939101621438855516">"來源不明的應用程式可能會侵害您的平板電腦和個人資料。安裝此應用程式,即表示您同意承擔因使用這個應用程式而導致平板電腦損壞或資料遺失的責任。"</string>
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
index e4bdab8..88c1036 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/InstallStart.java
@@ -28,7 +28,6 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
-import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
@@ -104,10 +103,9 @@
                 Intent.EXTRA_INSTALLER_PACKAGE_NAME);
         if (installerPackageNameFromIntent != null) {
             final String callingPkgName = getLaunchedFromPackage();
-            if (installerPackageNameFromIntent.length() >= SessionParams.MAX_PACKAGE_NAME_LENGTH
-                    || (!TextUtils.equals(installerPackageNameFromIntent, callingPkgName)
+            if (!TextUtils.equals(installerPackageNameFromIntent, callingPkgName)
                     && mPackageManager.checkPermission(Manifest.permission.INSTALL_PACKAGES,
-                    callingPkgName) != PackageManager.PERMISSION_GRANTED)) {
+                    callingPkgName) != PackageManager.PERMISSION_GRANTED) {
                 Log.e(LOG_TAG, "The given installer package name " + installerPackageNameFromIntent
                         + " is invalid. Remove it.");
                 EventLog.writeEvent(0x534e4554, "236687884", getLaunchedFromUid(),
diff --git a/packages/SettingsLib/FooterPreference/Android.bp b/packages/SettingsLib/FooterPreference/Android.bp
index 0929706..bcedf50 100644
--- a/packages/SettingsLib/FooterPreference/Android.bp
+++ b/packages/SettingsLib/FooterPreference/Android.bp
@@ -23,5 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index dd29827..372a276 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -25,5 +25,6 @@
         "//apex_available:platform",
         "com.android.adservices",
         "com.android.cellbroadcast",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
index a051ffe..37d6b42 100644
--- a/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
+++ b/packages/SettingsLib/Spa/gallery/AndroidManifest.xml
@@ -36,13 +36,13 @@
         </activity>
 
         <provider
-            android:name="com.android.settingslib.spa.framework.SpaSearchProvider"
+            android:name="com.android.settingslib.spa.search.SpaSearchProvider"
             android:authorities="com.android.spa.gallery.search.provider"
             android:enabled="true"
             android:exported="false">
         </provider>
 
-        <provider android:name="com.android.settingslib.spa.framework.SpaSliceProvider"
+        <provider android:name="com.android.settingslib.spa.slice.SpaSliceProvider"
             android:authorities="com.android.spa.gallery.slice.provider"
             android:exported="true" >
             <intent-filter>
@@ -52,7 +52,7 @@
         </provider>
 
         <receiver
-            android:name="com.android.settingslib.spa.framework.SpaSliceBroadcastReceiver"
+            android:name="com.android.settingslib.spa.slice.SpaSliceBroadcastReceiver"
             android:exported="false">
         </receiver>
 
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
index 6d20c91..db49909 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/GallerySpaEnvironment.kt
@@ -17,7 +17,6 @@
 package com.android.settingslib.spa.gallery
 
 import android.content.Context
-import com.android.settingslib.spa.framework.SpaSliceBroadcastReceiver
 import com.android.settingslib.spa.framework.common.LocalLogger
 import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
 import com.android.settingslib.spa.framework.common.SpaEnvironment
@@ -29,6 +28,7 @@
 import com.android.settingslib.spa.gallery.page.ChartPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
 import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
+import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
 import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider
 import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
 import com.android.settingslib.spa.gallery.page.SliderPageProvider
@@ -39,6 +39,7 @@
 import com.android.settingslib.spa.gallery.preference.TwoTargetSwitchPreferencePageProvider
 import com.android.settingslib.spa.gallery.ui.CategoryPageProvider
 import com.android.settingslib.spa.gallery.ui.SpinnerPageProvider
+import com.android.settingslib.spa.slice.SpaSliceBroadcastReceiver
 
 /**
  * Enum to define all SPP name here.
@@ -72,6 +73,7 @@
                 CategoryPageProvider,
                 ActionButtonPageProvider,
                 ProgressBarPageProvider,
+                LoadingBarPageProvider,
                 ChartPageProvider,
                 AlterDialogPageProvider,
             ),
@@ -81,9 +83,12 @@
         )
     }
 
+    override val logger = LocalLogger()
+
     override val browseActivityClass = GalleryMainActivity::class.java
     override val sliceBroadcastReceiverClass = SpaSliceBroadcastReceiver::class.java
+
+    // For debugging
     override val searchProviderAuthorities = "com.android.spa.gallery.search.provider"
     override val sliceProviderAuthorities = "com.android.spa.gallery.slice.provider"
-    override val logger = LocalLogger()
 }
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/button/ActionButtonsPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/button/ActionButtonsPage.kt
index 96e2498..decc292 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/button/ActionButtonsPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/button/ActionButtonsPage.kt
@@ -46,7 +46,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/AlterDialogPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/AlterDialogPage.kt
index a57df0f..063b61c 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/AlterDialogPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/dialog/AlterDialogPage.kt
@@ -50,7 +50,6 @@
     )
 
     fun buildInjectEntry() = SettingsEntryBuilder.createInject(owner)
-        .setIsAllowSearch(true)
         .setUiLayoutFn {
             Preference(object : PreferenceModel {
                 override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
index 6d53dae..5d26b34 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/home/HomePage.kt
@@ -33,6 +33,7 @@
 import com.android.settingslib.spa.gallery.page.ChartPageProvider
 import com.android.settingslib.spa.gallery.page.FooterPageProvider
 import com.android.settingslib.spa.gallery.page.IllustrationPageProvider
+import com.android.settingslib.spa.gallery.page.LoadingBarPageProvider
 import com.android.settingslib.spa.gallery.page.ProgressBarPageProvider
 import com.android.settingslib.spa.gallery.page.SettingsPagerPageProvider
 import com.android.settingslib.spa.gallery.page.SliderPageProvider
@@ -58,6 +59,7 @@
             CategoryPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             ActionButtonPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             ProgressBarPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
+            LoadingBarPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             ChartPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
             AlterDialogPageProvider.buildInjectEntry().setLink(fromPage = owner).build(),
         )
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
index 7958d11..42ac1ac 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ArgumentPage.kt
@@ -55,7 +55,6 @@
         entryList.add(
             createEntry(owner, EntryEnum.STRING_PARAM)
                 // Set attributes
-                .setIsAllowSearch(true)
                 .setIsSearchDataDynamic(true)
                 .setSearchDataFn { ArgumentPageModel.genStringParamSearchData() }
                 .setUiLayoutFn {
@@ -67,7 +66,6 @@
         entryList.add(
             createEntry(owner, EntryEnum.INT_PARAM)
                 // Set attributes
-                .setIsAllowSearch(true)
                 .setIsSearchDataDynamic(true)
                 .setSearchDataFn { ArgumentPageModel.genIntParamSearchData() }
                 .setUiLayoutFn {
@@ -90,8 +88,6 @@
             owner = createSettingsPage(arguments),
             displayName = "${name}_$stringParam",
         )
-            // Set attributes
-            .setIsAllowSearch(false)
             .setSearchDataFn { ArgumentPageModel.genInjectSearchData() }
             .setUiLayoutFn {
                 // Set ui rendering
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
index 160e77b..7f21a4d 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ChartPage.kt
@@ -134,7 +134,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
index c903cfd..9f24ea9 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/FooterPage.kt
@@ -20,6 +20,7 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import androidx.compose.ui.tooling.preview.Preview
+import com.android.settingslib.spa.framework.common.EntrySearchData
 import com.android.settingslib.spa.framework.common.SettingsEntry
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPage
@@ -42,7 +43,7 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             SettingsEntryBuilder.create( "Some Preference", owner)
-                .setIsAllowSearch(true)
+                .setSearchDataFn { EntrySearchData(title = "Some Preference") }
                 .setUiLayoutFn {
                     Preference(remember {
                         object : PreferenceModel {
@@ -58,7 +59,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
index e10cf3a..44f0343 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/IllustrationPage.kt
@@ -26,9 +26,9 @@
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.theme.SettingsTheme
 import com.android.settingslib.spa.gallery.R
-import com.android.settingslib.spa.widget.Illustration
-import com.android.settingslib.spa.widget.IllustrationModel
-import com.android.settingslib.spa.widget.ResourceType
+import com.android.settingslib.spa.widget.illustration.Illustration
+import com.android.settingslib.spa.widget.illustration.IllustrationModel
+import com.android.settingslib.spa.widget.illustration.ResourceType
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 
@@ -72,7 +72,6 @@
 
      fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/LoadingBarPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/LoadingBarPage.kt
new file mode 100644
index 0000000..4332a81
--- /dev/null
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/LoadingBarPage.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.gallery.page
+
+import android.os.Bundle
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Button
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.unit.dp
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.compose.navigator
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.widget.preference.Preference
+import com.android.settingslib.spa.widget.preference.PreferenceModel
+import com.android.settingslib.spa.widget.scaffold.RegularScaffold
+import com.android.settingslib.spa.widget.ui.CircularLoadingBar
+import com.android.settingslib.spa.widget.ui.LinearLoadingBar
+
+private const val TITLE = "Sample LoadingBar"
+
+object LoadingBarPageProvider : SettingsPageProvider {
+    override val name = "LoadingBar"
+
+    fun buildInjectEntry(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
+            .setUiLayoutFn {
+                Preference(object : PreferenceModel {
+                    override val title = TITLE
+                    override val onClick = navigator(name)
+                })
+            }
+    }
+
+    override fun getTitle(arguments: Bundle?): String {
+        return TITLE
+    }
+
+    @Composable
+    override fun Page(arguments: Bundle?) {
+        var loading by remember { mutableStateOf(true) }
+        RegularScaffold(title = getTitle(arguments)) {
+            Button(
+                onClick = { loading = !loading },
+                modifier = Modifier.padding(start = 20.dp)
+            ) {
+                if (loading) {
+                    Text(text = "Stop")
+                } else {
+                    Text(text = "Resume")
+                }
+            }
+        }
+
+        LinearLoadingBar(isLoading = loading, yOffset = 104.dp)
+        CircularLoadingBar(isLoading = loading)
+    }
+}
+
+@Preview(showBackground = true)
+@Composable
+private fun LoadingBarPagePreview() {
+    SettingsTheme {
+        LoadingBarPageProvider.Page(null)
+    }
+}
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
index 9136b04..20d90dd 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/ProgressBarPage.kt
@@ -27,7 +27,6 @@
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.setValue
 import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
 import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
 import com.android.settingslib.spa.framework.common.SettingsPage
 import com.android.settingslib.spa.framework.common.SettingsPageProvider
@@ -39,9 +38,7 @@
 import com.android.settingslib.spa.widget.preference.ProgressBarPreferenceModel
 import com.android.settingslib.spa.widget.preference.ProgressBarWithDataPreference
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
-import com.android.settingslib.spa.widget.ui.CircularLoadingBar
 import com.android.settingslib.spa.widget.ui.CircularProgressBar
-import com.android.settingslib.spa.widget.ui.LinearLoadingBar
 import kotlinx.coroutines.delay
 
 private const val TITLE = "Sample ProgressBar"
@@ -51,7 +48,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
@@ -66,18 +62,10 @@
 
     @Composable
     override fun Page(arguments: Bundle?) {
-        // Mocks a loading time of 2 seconds.
-        var loading by remember { mutableStateOf(true) }
-        LaunchedEffect(Unit) {
-            delay(2000)
-            loading = false
-        }
-
         RegularScaffold(title = getTitle(arguments)) {
             // Auto update the progress and finally jump tp 0.4f.
             var progress by remember { mutableStateOf(0f) }
             LaunchedEffect(Unit) {
-                delay(2000)
                 while (progress < 1f) {
                     delay(100)
                     progress += 0.01f
@@ -86,19 +74,11 @@
                 progress = 0.4f
             }
 
-            // Show as a placeholder for progress bar
             LargeProgressBar(progress)
-            // The remaining information only shows after loading complete.
-            if (!loading) {
-                SimpleProgressBar()
-                ProgressBarWithData()
-                CircularProgressBar(progress = progress, radius = 160f)
-            }
+            SimpleProgressBar()
+            ProgressBarWithData()
+            CircularProgressBar(progress = progress, radius = 160f)
         }
-
-        // Add loading bar examples, running for 2 seconds.
-        LinearLoadingBar(isLoading = loading, yOffset = 64.dp)
-        CircularLoadingBar(isLoading = loading)
     }
 }
 
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
index cb58a95..c0d0abc 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SettingsPagerPage.kt
@@ -40,7 +40,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
index 73b34a5..a62ec7b 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/page/SliderPage.kt
@@ -48,7 +48,6 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             SettingsEntryBuilder.create("Simple Slider", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SliderPreference(object : SliderPreferenceModel {
                         override val title = "Simple Slider"
@@ -58,7 +57,6 @@
         )
         entryList.add(
             SettingsEntryBuilder.create("Slider with icon", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SliderPreference(object : SliderPreferenceModel {
                         override val title = "Slider with icon"
@@ -72,7 +70,6 @@
         )
         entryList.add(
             SettingsEntryBuilder.create("Slider with changeable icon", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     val initValue = 0
                     var icon by remember { mutableStateOf(Icons.Outlined.MusicOff) }
@@ -93,7 +90,6 @@
         )
         entryList.add(
             SettingsEntryBuilder.create("Slider with steps", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SliderPreference(object : SliderPreferenceModel {
                         override val title = "Slider with steps"
@@ -109,7 +105,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
index f38a8d4..67e35dc 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/MainSwitchPreferencePage.kt
@@ -44,14 +44,12 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             SettingsEntryBuilder.create( "MainSwitchPreference", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleMainSwitchPreference()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "MainSwitchPreference not changeable", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleNotChangeableMainSwitchPreference()
                 }.build()
@@ -62,7 +60,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
index 61925a7..eddede7 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferenceMain.kt
@@ -43,7 +43,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = owner)
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
index ff89f2b..238204a 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/PreferencePage.kt
@@ -36,6 +36,7 @@
 import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.util.createIntent
 import com.android.settingslib.spa.gallery.R
 import com.android.settingslib.spa.gallery.SettingsPageProviderEnum
 import com.android.settingslib.spa.gallery.preference.PreferencePageModel.Companion.ASYNC_PREFERENCE_SUMMARY
@@ -87,16 +88,15 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             createEntry(EntryEnum.SIMPLE_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setMacro {
                     spaLogger.message(TAG, "create macro for ${EntryEnum.SIMPLE_PREFERENCE}")
                     SimplePreferenceMacro(title = SIMPLE_PREFERENCE_TITLE)
                 }
+                .setStatusDataFn { EntryStatusData(isDisabled = false) }
                 .build()
         )
         entryList.add(
             createEntry(EntryEnum.SUMMARY_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setMacro {
                     spaLogger.message(TAG, "create macro for ${EntryEnum.SUMMARY_PREFERENCE}")
                     SimplePreferenceMacro(
@@ -105,12 +105,12 @@
                         searchKeywords = SIMPLE_PREFERENCE_KEYWORDS,
                     )
                 }
+                .setStatusDataFn { EntryStatusData(isDisabled = true) }
                 .build()
         )
         entryList.add(singleLineSummaryEntry())
         entryList.add(
             createEntry(EntryEnum.DISABLED_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setHasMutableStatus(true)
                 .setMacro {
                     spaLogger.message(TAG, "create macro for ${EntryEnum.DISABLED_PREFERENCE}")
@@ -126,7 +126,6 @@
         )
         entryList.add(
             createEntry(EntryEnum.ASYNC_SUMMARY_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setHasMutableStatus(true)
                 .setSearchDataFn {
                     EntrySearchData(title = ASYNC_PREFERENCE_TITLE)
@@ -165,7 +164,6 @@
         )
         entryList.add(
             createEntry(EntryEnum.MANUAL_UPDATE_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     val model = PreferencePageModel.create()
                     val manualUpdaterSummary = remember { model.getManualUpdaterSummary() }
@@ -179,7 +177,8 @@
                             }
                         }
                     )
-                }.setSliceDataFn { sliceUri, args ->
+                }
+                .setSliceDataFn { sliceUri, args ->
                     val createSliceImpl = { v: Int ->
                         createDemoActionSlice(
                             sliceUri = sliceUri,
@@ -204,7 +203,6 @@
         )
         entryList.add(
             createEntry(EntryEnum.AUTO_UPDATE_PREFERENCE)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     val model = PreferencePageModel.create()
                     val autoUpdaterSummary = remember { model.getAutoUpdaterSummary() }
@@ -251,7 +249,6 @@
     }
 
     private fun singleLineSummaryEntry() = createEntry(EntryEnum.SINGLE_LINE_SUMMARY_PREFERENCE)
-        .setIsAllowSearch(true)
         .setUiLayoutFn {
             Preference(
                 model = object : PreferenceModel {
@@ -267,7 +264,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = owner)
-            .setIsAllowSearch(true)
             .setMacro {
                 spaLogger.message(TAG, "create macro for INJECT entry")
                 SimplePreferenceMacro(
@@ -276,7 +272,7 @@
                 )
             }
             .setSliceDataFn { sliceUri, _ ->
-                val intent = owner.createBrowseIntent()?.createBrowsePendingIntent()
+                val intent = owner.createIntent()?.createBrowsePendingIntent()
                     ?: return@setSliceDataFn null
                 return@setSliceDataFn object : EntrySliceData() {
                     init {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
index 367766a..067911c 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/SwitchPreferencePage.kt
@@ -17,6 +17,8 @@
 package com.android.settingslib.spa.gallery.preference
 
 import android.os.Bundle
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AirplanemodeActive
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.produceState
@@ -34,6 +36,7 @@
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spa.widget.ui.SettingsIcon
 import kotlinx.coroutines.delay
 
 private const val TITLE = "Sample SwitchPreference"
@@ -46,39 +49,40 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             SettingsEntryBuilder.create( "SwitchPreference", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleSwitchPreference()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "SwitchPreference with summary", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleSwitchPreferenceWithSummary()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "SwitchPreference with async summary", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleSwitchPreferenceWithAsyncSummary()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "SwitchPreference not changeable", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleNotChangeableSwitchPreference()
                 }.build()
         )
+        entryList.add(
+            SettingsEntryBuilder.create( "SwitchPreference with icon", owner)
+                .setUiLayoutFn {
+                    SampleSwitchPreferenceWithIcon()
+                }.build()
+        )
 
         return entryList
     }
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
@@ -148,6 +152,21 @@
     })
 }
 
+@Composable
+private fun SampleSwitchPreferenceWithIcon() {
+    val checked = rememberSaveable { mutableStateOf(true) }
+    SwitchPreference(remember {
+        object : SwitchPreferenceModel {
+            override val title = "SwitchPreference"
+            override val checked = checked
+            override val onCheckedChange = { newChecked: Boolean -> checked.value = newChecked }
+            override val icon = @Composable {
+                SettingsIcon(imageVector = Icons.Outlined.AirplanemodeActive)
+            }
+        }
+    })
+}
+
 @Preview(showBackground = true)
 @Composable
 private fun SwitchPreferencePagePreview() {
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
index 22da99c..33e5e8d 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/preference/TwoTargetSwitchPreferencePage.kt
@@ -46,28 +46,24 @@
         val entryList = mutableListOf<SettingsEntry>()
         entryList.add(
             SettingsEntryBuilder.create( "TwoTargetSwitchPreference", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleTwoTargetSwitchPreference()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "TwoTargetSwitchPreference with summary", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleTwoTargetSwitchPreferenceWithSummary()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "TwoTargetSwitchPreference with async summary", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleTwoTargetSwitchPreferenceWithAsyncSummary()
                 }.build()
         )
         entryList.add(
             SettingsEntryBuilder.create( "TwoTargetSwitchPreference not changeable", owner)
-                .setIsAllowSearch(true)
                 .setUiLayoutFn {
                     SampleNotChangeableTwoTargetSwitchPreference()
                 }.build()
@@ -78,7 +74,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
index d87cbe8..cb58abf6 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/CategoryPage.kt
@@ -39,7 +39,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
index ec2f436..ba769d2 100644
--- a/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
+++ b/packages/SettingsLib/Spa/gallery/src/com/android/settingslib/spa/gallery/ui/SpinnerPage.kt
@@ -40,7 +40,6 @@
 
     fun buildInjectEntry(): SettingsEntryBuilder {
         return SettingsEntryBuilder.createInject(owner = SettingsPage.create(name))
-            .setIsAllowSearch(true)
             .setUiLayoutFn {
                 Preference(object : PreferenceModel {
                     override val title = TITLE
diff --git a/packages/SettingsLib/Spa/spa/Android.bp b/packages/SettingsLib/Spa/spa/Android.bp
index eb7aaa7..3ea3b5c 100644
--- a/packages/SettingsLib/Spa/spa/Android.bp
+++ b/packages/SettingsLib/Spa/spa/Android.bp
@@ -33,6 +33,7 @@
         "androidx.compose.runtime_runtime-livedata",
         "androidx.compose.ui_ui-tooling-preview",
         "androidx.lifecycle_lifecycle-livedata-ktx",
+        "androidx.lifecycle_lifecycle-runtime-compose",
         "androidx.navigation_navigation-compose",
         "com.google.android.material_material",
         "lottie_compose",
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
index 238268a..f7cbdae 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugActivity.kt
@@ -39,7 +39,10 @@
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.slice.appendSliceParams
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.android.settingslib.spa.framework.util.createIntent
+import com.android.settingslib.spa.slice.fromEntry
 import com.android.settingslib.spa.slice.presenter.SliceDemo
 import com.android.settingslib.spa.widget.preference.Preference
 import com.android.settingslib.spa.widget.preference.PreferenceModel
@@ -158,14 +161,13 @@
             remember { entryRepository.getAllEntries().filter { it.hasSliceSupport } }
         RegularScaffold(title = "All Slices (${allSliceEntry.size})") {
             for (entry in allSliceEntry) {
-                SliceDemo(sliceUri = entry.createSliceUri(authority))
+                SliceDemo(sliceUri = Uri.Builder().fromEntry(entry, authority).build())
             }
         }
     }
 
     @Composable
     fun OnePage(arguments: Bundle?) {
-        val context = LocalContext.current
         val entryRepository by spaEnvironment.entryRepository
         val id = arguments!!.getString(PARAM_NAME_PAGE_ID, "")
         val pageWithEntry = entryRepository.getPageWithEntry(id)!!
@@ -176,8 +178,8 @@
             Text(text = "Entry size: ${pageWithEntry.entries.size}")
             Preference(model = object : PreferenceModel {
                 override val title = "open page"
-                override val enabled =
-                    page.isBrowsable(context, spaEnvironment.browseActivityClass).toState()
+                override val enabled = (spaEnvironment.browseActivityClass != null &&
+                    page.isBrowsable()).toState()
                 override val onClick = openPage(page)
             })
             EntryList(pageWithEntry.entries)
@@ -186,7 +188,6 @@
 
     @Composable
     fun OneEntry(arguments: Bundle?) {
-        val context = LocalContext.current
         val entryRepository by spaEnvironment.entryRepository
         val id = arguments!!.getString(PARAM_NAME_ENTRY_ID, "")
         val entry = entryRepository.getEntry(id)!!
@@ -194,9 +195,9 @@
         RegularScaffold(title = "Entry - ${entry.debugBrief()}") {
             Preference(model = object : PreferenceModel {
                 override val title = "open entry"
-                override val enabled =
-                    entry.containerPage().isBrowsable(context, spaEnvironment.browseActivityClass)
-                        .toState()
+                override val enabled = (spaEnvironment.browseActivityClass != null &&
+                    entry.containerPage().isBrowsable())
+                    .toState()
                 override val onClick = openEntry(entry)
             })
             Text(text = entryContent)
@@ -219,7 +220,7 @@
     private fun openPage(page: SettingsPage): (() -> Unit)? {
         val context = LocalContext.current
         val intent =
-            page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: return null
+            page.createIntent(SESSION_BROWSE) ?: return null
         val route = page.buildRoute()
         return {
             spaEnvironment.logger.message(
@@ -232,8 +233,7 @@
     @Composable
     private fun openEntry(entry: SettingsEntry): (() -> Unit)? {
         val context = LocalContext.current
-        val intent = entry.containerPage()
-            .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
+        val intent = entry.createIntent(SESSION_SEARCH)
             ?: return null
         val route = entry.containerPage().buildRoute()
         return {
@@ -245,18 +245,6 @@
     }
 }
 
-private fun SettingsEntry.createSliceUri(
-    authority: String?,
-    runtimeArguments: Bundle? = null
-): Uri {
-    if (authority == null) return Uri.EMPTY
-    return Uri.Builder().scheme("content").authority(authority).appendSliceParams(
-        route = this.containerPage().buildRoute(),
-        entryId = this.id,
-        runtimeArguments = runtimeArguments,
-    ).build()
-}
-
 /**
  * A blank activity without any page.
  */
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
index 3df7727..59ec985 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/debug/DebugProvider.kt
@@ -32,6 +32,12 @@
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
 import com.android.settingslib.spa.framework.common.addUri
 import com.android.settingslib.spa.framework.common.getColumns
+import com.android.settingslib.spa.framework.util.KEY_DESTINATION
+import com.android.settingslib.spa.framework.util.KEY_HIGHLIGHT_ENTRY
+import com.android.settingslib.spa.framework.util.KEY_SESSION_SOURCE_NAME
+import com.android.settingslib.spa.framework.util.SESSION_BROWSE
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.android.settingslib.spa.framework.util.createIntent
 
 private const val TAG = "DebugProvider"
 
@@ -116,9 +122,11 @@
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.PAGE_DEBUG_QUERY.getColumns())
         for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
-            val command = pageWithEntry.page.createBrowseAdbCommand(
-                context,
-                spaEnvironment.browseActivityClass
+            val page = pageWithEntry.page
+            if (!page.isBrowsable()) continue
+            val command = createBrowseAdbCommand(
+                destination = page.buildRoute(),
+                sessionName = SESSION_BROWSE
             )
             if (command != null) {
                 cursor.newRow().add(ColumnEnum.PAGE_START_ADB.id, command)
@@ -131,8 +139,13 @@
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.ENTRY_DEBUG_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
-            val command = entry.containerPage()
-                .createBrowseAdbCommand(context, spaEnvironment.browseActivityClass, entry.id)
+            val page = entry.containerPage()
+            if (!page.isBrowsable()) continue
+            val command = createBrowseAdbCommand(
+                destination = page.buildRoute(),
+                entryId = entry.id,
+                sessionName = SESSION_SEARCH
+            )
             if (command != null) {
                 cursor.newRow().add(ColumnEnum.ENTRY_START_ADB.id, command)
             }
@@ -145,8 +158,7 @@
         val cursor = MatrixCursor(QueryEnum.PAGE_INFO_QUERY.getColumns())
         for (pageWithEntry in entryRepository.getAllPageWithEntry()) {
             val page = pageWithEntry.page
-            val intent =
-                page.createBrowseIntent(context, spaEnvironment.browseActivityClass) ?: Intent()
+            val intent = page.createIntent(SESSION_BROWSE) ?: Intent()
             cursor.newRow()
                 .add(ColumnEnum.PAGE_ID.id, page.id)
                 .add(ColumnEnum.PAGE_NAME.id, page.displayName)
@@ -162,17 +174,36 @@
         val entryRepository by spaEnvironment.entryRepository
         val cursor = MatrixCursor(QueryEnum.ENTRY_INFO_QUERY.getColumns())
         for (entry in entryRepository.getAllEntries()) {
-            val intent = entry.containerPage()
-                .createBrowseIntent(context, spaEnvironment.browseActivityClass, entry.id)
-                ?: Intent()
+            val intent = entry.createIntent(SESSION_SEARCH) ?: Intent()
             cursor.newRow()
                 .add(ColumnEnum.ENTRY_ID.id, entry.id)
                 .add(ColumnEnum.ENTRY_NAME.id, entry.displayName)
                 .add(ColumnEnum.ENTRY_ROUTE.id, entry.containerPage().buildRoute())
                 .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(URI_INTENT_SCHEME))
-                .add(ColumnEnum.ENTRY_HIERARCHY_PATH.id,
-                    entryRepository.getEntryPathWithDisplayName(entry.id))
+                .add(
+                    ColumnEnum.ENTRY_HIERARCHY_PATH.id,
+                    entryRepository.getEntryPathWithDisplayName(entry.id)
+                )
         }
         return cursor
     }
 }
+
+private fun createBrowseAdbCommand(
+    destination: String? = null,
+    entryId: String? = null,
+    sessionName: String? = null,
+): String? {
+    val context = SpaEnvironmentFactory.instance.appContext
+    val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null
+    val packageName = context.packageName
+    val activityName = browseActivityClass.name.replace(packageName, "")
+    val destinationParam =
+        if (destination != null) " -e $KEY_DESTINATION $destination" else ""
+    val highlightParam =
+        if (entryId != null) " -e $KEY_HIGHLIGHT_ENTRY $entryId" else ""
+    val sessionParam =
+        if (sessionName != null) " -e $KEY_SESSION_SOURCE_NAME $sessionName" else ""
+    return "adb shell am start -n $packageName/$activityName" +
+        "$destinationParam$highlightParam$sessionParam"
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
index c3c90ab..aa10cc8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/BrowseActivity.kt
@@ -16,20 +16,17 @@
 
 package com.android.settingslib.spa.framework
 
+import android.content.Intent
 import android.os.Bundle
 import androidx.activity.ComponentActivity
 import androidx.activity.compose.setContent
+import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
 import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.ui.platform.LocalLifecycleOwner
 import androidx.core.view.WindowCompat
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleEventObserver
 import androidx.navigation.NavGraph.Companion.findStartDestination
 import androidx.navigation.compose.NavHost
 import androidx.navigation.compose.composable
@@ -37,12 +34,17 @@
 import com.android.settingslib.spa.R
 import com.android.settingslib.spa.framework.common.LogCategory
 import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
-import com.android.settingslib.spa.framework.common.createSettingsPage
 import com.android.settingslib.spa.framework.compose.LocalNavController
 import com.android.settingslib.spa.framework.compose.NavControllerWrapperImpl
 import com.android.settingslib.spa.framework.compose.localNavController
 import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.util.PageEvent
+import com.android.settingslib.spa.framework.util.getDestination
+import com.android.settingslib.spa.framework.util.getEntryId
+import com.android.settingslib.spa.framework.util.getSessionName
 import com.android.settingslib.spa.framework.util.navRoute
 
 private const val TAG = "BrowseActivity"
@@ -74,86 +76,65 @@
 
         setContent {
             SettingsTheme {
-                MainContent()
+                val sppRepository by spaEnvironment.pageProviderRepository
+                BrowseContent(sppRepository, intent)
             }
         }
     }
+}
 
-    @Composable
-    private fun MainContent() {
-        val sppRepository by spaEnvironment.pageProviderRepository
-        val navController = rememberNavController()
-        val nullPage = SettingsPage.createNull()
-        CompositionLocalProvider(navController.localNavController()) {
-            NavHost(
-                navController = navController,
-                startDestination = nullPage.sppName,
-            ) {
-                composable(nullPage.sppName) {}
-                for (spp in sppRepository.getAllProviders()) {
-                    composable(
-                        route = spp.name + spp.parameter.navRoute(),
-                        arguments = spp.parameter,
-                    ) { navBackStackEntry ->
-                        PageLogger(remember(navBackStackEntry.arguments) {
-                            spp.createSettingsPage(arguments = navBackStackEntry.arguments)
-                        })
-
-                        spp.Page(navBackStackEntry.arguments)
-                    }
-                }
-            }
-            InitialDestinationNavigator()
-        }
-    }
-
-    @Composable
-    private fun PageLogger(settingsPage: SettingsPage) {
-        val lifecycleOwner = LocalLifecycleOwner.current
-        DisposableEffect(lifecycleOwner) {
-            val observer = LifecycleEventObserver { _, event ->
-                if (event == Lifecycle.Event.ON_START) {
-                    settingsPage.enterPage()
-                } else if (event == Lifecycle.Event.ON_STOP) {
-                    settingsPage.leavePage()
-                }
-            }
-
-            // Add the observer to the lifecycle
-            lifecycleOwner.lifecycle.addObserver(observer)
-
-            // When the effect leaves the Composition, remove the observer
-            onDispose {
-                lifecycleOwner.lifecycle.removeObserver(observer)
-            }
-        }
-    }
-
-    @Composable
-    private fun InitialDestinationNavigator() {
-        val sppRepository by spaEnvironment.pageProviderRepository
-        val destinationNavigated = rememberSaveable { mutableStateOf(false) }
-        if (destinationNavigated.value) return
-        destinationNavigated.value = true
+@VisibleForTesting
+@Composable
+fun BrowseContent(sppRepository: SettingsPageProviderRepository, initialIntent: Intent? = null) {
+    val navController = rememberNavController()
+    CompositionLocalProvider(navController.localNavController()) {
         val controller = LocalNavController.current as NavControllerWrapperImpl
-        LaunchedEffect(Unit) {
-            val destination =
-                intent?.getStringExtra(KEY_DESTINATION) ?: sppRepository.getDefaultStartPage()
-            val highlightEntryId = intent?.getStringExtra(KEY_HIGHLIGHT_ENTRY)
-            if (destination.isNotEmpty()) {
-                controller.highlightId = highlightEntryId
-                val navController = controller.navController
-                navController.navigate(destination) {
-                    popUpTo(navController.graph.findStartDestination().id) {
-                        inclusive = true
-                    }
-                }
+        controller.NavContent(sppRepository.getAllProviders())
+        controller.InitialDestination(initialIntent, sppRepository.getDefaultStartPage())
+    }
+}
+
+@Composable
+private fun NavControllerWrapperImpl.NavContent(allProvider: Collection<SettingsPageProvider>) {
+    val nullPage = SettingsPage.createNull()
+    NavHost(
+        navController = navController,
+        startDestination = nullPage.sppName,
+    ) {
+        composable(nullPage.sppName) {}
+        for (spp in allProvider) {
+            composable(
+                route = spp.name + spp.parameter.navRoute(),
+                arguments = spp.parameter,
+            ) { navBackStackEntry ->
+                spp.PageEvent(navBackStackEntry.arguments)
+                spp.Page(navBackStackEntry.arguments)
             }
         }
     }
+}
 
-    companion object {
-        const val KEY_DESTINATION = "spaActivityDestination"
-        const val KEY_HIGHLIGHT_ENTRY = "highlightEntry"
+@Composable
+private fun NavControllerWrapperImpl.InitialDestination(
+    initialIntent: Intent?,
+    defaultDestination: String
+) {
+    val destinationNavigated = rememberSaveable { mutableStateOf(false) }
+    if (destinationNavigated.value) return
+    destinationNavigated.value = true
+
+    val initialDestination = initialIntent?.getDestination() ?: defaultDestination
+    if (initialDestination.isEmpty()) return
+    val initialEntryId = initialIntent?.getEntryId()
+    val sessionSourceName = initialIntent?.getSessionName()
+
+    LaunchedEffect(Unit) {
+        highlightId = initialEntryId
+        sessionName = sessionSourceName
+        navController.navigate(initialDestination) {
+            popUpTo(navController.graph.findStartDestination().id) {
+                inclusive = true
+            }
+        }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSearchProvider.kt
deleted file mode 100644
index 3689e4e..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSearchProvider.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework
-
-import android.content.ContentProvider
-import android.content.ContentValues
-import android.content.Context
-import android.content.Intent
-import android.content.UriMatcher
-import android.content.pm.ProviderInfo
-import android.database.Cursor
-import android.database.MatrixCursor
-import android.net.Uri
-import android.util.Log
-import com.android.settingslib.spa.framework.common.ColumnEnum
-import com.android.settingslib.spa.framework.common.QueryEnum
-import com.android.settingslib.spa.framework.common.SettingsEntry
-import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
-import com.android.settingslib.spa.framework.common.addUri
-import com.android.settingslib.spa.framework.common.getColumns
-
-private const val TAG = "SpaSearchProvider"
-
-/**
- * The content provider to return entry related data, which can be used for search and hierarchy.
- * One can query the provider result by:
- *   $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
- * For gallery, AuthorityPath = com.android.spa.gallery.provider
- * For Settings, AuthorityPath = com.android.settings.spa.provider
- * Some examples:
- *   $ adb shell content query --uri content://<AuthorityPath>/search_static
- *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic
- *   $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
- *   $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
- */
-class SpaSearchProvider : ContentProvider() {
-    private val spaEnvironment get() = SpaEnvironmentFactory.instance
-    private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
-
-    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
-        TODO("Implement this to handle requests to delete one or more rows")
-    }
-
-    override fun getType(uri: Uri): String? {
-        TODO(
-            "Implement this to handle requests for the MIME type of the data" +
-                "at the given URI"
-        )
-    }
-
-    override fun insert(uri: Uri, values: ContentValues?): Uri? {
-        TODO("Implement this to handle requests to insert a new row.")
-    }
-
-    override fun update(
-        uri: Uri,
-        values: ContentValues?,
-        selection: String?,
-        selectionArgs: Array<String>?
-    ): Int {
-        TODO("Implement this to handle requests to update one or more rows.")
-    }
-
-    override fun onCreate(): Boolean {
-        Log.d(TAG, "onCreate")
-        return true
-    }
-
-    override fun attachInfo(context: Context?, info: ProviderInfo?) {
-        if (info != null) {
-            QueryEnum.SEARCH_STATIC_DATA_QUERY.addUri(uriMatcher, info.authority)
-            QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.addUri(uriMatcher, info.authority)
-            QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
-            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
-        }
-        super.attachInfo(context, info)
-    }
-
-    override fun query(
-        uri: Uri,
-        projection: Array<String>?,
-        selection: String?,
-        selectionArgs: Array<String>?,
-        sortOrder: String?
-    ): Cursor? {
-        return try {
-            when (uriMatcher.match(uri)) {
-                QueryEnum.SEARCH_STATIC_DATA_QUERY.queryMatchCode -> querySearchStaticData()
-                QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.queryMatchCode -> querySearchDynamicData()
-                QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
-                    querySearchMutableStatusData()
-                QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
-                    querySearchImmutableStatusData()
-                else -> throw UnsupportedOperationException("Unknown Uri $uri")
-            }
-        } catch (e: UnsupportedOperationException) {
-            throw e
-        } catch (e: Exception) {
-            Log.e(TAG, "Provider querying exception:", e)
-            null
-        }
-    }
-
-    private fun querySearchImmutableStatusData(): Cursor {
-        val entryRepository by spaEnvironment.entryRepository
-        val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
-        for (entry in entryRepository.getAllEntries()) {
-            if (!entry.isAllowSearch || entry.hasMutableStatus) continue
-            fetchStatusData(entry, cursor)
-        }
-        return cursor
-    }
-
-    private fun querySearchMutableStatusData(): Cursor {
-        val entryRepository by spaEnvironment.entryRepository
-        val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
-        for (entry in entryRepository.getAllEntries()) {
-            if (!entry.isAllowSearch || !entry.hasMutableStatus) continue
-            fetchStatusData(entry, cursor)
-        }
-        return cursor
-    }
-
-    private fun querySearchStaticData(): Cursor {
-        val entryRepository by spaEnvironment.entryRepository
-        val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_DATA_QUERY.getColumns())
-        for (entry in entryRepository.getAllEntries()) {
-            if (!entry.isAllowSearch || entry.isSearchDataDynamic) continue
-            fetchSearchData(entry, cursor)
-        }
-        return cursor
-    }
-
-    private fun querySearchDynamicData(): Cursor {
-        val entryRepository by spaEnvironment.entryRepository
-        val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.getColumns())
-        for (entry in entryRepository.getAllEntries()) {
-            if (!entry.isAllowSearch || !entry.isSearchDataDynamic) continue
-            fetchSearchData(entry, cursor)
-        }
-        return cursor
-    }
-
-    private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
-        val entryRepository by spaEnvironment.entryRepository
-        val browseActivityClass = spaEnvironment.browseActivityClass
-
-        // Fetch search data. We can add runtime arguments later if necessary
-        val searchData = entry.getSearchData() ?: return
-        val intent = entry.containerPage()
-            .createBrowseIntent(context, browseActivityClass, entry.id)
-            ?: Intent()
-        cursor.newRow()
-            .add(ColumnEnum.ENTRY_ID.id, entry.id)
-            .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME))
-            .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
-            .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
-            .add(ColumnEnum.SEARCH_PATH.id,
-                entryRepository.getEntryPathWithTitle(entry.id, searchData.title))
-    }
-
-    private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
-        // Fetch status data. We can add runtime arguments later if necessary
-        val statusData = entry.getStatusData() ?: return
-        cursor.newRow()
-            .add(ColumnEnum.ENTRY_ID.id, entry.id)
-            .add(ColumnEnum.SEARCH_STATUS_DISABLED.id, statusData.isDisabled)
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceBroadcastReceiver.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceBroadcastReceiver.kt
deleted file mode 100644
index 58131e6..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceBroadcastReceiver.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework
-
-import android.content.BroadcastReceiver
-import android.content.Context
-import android.content.Intent
-import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
-
-class SpaSliceBroadcastReceiver : BroadcastReceiver() {
-    override fun onReceive(context: Context?, intent: Intent?) {
-        val sliceRepository by SpaEnvironmentFactory.instance.sliceDataRepository
-        val sliceUri = intent?.data ?: return
-        val sliceData = sliceRepository.getActiveSliceData(sliceUri) ?: return
-        sliceData.doAction()
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceProvider.kt
deleted file mode 100644
index faa04fd..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/SpaSliceProvider.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework
-
-import android.net.Uri
-import android.util.Log
-import androidx.lifecycle.Observer
-import androidx.slice.Slice
-import androidx.slice.SliceProvider
-import com.android.settingslib.spa.framework.common.EntrySliceData
-import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
-
-private const val TAG = "SpaSliceProvider"
-
-class SpaSliceProvider : SliceProvider(), Observer<Slice?> {
-    private fun getOrPutSliceData(sliceUri: Uri): EntrySliceData? {
-        if (!SpaEnvironmentFactory.isReady()) return null
-        val sliceRepository by SpaEnvironmentFactory.instance.sliceDataRepository
-        return sliceRepository.getOrBuildSliceData(sliceUri)
-    }
-
-    override fun onBindSlice(sliceUri: Uri): Slice? {
-        if (context == null) return null
-        Log.d(TAG, "onBindSlice: $sliceUri")
-        return getOrPutSliceData(sliceUri)?.value
-    }
-
-    override fun onSlicePinned(sliceUri: Uri) {
-        Log.d(TAG, "onSlicePinned: $sliceUri")
-        super.onSlicePinned(sliceUri)
-        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
-        runBlocking {
-            withContext(Dispatchers.Main) {
-                sliceLiveData.observeForever(this@SpaSliceProvider)
-            }
-        }
-    }
-
-    override fun onSliceUnpinned(sliceUri: Uri) {
-        Log.d(TAG, "onSliceUnpinned: $sliceUri")
-        super.onSliceUnpinned(sliceUri)
-        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
-        runBlocking {
-            withContext(Dispatchers.Main) {
-                sliceLiveData.removeObserver(this@SpaSliceProvider)
-            }
-        }
-    }
-
-    override fun onChanged(slice: Slice?) {
-        val uri = slice?.uri ?: return
-        Log.d(TAG, "onChanged: $uri")
-        context?.contentResolver?.notifyChange(uri, null)
-    }
-
-    override fun onCreateSliceProvider(): Boolean {
-        Log.d(TAG, "onCreateSliceProvider")
-        return true
-    }
-}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
index 121c07f..61b46be 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/ProviderColumn.kt
@@ -17,6 +17,7 @@
 package com.android.settingslib.spa.framework.common
 
 import android.content.UriMatcher
+import androidx.annotation.VisibleForTesting
 
 /**
  * Enum to define all column names in provider.
@@ -125,14 +126,17 @@
     ),
 }
 
-internal fun QueryEnum.getColumns(): Array<String> {
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+fun QueryEnum.getColumns(): Array<String> {
     return columnNames.map { it.id }.toTypedArray()
 }
 
-internal fun QueryEnum.getIndex(name: ColumnEnum): Int {
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+fun QueryEnum.getIndex(name: ColumnEnum): Int {
     return columnNames.indexOf(name)
 }
 
-internal fun QueryEnum.addUri(uriMatcher: UriMatcher, authority: String) {
+@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+fun QueryEnum.addUri(uriMatcher: UriMatcher, authority: String) {
     uriMatcher.addURI(authority, queryPath, queryMatchCode)
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
index 9ee7f9e..702c075 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsEntry.kt
@@ -219,11 +219,6 @@
         return this
     }
 
-    fun setIsAllowSearch(isAllowSearch: Boolean): SettingsEntryBuilder {
-        this.isAllowSearch = isAllowSearch
-        return this
-    }
-
     fun setIsSearchDataDynamic(isDynamic: Boolean): SettingsEntryBuilder {
         this.isSearchDataDynamic = isDynamic
         return this
@@ -251,6 +246,13 @@
 
     fun setSearchDataFn(fn: SearchDataGetter): SettingsEntryBuilder {
         this.searchDataFn = fn
+        this.isAllowSearch = true
+        return this
+    }
+
+    fun clearSearchDataFn(): SettingsEntryBuilder {
+        this.searchDataFn = { null }
+        this.isAllowSearch = false
         return this
     }
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
index a372bbd..7a39b73 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPage.kt
@@ -16,13 +16,8 @@
 
 package com.android.settingslib.spa.framework.common
 
-import android.app.Activity
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
 import android.os.Bundle
 import androidx.navigation.NamedNavArgument
-import com.android.settingslib.spa.framework.BrowseActivity
 import com.android.settingslib.spa.framework.util.isRuntimeParam
 import com.android.settingslib.spa.framework.util.navLink
 import com.android.settingslib.spa.framework.util.normalize
@@ -95,67 +90,21 @@
         return false
     }
 
-    fun enterPage() {
-        SpaEnvironmentFactory.instance.logger.event(
-            id,
-            LogEvent.PAGE_ENTER,
-            category = LogCategory.FRAMEWORK,
-            details = displayName,
-        )
-    }
-
-    fun leavePage() {
-        SpaEnvironmentFactory.instance.logger.event(
-            id,
-            LogEvent.PAGE_LEAVE,
-            category = LogCategory.FRAMEWORK,
-            details = displayName,
-        )
-    }
-
-    fun createBrowseIntent(entryId: String? = null): Intent? {
-        val context = SpaEnvironmentFactory.instance.appContext
-        val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass
-        return createBrowseIntent(context, browseActivityClass, entryId)
-    }
-
-    fun createBrowseIntent(
-        context: Context?,
-        browseActivityClass: Class<out Activity>?,
-        entryId: String? = null
-    ): Intent? {
-        if (!isBrowsable(context, browseActivityClass)) return null
-        return Intent().setComponent(ComponentName(context!!, browseActivityClass!!))
-            .apply {
-                putExtra(BrowseActivity.KEY_DESTINATION, buildRoute())
-                if (entryId != null) {
-                    putExtra(BrowseActivity.KEY_HIGHLIGHT_ENTRY, entryId)
-                }
-            }
-    }
-
-    fun createBrowseAdbCommand(
-        context: Context?,
-        browseActivityClass: Class<out Activity>?,
-        entryId: String? = null
-    ): String? {
-        if (!isBrowsable(context, browseActivityClass)) return null
-        val packageName = context!!.packageName
-        val activityName = browseActivityClass!!.name.replace(packageName, "")
-        val destinationParam = " -e ${BrowseActivity.KEY_DESTINATION} ${buildRoute()}"
-        val highlightParam =
-            if (entryId != null) " -e ${BrowseActivity.KEY_HIGHLIGHT_ENTRY} $entryId" else ""
-        return "adb shell am start -n $packageName/$activityName$destinationParam$highlightParam"
-    }
-
-    fun isBrowsable(context: Context?, browseActivityClass: Class<out Activity>?): Boolean {
-        return context != null &&
-            browseActivityClass != null &&
-            !isCreateBy(NULL_PAGE_NAME) &&
+    fun isBrowsable(): Boolean {
+        return !isCreateBy(NULL_PAGE_NAME) &&
             !hasRuntimeParam()
     }
 }
 
+fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
+    return SettingsPage.create(
+        name = name,
+        displayName = displayName,
+        parameter = parameter,
+        arguments = arguments
+    )
+}
+
 fun String.toHashId(): String {
     return this.hashCode().toUInt().toString(36)
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
index 60599d4..940005d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SettingsPageProvider.kt
@@ -51,12 +51,3 @@
         }
     }
 }
-
-fun SettingsPageProvider.createSettingsPage(arguments: Bundle? = null): SettingsPage {
-    return SettingsPage.create(
-        name = name,
-        displayName = displayName,
-        parameter = parameter,
-        arguments = arguments
-    )
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
index 945add4..6d0b810 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaEnvironment.kt
@@ -70,11 +70,14 @@
     // In Robolectric test, applicationContext is not available. Use context as fallback.
     val appContext: Context = context.applicationContext ?: context
 
+    open val logger: SpaLogger = object : SpaLogger {}
+
     open val browseActivityClass: Class<out Activity>? = null
     open val sliceBroadcastReceiverClass: Class<out BroadcastReceiver>? = null
+
+    // Specify provider authorities for debugging purpose.
     open val searchProviderAuthorities: String? = null
     open val sliceProviderAuthorities: String? = null
-    open val logger: SpaLogger = object : SpaLogger {}
 
     // TODO: add other environment setup here.
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
index 00a0362..6ecb7fa 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/common/SpaLogger.kt
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.spa.framework.common
 
+import android.os.Bundle
 import android.util.Log
 
 // Defines the category of the log, for quick filter
@@ -38,10 +39,13 @@
 
     // Entry related events.
     ENTRY_CLICK,
-    ENTRY_SWITCH_ON,
-    ENTRY_SWITCH_OFF,
+    ENTRY_SWITCH,
 }
 
+internal const val LOG_DATA_DISPLAY_NAME = "name"
+internal const val LOG_DATA_SESSION_NAME = "session"
+internal const val LOG_DATA_SWITCH_STATUS = "switch"
+
 /**
  * The interface of logger in Spa
  */
@@ -54,7 +58,7 @@
         id: String,
         event: LogEvent,
         category: LogCategory = LogCategory.DEFAULT,
-        details: String? = null
+        extraData: Bundle = Bundle.EMPTY
     ) {
     }
 }
@@ -64,8 +68,8 @@
         Log.d("SpaMsg-$category", "[$tag] $msg")
     }
 
-    override fun event(id: String, event: LogEvent, category: LogCategory, details: String?) {
-        val extraMsg = if (details == null) "" else " ($details)"
-        Log.d("SpaEvent-$category", "[$id] $event$extraMsg")
+    override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
+        val extraMsg = extraData.toString().removeRange(0, 6)
+        Log.d("SpaEvent-$category", "[$id] $event $extraMsg")
     }
 }
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/DrawablePainter.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/DrawablePainter.kt
index ae325f8..e3e1220 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/DrawablePainter.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/DrawablePainter.kt
@@ -20,6 +20,7 @@
 import android.graphics.drawable.BitmapDrawable
 import android.graphics.drawable.ColorDrawable
 import android.graphics.drawable.Drawable
+import android.os.Build
 import android.os.Handler
 import android.os.Looper
 import android.view.View
@@ -117,13 +118,17 @@
         return true
     }
 
-    override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean =
-        drawable.setLayoutDirection(
-            when (layoutDirection) {
-                LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
-                LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
-            }
-        )
+    override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean {
+        if (Build.VERSION.SDK_INT >= 23) {
+            return drawable.setLayoutDirection(
+                when (layoutDirection) {
+                    LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
+                    LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
+                }
+            )
+        }
+        return false
+    }
 
     override val intrinsicSize: Size get() = drawableIntrinsicSize
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt
deleted file mode 100644
index dbf8836..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/FlowExt.kt
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * Copyright 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.compose
-
-import android.annotation.SuppressLint
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.State
-import androidx.compose.runtime.produceState
-import androidx.compose.ui.platform.LocalLifecycleOwner
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.repeatOnLifecycle
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.withContext
-import kotlin.coroutines.CoroutineContext
-import kotlin.coroutines.EmptyCoroutineContext
-
-/**
- * *************************************************************************************************
- * This file was forked from AndroidX:
- * lifecycle/lifecycle-runtime-compose/src/main/java/androidx/lifecycle/compose/FlowExt.kt
- * TODO: Replace with AndroidX when it's usable.
- */
-
-/**
- * Collects values from this [StateFlow] and represents its latest value via [State] in a
- * lifecycle-aware manner.
- *
- * The [StateFlow.value] is used as an initial value. Every time there would be new value posted
- * into the [StateFlow] the returned [State] will be updated causing recomposition of every
- * [State.value] usage whenever the [lifecycleOwner]'s lifecycle is at least [minActiveState].
- *
- * This [StateFlow] is collected every time the [lifecycleOwner]'s lifecycle reaches the
- * [minActiveState] Lifecycle state. The collection stops when the [lifecycleOwner]'s lifecycle
- * falls below [minActiveState].
- *
- * @sample androidx.lifecycle.compose.samples.StateFlowCollectAsStateWithLifecycle
- *
- * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
- * parameter will throw an [IllegalArgumentException].
- *
- * @param lifecycleOwner [LifecycleOwner] whose `lifecycle` is used to restart collecting `this`
- * flow.
- * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
- * collection will stop if the lifecycle falls below that state, and will restart if it's in that
- * state again.
- * @param context [CoroutineContext] to use for collecting.
- */
-@SuppressLint("StateFlowValueCalledInComposition")
-@Composable
-fun <T> StateFlow<T>.collectAsStateWithLifecycle(
-    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
-    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
-    context: CoroutineContext = EmptyCoroutineContext
-): State<T> = collectAsStateWithLifecycle(
-    initialValue = this.value,
-    lifecycle = lifecycleOwner.lifecycle,
-    minActiveState = minActiveState,
-    context = context
-)
-
-/**
- * Collects values from this [StateFlow] and represents its latest value via [State] in a
- * lifecycle-aware manner.
- *
- * The [StateFlow.value] is used as an initial value. Every time there would be new value posted
- * into the [StateFlow] the returned [State] will be updated causing recomposition of every
- * [State.value] usage whenever the [lifecycle] is at least [minActiveState].
- *
- * This [StateFlow] is collected every time [lifecycle] reaches the [minActiveState] Lifecycle
- * state. The collection stops when [lifecycle] falls below [minActiveState].
- *
- * @sample androidx.lifecycle.compose.samples.StateFlowCollectAsStateWithLifecycle
- *
- * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
- * parameter will throw an [IllegalArgumentException].
- *
- * @param lifecycle [Lifecycle] used to restart collecting `this` flow.
- * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
- * collection will stop if the lifecycle falls below that state, and will restart if it's in that
- * state again.
- * @param context [CoroutineContext] to use for collecting.
- */
-@SuppressLint("StateFlowValueCalledInComposition")
-@Composable
-fun <T> StateFlow<T>.collectAsStateWithLifecycle(
-    lifecycle: Lifecycle,
-    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
-    context: CoroutineContext = EmptyCoroutineContext
-): State<T> = collectAsStateWithLifecycle(
-    initialValue = this.value,
-    lifecycle = lifecycle,
-    minActiveState = minActiveState,
-    context = context
-)
-
-/**
- * Collects values from this [Flow] and represents its latest value via [State] in a
- * lifecycle-aware manner.
- *
- * Every time there would be new value posted into the [Flow] the returned [State] will be updated
- * causing recomposition of every [State.value] usage whenever the [lifecycleOwner]'s lifecycle is
- * at least [minActiveState].
- *
- * This [Flow] is collected every time the [lifecycleOwner]'s lifecycle reaches the [minActiveState]
- * Lifecycle state. The collection stops when the [lifecycleOwner]'s lifecycle falls below
- * [minActiveState].
- *
- * @sample androidx.lifecycle.compose.samples.FlowCollectAsStateWithLifecycle
- *
- * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
- * parameter will throw an [IllegalArgumentException].
- *
- * @param initialValue The initial value given to the returned [State.value].
- * @param lifecycleOwner [LifecycleOwner] whose `lifecycle` is used to restart collecting `this`
- * flow.
- * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
- * collection will stop if the lifecycle falls below that state, and will restart if it's in that
- * state again.
- * @param context [CoroutineContext] to use for collecting.
- */
-@Composable
-fun <T> Flow<T>.collectAsStateWithLifecycle(
-    initialValue: T,
-    lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current,
-    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
-    context: CoroutineContext = EmptyCoroutineContext
-): State<T> = collectAsStateWithLifecycle(
-    initialValue = initialValue,
-    lifecycle = lifecycleOwner.lifecycle,
-    minActiveState = minActiveState,
-    context = context
-)
-
-/**
- * Collects values from this [Flow] and represents its latest value via [State] in a
- * lifecycle-aware manner.
- *
- * Every time there would be new value posted into the [Flow] the returned [State] will be updated
- * causing recomposition of every [State.value] usage whenever the [lifecycle] is at
- * least [minActiveState].
- *
- * This [Flow] is collected every time [lifecycle] reaches the [minActiveState] Lifecycle
- * state. The collection stops when [lifecycle] falls below [minActiveState].
- *
- * @sample androidx.lifecycle.compose.samples.FlowCollectAsStateWithLifecycle
- *
- * Warning: [Lifecycle.State.INITIALIZED] is not allowed in this API. Passing it as a
- * parameter will throw an [IllegalArgumentException].
- *
- * @param initialValue The initial value given to the returned [State.value].
- * @param lifecycle [Lifecycle] used to restart collecting `this` flow.
- * @param minActiveState [Lifecycle.State] in which the upstream flow gets collected. The
- * collection will stop if the lifecycle falls below that state, and will restart if it's in that
- * state again.
- * @param context [CoroutineContext] to use for collecting.
- */
-@Composable
-fun <T> Flow<T>.collectAsStateWithLifecycle(
-    initialValue: T,
-    lifecycle: Lifecycle,
-    minActiveState: Lifecycle.State = Lifecycle.State.STARTED,
-    context: CoroutineContext = EmptyCoroutineContext
-): State<T> {
-    return produceState(initialValue, this, lifecycle, minActiveState, context) {
-        lifecycle.repeatOnLifecycle(minActiveState) {
-            if (context == EmptyCoroutineContext) {
-                this@collectAsStateWithLifecycle.collect { this@produceState.value = it }
-            } else withContext(context) {
-                this@collectAsStateWithLifecycle.collect { this@produceState.value = it }
-            }
-        }
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
index 8d0313f..3f7cc19 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Keyboards.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.lazy.LazyListState
 import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.foundation.text.KeyboardActionScope
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.snapshotFlow
@@ -32,7 +31,7 @@
  */
 @OptIn(ExperimentalComposeUiApi::class)
 @Composable
-fun hideKeyboardAction(): KeyboardActionScope.() -> Unit {
+fun hideKeyboardAction(): () -> Unit {
     val keyboardController = LocalSoftwareKeyboardController.current
     return { keyboardController?.hide() }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
index 382c498..eb2bffe 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/NavControllerWrapper.kt
@@ -29,7 +29,10 @@
     fun navigateBack()
 
     val highlightEntryId: String?
-      get() = null
+        get() = null
+
+    val sessionSourceName: String?
+        get() = null
 }
 
 @Composable
@@ -63,6 +66,7 @@
     private val onBackPressedDispatcher: OnBackPressedDispatcher?,
 ) : NavControllerWrapper {
     var highlightId: String? = null
+    var sessionName: String? = null
 
     override fun navigate(route: String) {
         navController.navigate(route)
@@ -73,5 +77,8 @@
     }
 
     override val highlightEntryId: String?
-      get() = highlightId
+        get() = highlightId
+
+    override val sessionSourceName: String?
+        get() = sessionName
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
index 4df7794..392089a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/Pager.kt
@@ -19,8 +19,6 @@
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.calculateEndPadding
-import androidx.compose.foundation.layout.calculateStartPadding
 import androidx.compose.foundation.layout.wrapContentSize
 import androidx.compose.foundation.lazy.LazyColumn
 import androidx.compose.foundation.lazy.LazyRow
@@ -36,7 +34,6 @@
 import androidx.compose.ui.input.nestedscroll.NestedScrollSource
 import androidx.compose.ui.input.nestedscroll.nestedScroll
 import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.platform.LocalLayoutDirection
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.Velocity
 import androidx.compose.ui.unit.dp
@@ -123,7 +120,7 @@
     contentPadding: PaddingValues = PaddingValues(0.dp),
     horizontalAlignment: Alignment.Horizontal = Alignment.CenterHorizontally,
     key: ((page: Int) -> Any)? = null,
-    content: @Composable() (PagerScope.(page: Int) -> Unit),
+    content: @Composable PagerScope.(page: Int) -> Unit,
 ) {
     Pager(
         count = count,
@@ -175,24 +172,8 @@
             .collect { state.updateCurrentPageBasedOnLazyListState() }
     }
     val density = LocalDensity.current
-    val layoutDirection = LocalLayoutDirection.current
-    LaunchedEffect(density, contentPadding, isVertical, layoutDirection, reverseLayout, state) {
-        with(density) {
-            // this should be exposed on LazyListLayoutInfo instead. b/200920410
-            state.afterContentPadding = if (isVertical) {
-                if (!reverseLayout) {
-                    contentPadding.calculateBottomPadding()
-                } else {
-                    contentPadding.calculateTopPadding()
-                }
-            } else {
-                if (!reverseLayout) {
-                    contentPadding.calculateEndPadding(layoutDirection)
-                } else {
-                    contentPadding.calculateStartPadding(layoutDirection)
-                }
-            }.roundToPx()
-        }
+    LaunchedEffect(density, state, itemSpacing) {
+        with(density) { state.itemSpacing = itemSpacing.roundToPx() }
     }
 
     val pagerScope = remember(state) { PagerScopeImpl(state) }
@@ -203,6 +184,7 @@
         ConsumeFlingNestedScrollConnection(
             consumeHorizontal = !isVertical,
             consumeVertical = isVertical,
+            pagerState = state,
         )
     }
 
@@ -268,6 +250,7 @@
 private class ConsumeFlingNestedScrollConnection(
     private val consumeHorizontal: Boolean,
     private val consumeVertical: Boolean,
+    private val pagerState: PagerState,
 ) : NestedScrollConnection {
     override fun onPostScroll(
         consumed: Offset,
@@ -281,9 +264,15 @@
     }
 
     override suspend fun onPostFling(consumed: Velocity, available: Velocity): Velocity {
-        // We can consume all post fling velocity on the main-axis
-        // so that it doesn't propagate up to the Pager
-        return available.consume(consumeHorizontal, consumeVertical)
+        return if (pagerState.currentPageOffset != 0f) {
+            // The Pager is already scrolling. This means that a nested scroll child was
+            // scrolled to end, and the Pager can use this fling
+            Velocity.Zero
+        } else {
+            // A nested scroll child is still scrolling. We can consume all post fling
+            // velocity on the main-axis so that it doesn't propagate up to the Pager
+            available.consume(consumeHorizontal, consumeVertical)
+        }
     }
 }
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
index 21ba117..480335d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/compose/PagerState.kt
@@ -85,12 +85,14 @@
             return layoutInfo.visibleItemsInfo.maxByOrNull {
                 val start = maxOf(it.offset, 0)
                 val end = minOf(
-                    it.offset + it.size, layoutInfo.viewportEndOffset - afterContentPadding)
+                    it.offset + it.size,
+                    layoutInfo.viewportEndOffset - layoutInfo.afterContentPadding
+                )
                 end - start
             }
         }
 
-    internal var afterContentPadding = 0
+    internal var itemSpacing by mutableStateOf(0)
 
     private val currentPageLayoutInfo: LazyListItemInfo?
         get() = lazyListState.layoutInfo.visibleItemsInfo.lastOrNull {
@@ -135,9 +137,7 @@
      */
     val currentPageOffset: Float by derivedStateOf {
         currentPageLayoutInfo?.let {
-            // We coerce since itemSpacing can make the offset > 1f.
-            // We don't want to count spacing in the offset so cap it to 1f
-            (-it.offset / it.size.toFloat()).coerceIn(-1f, 1f)
+            (-it.offset / (it.size + itemSpacing).toFloat()).coerceIn(-0.5f, 0.5f)
         } ?: 0f
     }
 
@@ -187,28 +187,26 @@
                     // offset from the size
                     lazyListState.animateScrollToItem(
                         index = page,
-                        scrollOffset = (target.size * pageOffset).roundToInt()
+                        scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
                     )
                 } else if (layoutInfo.visibleItemsInfo.isNotEmpty()) {
                     // If we don't, we use the current page size as a guide
-                    val currentSize = layoutInfo.visibleItemsInfo.first().size
+                    val currentSize = layoutInfo.visibleItemsInfo.first().size + itemSpacing
                     lazyListState.animateScrollToItem(
                         index = page,
                         scrollOffset = (currentSize * pageOffset).roundToInt()
                     )
 
                     // The target should be visible now
-                    target = lazyListState.layoutInfo.visibleItemsInfo.firstOrNull {
-                        it.index == page
-                    }
+                    target = layoutInfo.visibleItemsInfo.firstOrNull { it.index == page }
 
-                    if (target != null && target.size != currentSize) {
+                    if (target != null && target.size + itemSpacing != currentSize) {
                         // If the size we used for calculating the offset differs from the actual
                         // target page size, we need to scroll again. This doesn't look great,
                         // but there's not much else we can do.
                         lazyListState.animateScrollToItem(
                             index = page,
-                            scrollOffset = (target.size * pageOffset).roundToInt()
+                            scrollOffset = ((target.size + itemSpacing) * pageOffset).roundToInt()
                         )
                     }
                 }
@@ -248,7 +246,7 @@
             if (pageOffset.absoluteValue > 0.0001f) {
                 currentPageLayoutInfo?.let {
                     scroll {
-                        scrollBy(it.size * pageOffset)
+                        scrollBy((it.size + itemSpacing) * pageOffset)
                     }
                 }
             }
@@ -295,7 +293,7 @@
     }
 
     private fun requireCurrentPageOffset(value: Float, name: String) {
-        require(value in -1f..1f) { "$name must be >= 0 and <= 1" }
+        require(value in -1f..1f) { "$name must be >= -1 and <= 1" }
     }
 
     companion object {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryHighlight.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryHighlight.kt
new file mode 100644
index 0000000..90c44b5
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryHighlight.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.repeatable
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.SideEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.saveable.rememberSaveable
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import com.android.settingslib.spa.framework.common.LocalEntryDataProvider
+import com.android.settingslib.spa.framework.theme.SettingsTheme
+
+@Composable
+internal fun EntryHighlight(UiLayoutFn: @Composable () -> Unit) {
+    val entryData = LocalEntryDataProvider.current
+    val entryIsHighlighted = rememberSaveable { entryData.isHighlighted }
+    var localHighlighted by rememberSaveable { mutableStateOf(false) }
+    SideEffect {
+        localHighlighted = entryIsHighlighted
+    }
+
+    val backgroundColor by animateColorAsState(
+        targetValue = when {
+            localHighlighted -> MaterialTheme.colorScheme.surfaceVariant
+            else -> SettingsTheme.colorScheme.background
+        },
+        animationSpec = repeatable(
+            iterations = 3,
+            animation = tween(durationMillis = 500),
+            repeatMode = RepeatMode.Restart
+        )
+    )
+    Box(modifier = Modifier.background(color = backgroundColor)) {
+        UiLayoutFn()
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryLogger.kt
new file mode 100644
index 0000000..1c88187
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/EntryLogger.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.core.os.bundleOf
+import com.android.settingslib.spa.framework.common.LOG_DATA_SWITCH_STATUS
+import com.android.settingslib.spa.framework.common.LocalEntryDataProvider
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+
+@Composable
+fun logEntryEvent(): (event: LogEvent, extraData: Bundle) -> Unit {
+    val entryId = LocalEntryDataProvider.current.entryId ?: return { _, _ -> }
+    return { event, extraData ->
+        SpaEnvironmentFactory.instance.logger.event(
+            entryId, event, category = LogCategory.VIEW, extraData = extraData
+        )
+    }
+}
+
+@Composable
+fun wrapOnClickWithLog(onClick: (() -> Unit)?): (() -> Unit)? {
+    if (onClick == null) return null
+    val logEvent = logEntryEvent()
+    return {
+        logEvent(LogEvent.ENTRY_CLICK, Bundle.EMPTY)
+        onClick()
+    }
+}
+
+@Composable
+fun wrapOnSwitchWithLog(onSwitch: ((checked: Boolean) -> Unit)?): ((checked: Boolean) -> Unit)? {
+    if (onSwitch == null) return null
+    val logEvent = logEntryEvent()
+    return {
+        logEvent(LogEvent.ENTRY_SWITCH, bundleOf(LOG_DATA_SWITCH_STATUS to it))
+        onSwitch(it)
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt
index d801840..8bfcff8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/Flows.kt
@@ -16,15 +16,17 @@
 
 package com.android.settingslib.spa.framework.util
 
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.State
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.distinctUntilChangedBy
-import kotlinx.coroutines.flow.filterNotNull
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.take
+
+/**
+ * Returns a [Flow] whose values are a list which containing the results of applying the given
+ * [transform] function to each element in the original flow's list.
+ */
+inline fun <T, R> Flow<List<T>>.mapItem(crossinline transform: (T) -> R): Flow<List<R>> =
+    map { list -> list.map(transform) }
 
 /**
  * Returns a [Flow] whose values are a list which containing the results of asynchronously applying
@@ -34,33 +36,13 @@
     map { list -> list.asyncMap(transform) }
 
 /**
+ * Returns a [Flow] whose values are a list containing only elements matching the given [predicate].
+ */
+inline fun <T> Flow<List<T>>.filterItem(crossinline predicate: (T) -> Boolean): Flow<List<T>> =
+    map { list -> list.filter(predicate) }
+
+/**
  * Delays the flow a little bit, wait the other flow's first value.
  */
 fun <T1, T2> Flow<T1>.waitFirst(otherFlow: Flow<T2>): Flow<T1> =
-    combine(otherFlow.distinctUntilChangedBy {}) { value, _ -> value }
-
-/**
- * Returns a [Flow] whose values are generated list by combining the most recently emitted non null
- * values by each flow.
- */
-inline fun <reified T : Any> combineToList(vararg flows: Flow<T?>): Flow<List<T>> = combine(
-    flows.asList(),
-) { array: Array<T?> -> array.filterNotNull() }
-
-class StateFlowBridge<T> {
-    private val stateFlow = MutableStateFlow<T?>(null)
-    val flow = stateFlow.filterNotNull()
-
-    fun setIfAbsent(value: T) {
-        if (stateFlow.value == null) {
-            stateFlow.value = value
-        }
-    }
-
-    @Composable
-    fun Sync(state: State<T>) {
-        LaunchedEffect(state.value) {
-            stateFlow.value = state.value
-        }
-    }
-}
+    combine(otherFlow.take(1)) { value, _ -> value }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
new file mode 100644
index 0000000..a881254
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/PageLogger.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import android.os.Bundle
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalLifecycleOwner
+import androidx.core.os.bundleOf
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import com.android.settingslib.spa.framework.common.LOG_DATA_DISPLAY_NAME
+import com.android.settingslib.spa.framework.common.LOG_DATA_SESSION_NAME
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.framework.compose.LocalNavController
+
+@Composable
+internal fun SettingsPageProvider.PageEvent(arguments: Bundle? = null) {
+    val page = remember(arguments) { createSettingsPage(arguments) }
+    val lifecycleOwner = LocalLifecycleOwner.current
+    val navController = LocalNavController.current
+    DisposableEffect(lifecycleOwner) {
+        val observer = LifecycleEventObserver { _, event ->
+            val logPageEvent: (event: LogEvent) -> Unit = {
+                SpaEnvironmentFactory.instance.logger.event(
+                    id = page.id,
+                    event = it,
+                    category = LogCategory.FRAMEWORK,
+                    extraData = bundleOf(
+                        LOG_DATA_DISPLAY_NAME to page.displayName,
+                        LOG_DATA_SESSION_NAME to navController.sessionSourceName,
+                    )
+                )
+            }
+            if (event == Lifecycle.Event.ON_START) {
+                logPageEvent(LogEvent.PAGE_ENTER)
+            } else if (event == Lifecycle.Event.ON_STOP) {
+                logPageEvent(LogEvent.PAGE_LEAVE)
+            }
+        }
+
+        // Add the observer to the lifecycle
+        lifecycleOwner.lifecycle.addObserver(observer)
+
+        // When the effect leaves the Composition, remove the observer
+        onDispose {
+            lifecycleOwner.lifecycle.removeObserver(observer)
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt
new file mode 100644
index 0000000..2c3c2e0
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/SpaIntent.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import android.content.ComponentName
+import android.content.Intent
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+
+const val SESSION_BROWSE = "browse"
+const val SESSION_SEARCH = "search"
+const val SESSION_SLICE = "slice"
+
+const val KEY_DESTINATION = "spaActivityDestination"
+const val KEY_HIGHLIGHT_ENTRY = "highlightEntry"
+const val KEY_SESSION_SOURCE_NAME = "sessionSource"
+
+val SPA_INTENT_RESERVED_KEYS = listOf(
+    KEY_DESTINATION,
+    KEY_HIGHLIGHT_ENTRY,
+    KEY_SESSION_SOURCE_NAME
+)
+
+private fun createBaseIntent(): Intent? {
+    val context = SpaEnvironmentFactory.instance.appContext
+    val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null
+    return Intent().setComponent(ComponentName(context, browseActivityClass))
+}
+
+fun SettingsPage.createIntent(sessionName: String? = null): Intent? {
+    if (!isBrowsable()) return null
+    return createBaseIntent()?.appendSpaParams(
+        destination = buildRoute(),
+        sessionName = sessionName
+    )
+}
+
+fun SettingsEntry.createIntent(sessionName: String? = null): Intent? {
+    val sp = containerPage()
+    if (!sp.isBrowsable()) return null
+    return createBaseIntent()?.appendSpaParams(
+        destination = sp.buildRoute(),
+        entryId = id,
+        sessionName = sessionName
+    )
+}
+
+fun Intent.appendSpaParams(
+    destination: String? = null,
+    entryId: String? = null,
+    sessionName: String? = null
+): Intent {
+    return apply {
+        if (destination != null) putExtra(KEY_DESTINATION, destination)
+        if (entryId != null) putExtra(KEY_HIGHLIGHT_ENTRY, entryId)
+        if (sessionName != null) putExtra(KEY_SESSION_SOURCE_NAME, sessionName)
+    }
+}
+
+fun Intent.getDestination(): String? {
+    return getStringExtra(KEY_DESTINATION)
+}
+
+fun Intent.getEntryId(): String? {
+    return getStringExtra(KEY_HIGHLIGHT_ENTRY)
+}
+
+fun Intent.getSessionName(): String? {
+    return getStringExtra(KEY_SESSION_SOURCE_NAME)
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
new file mode 100644
index 0000000..494e69b
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/StateFlowBridge.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.State
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.filterNotNull
+
+/** A StateFlow holder which value could be set or sync from [State]. */
+class StateFlowBridge<T> {
+    private val stateFlow = MutableStateFlow<T?>(null)
+    val flow = stateFlow.filterNotNull()
+
+    fun setIfAbsent(value: T) {
+        if (stateFlow.value == null) {
+            stateFlow.value = value
+        }
+    }
+
+    @Composable
+    fun Sync(state: State<T>) {
+        LaunchedEffect(state.value) {
+            stateFlow.value = state.value
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/WidgetLogger.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/WidgetLogger.kt
deleted file mode 100644
index 8d0a35c..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/framework/util/WidgetLogger.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.util
-
-import androidx.compose.runtime.Composable
-import com.android.settingslib.spa.framework.common.LocalEntryDataProvider
-import com.android.settingslib.spa.framework.common.LogCategory
-import com.android.settingslib.spa.framework.common.LogEvent
-import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
-
-@Composable
-fun logEntryEvent(): (event: LogEvent) -> Unit {
-    val entryId = LocalEntryDataProvider.current.entryId ?: return {}
-    return {
-        SpaEnvironmentFactory.instance.logger.event(entryId, it, category = LogCategory.VIEW)
-    }
-}
-
-@Composable
-fun wrapOnClickWithLog(onClick: (() -> Unit)?): (() -> Unit)? {
-    if (onClick == null) return null
-    val logEvent = logEntryEvent()
-    return {
-        logEvent(LogEvent.ENTRY_CLICK)
-        onClick()
-    }
-}
-
-@Composable
-fun wrapOnSwitchWithLog(onSwitch: ((checked: Boolean) -> Unit)?): ((checked: Boolean) -> Unit)? {
-    if (onSwitch == null) return null
-    val logEvent = logEntryEvent()
-    return {
-        val event = if (it) LogEvent.ENTRY_SWITCH_ON else LogEvent.ENTRY_SWITCH_OFF
-        logEvent(event)
-        onSwitch(it)
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
new file mode 100644
index 0000000..02aed1c
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/search/SpaSearchProvider.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.search
+
+import android.content.ContentProvider
+import android.content.ContentValues
+import android.content.Context
+import android.content.Intent
+import android.content.UriMatcher
+import android.content.pm.ProviderInfo
+import android.database.Cursor
+import android.database.MatrixCursor
+import android.net.Uri
+import android.util.Log
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.spa.framework.common.ColumnEnum
+import com.android.settingslib.spa.framework.common.QueryEnum
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.common.addUri
+import com.android.settingslib.spa.framework.common.getColumns
+import com.android.settingslib.spa.framework.util.SESSION_SEARCH
+import com.android.settingslib.spa.framework.util.createIntent
+
+private const val TAG = "SpaSearchProvider"
+
+/**
+ * The content provider to return entry related data, which can be used for search and hierarchy.
+ * One can query the provider result by:
+ *   $ adb shell content query --uri content://<AuthorityPath>/<QueryPath>
+ * For gallery, AuthorityPath = com.android.spa.gallery.provider
+ * For Settings, AuthorityPath = com.android.settings.spa.provider
+ * Some examples:
+ *   $ adb shell content query --uri content://<AuthorityPath>/search_static
+ *   $ adb shell content query --uri content://<AuthorityPath>/search_dynamic
+ *   $ adb shell content query --uri content://<AuthorityPath>/search_mutable_status
+ *   $ adb shell content query --uri content://<AuthorityPath>/search_immutable_status
+ */
+class SpaSearchProvider : ContentProvider() {
+    private val spaEnvironment get() = SpaEnvironmentFactory.instance
+    private val uriMatcher = UriMatcher(UriMatcher.NO_MATCH)
+
+    override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
+        TODO("Implement this to handle requests to delete one or more rows")
+    }
+
+    override fun getType(uri: Uri): String? {
+        TODO(
+            "Implement this to handle requests for the MIME type of the data" +
+                "at the given URI"
+        )
+    }
+
+    override fun insert(uri: Uri, values: ContentValues?): Uri? {
+        TODO("Implement this to handle requests to insert a new row.")
+    }
+
+    override fun update(
+        uri: Uri,
+        values: ContentValues?,
+        selection: String?,
+        selectionArgs: Array<String>?
+    ): Int {
+        TODO("Implement this to handle requests to update one or more rows.")
+    }
+
+    override fun onCreate(): Boolean {
+        Log.d(TAG, "onCreate")
+        return true
+    }
+
+    override fun attachInfo(context: Context?, info: ProviderInfo?) {
+        if (info != null) {
+            QueryEnum.SEARCH_STATIC_DATA_QUERY.addUri(uriMatcher, info.authority)
+            QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.addUri(uriMatcher, info.authority)
+            QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
+            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.addUri(uriMatcher, info.authority)
+        }
+        super.attachInfo(context, info)
+    }
+
+    override fun query(
+        uri: Uri,
+        projection: Array<String>?,
+        selection: String?,
+        selectionArgs: Array<String>?,
+        sortOrder: String?
+    ): Cursor? {
+        return try {
+            when (uriMatcher.match(uri)) {
+                QueryEnum.SEARCH_STATIC_DATA_QUERY.queryMatchCode -> querySearchStaticData()
+                QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.queryMatchCode -> querySearchDynamicData()
+                QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
+                    querySearchMutableStatusData()
+                QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.queryMatchCode ->
+                    querySearchImmutableStatusData()
+                else -> throw UnsupportedOperationException("Unknown Uri $uri")
+            }
+        } catch (e: UnsupportedOperationException) {
+            throw e
+        } catch (e: Exception) {
+            Log.e(TAG, "Provider querying exception:", e)
+            null
+        }
+    }
+
+    @VisibleForTesting
+    fun querySearchImmutableStatusData(): Cursor {
+        val entryRepository by spaEnvironment.entryRepository
+        val cursor = MatrixCursor(QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY.getColumns())
+        for (entry in entryRepository.getAllEntries()) {
+            if (!entry.isAllowSearch || entry.hasMutableStatus) continue
+            fetchStatusData(entry, cursor)
+        }
+        return cursor
+    }
+
+    @VisibleForTesting
+    fun querySearchMutableStatusData(): Cursor {
+        val entryRepository by spaEnvironment.entryRepository
+        val cursor = MatrixCursor(QueryEnum.SEARCH_MUTABLE_STATUS_DATA_QUERY.getColumns())
+        for (entry in entryRepository.getAllEntries()) {
+            if (!entry.isAllowSearch || !entry.hasMutableStatus) continue
+            fetchStatusData(entry, cursor)
+        }
+        return cursor
+    }
+
+    @VisibleForTesting
+    fun querySearchStaticData(): Cursor {
+        val entryRepository by spaEnvironment.entryRepository
+        val cursor = MatrixCursor(QueryEnum.SEARCH_STATIC_DATA_QUERY.getColumns())
+        for (entry in entryRepository.getAllEntries()) {
+            if (!entry.isAllowSearch || entry.isSearchDataDynamic) continue
+            fetchSearchData(entry, cursor)
+        }
+        return cursor
+    }
+
+    @VisibleForTesting
+    fun querySearchDynamicData(): Cursor {
+        val entryRepository by spaEnvironment.entryRepository
+        val cursor = MatrixCursor(QueryEnum.SEARCH_DYNAMIC_DATA_QUERY.getColumns())
+        for (entry in entryRepository.getAllEntries()) {
+            if (!entry.isAllowSearch || !entry.isSearchDataDynamic) continue
+            fetchSearchData(entry, cursor)
+        }
+        return cursor
+    }
+
+    private fun fetchSearchData(entry: SettingsEntry, cursor: MatrixCursor) {
+        val entryRepository by spaEnvironment.entryRepository
+
+        // Fetch search data. We can add runtime arguments later if necessary
+        val searchData = entry.getSearchData() ?: return
+        val intent = entry.createIntent(SESSION_SEARCH) ?: Intent()
+        cursor.newRow()
+            .add(ColumnEnum.ENTRY_ID.id, entry.id)
+            .add(ColumnEnum.ENTRY_INTENT_URI.id, intent.toUri(Intent.URI_INTENT_SCHEME))
+            .add(ColumnEnum.SEARCH_TITLE.id, searchData.title)
+            .add(ColumnEnum.SEARCH_KEYWORD.id, searchData.keyword)
+            .add(
+                ColumnEnum.SEARCH_PATH.id,
+                entryRepository.getEntryPathWithTitle(entry.id, searchData.title)
+            )
+    }
+
+    private fun fetchStatusData(entry: SettingsEntry, cursor: MatrixCursor) {
+        // Fetch status data. We can add runtime arguments later if necessary
+        val statusData = entry.getStatusData() ?: return
+        cursor.newRow()
+            .add(ColumnEnum.ENTRY_ID.id, entry.id)
+            .add(ColumnEnum.SEARCH_STATUS_DISABLED.id, statusData.isDisabled)
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt
index 14855a8..7a4750d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SettingsSliceDataRepository.kt
@@ -20,6 +20,7 @@
 import android.util.Log
 import com.android.settingslib.spa.framework.common.EntrySliceData
 import com.android.settingslib.spa.framework.common.SettingsEntryRepository
+import com.android.settingslib.spa.framework.util.getEntryId
 
 private const val TAG = "SliceDataRepository"
 
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt
index ff143ed..f362890 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SliceUtil.kt
@@ -24,9 +24,15 @@
 import android.content.Intent
 import android.net.Uri
 import android.os.Bundle
-import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_DESTINATION
-import com.android.settingslib.spa.framework.BrowseActivity.Companion.KEY_HIGHLIGHT_ENTRY
+import com.android.settingslib.spa.framework.common.SettingsEntry
 import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.util.KEY_DESTINATION
+import com.android.settingslib.spa.framework.util.KEY_HIGHLIGHT_ENTRY
+import com.android.settingslib.spa.framework.util.SESSION_SLICE
+import com.android.settingslib.spa.framework.util.SPA_INTENT_RESERVED_KEYS
+import com.android.settingslib.spa.framework.util.appendSpaParams
+import com.android.settingslib.spa.framework.util.getDestination
+import com.android.settingslib.spa.framework.util.getEntryId
 
 // Defines SliceUri, which contains special query parameters:
 //  -- KEY_DESTINATION: The route that this slice is navigated to.
@@ -35,11 +41,6 @@
 // Use {entryId, runtimeParams} as the unique Id of this Slice.
 typealias SliceUri = Uri
 
-val RESERVED_KEYS = listOf(
-    KEY_DESTINATION,
-    KEY_HIGHLIGHT_ENTRY
-)
-
 fun SliceUri.getEntryId(): String? {
     return getQueryParameter(KEY_HIGHLIGHT_ENTRY)
 }
@@ -51,7 +52,7 @@
 fun SliceUri.getRuntimeArguments(): Bundle {
     val params = Bundle()
     for (queryName in queryParameterNames) {
-        if (RESERVED_KEYS.contains(queryName)) continue
+        if (SPA_INTENT_RESERVED_KEYS.contains(queryName)) continue
         params.putString(queryName, getQueryParameter(queryName))
     }
     return params
@@ -63,12 +64,12 @@
     return "${entryId}_$params"
 }
 
-fun Uri.Builder.appendSliceParams(
-    route: String? = null,
+fun Uri.Builder.appendSpaParams(
+    destination: String? = null,
     entryId: String? = null,
     runtimeArguments: Bundle? = null
 ): Uri.Builder {
-    if (route != null) appendQueryParameter(KEY_DESTINATION, route)
+    if (destination != null) appendQueryParameter(KEY_DESTINATION, destination)
     if (entryId != null) appendQueryParameter(KEY_HIGHLIGHT_ENTRY, entryId)
     if (runtimeArguments != null) {
         for (key in runtimeArguments.keySet()) {
@@ -78,6 +79,20 @@
     return this
 }
 
+fun Uri.Builder.fromEntry(
+    entry: SettingsEntry,
+    authority: String?,
+    runtimeArguments: Bundle? = null
+): Uri.Builder {
+    if (authority == null) return this
+    val sp = entry.containerPage()
+    return scheme("content").authority(authority).appendSpaParams(
+        destination = sp.buildRoute(),
+        entryId = entry.id,
+        runtimeArguments = runtimeArguments
+    )
+}
+
 fun SliceUri.createBroadcastPendingIntent(): PendingIntent? {
     val context = SpaEnvironmentFactory.instance.appContext
     val sliceBroadcastClass =
@@ -97,8 +112,8 @@
 fun Intent.createBrowsePendingIntent(): PendingIntent? {
     val context = SpaEnvironmentFactory.instance.appContext
     val browseActivityClass = SpaEnvironmentFactory.instance.browseActivityClass ?: return null
-    val destination = getStringExtra(KEY_DESTINATION) ?: return null
-    val entryId = getStringExtra(KEY_HIGHLIGHT_ENTRY)
+    val destination = getDestination() ?: return null
+    val entryId = getEntryId()
     return createBrowsePendingIntent(context, browseActivityClass, destination, entryId)
 }
 
@@ -109,15 +124,12 @@
     entryId: String?
 ): PendingIntent {
     val intent = Intent().setComponent(ComponentName(context, browseActivityClass))
+        .appendSpaParams(destination, entryId, SESSION_SLICE)
         .apply {
             // Set both extra and data (which is a Uri) in Slice Intent:
             // 1) extra is used in SPA navigation framework
             // 2) data is used in Slice framework
-            putExtra(KEY_DESTINATION, destination)
-            if (entryId != null) {
-                putExtra(KEY_HIGHLIGHT_ENTRY, entryId)
-            }
-            data = Uri.Builder().appendSliceParams(destination, entryId).build()
+            data = Uri.Builder().appendSpaParams(destination, entryId).build()
             flags = Intent.FLAG_ACTIVITY_NEW_TASK
         }
 
@@ -130,7 +142,7 @@
     entryId: String
 ): PendingIntent {
     val intent = Intent().setComponent(ComponentName(context, sliceBroadcastClass))
-        .apply { data = Uri.Builder().appendSliceParams(entryId = entryId).build() }
+        .apply { data = Uri.Builder().appendSpaParams(entryId = entryId).build() }
     return PendingIntent.getBroadcast(
         context, 0 /* requestCode */, intent,
         PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_MUTABLE
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceBroadcastReceiver.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceBroadcastReceiver.kt
new file mode 100644
index 0000000..39cb431
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceBroadcastReceiver.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.slice
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+
+class SpaSliceBroadcastReceiver : BroadcastReceiver() {
+    override fun onReceive(context: Context?, intent: Intent?) {
+        val sliceRepository by SpaEnvironmentFactory.instance.sliceDataRepository
+        val sliceUri = intent?.data ?: return
+        val sliceData = sliceRepository.getActiveSliceData(sliceUri) ?: return
+        sliceData.doAction()
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
new file mode 100644
index 0000000..b809c0f
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/slice/SpaSliceProvider.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.slice
+
+import android.net.Uri
+import android.util.Log
+import androidx.lifecycle.Observer
+import androidx.slice.Slice
+import androidx.slice.SliceProvider
+import com.android.settingslib.spa.framework.common.EntrySliceData
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withContext
+
+private const val TAG = "SpaSliceProvider"
+
+class SpaSliceProvider : SliceProvider(), Observer<Slice?> {
+    private fun getOrPutSliceData(sliceUri: Uri): EntrySliceData? {
+        if (!SpaEnvironmentFactory.isReady()) return null
+        val sliceRepository by SpaEnvironmentFactory.instance.sliceDataRepository
+        return sliceRepository.getOrBuildSliceData(sliceUri)
+    }
+
+    override fun onBindSlice(sliceUri: Uri): Slice? {
+        if (context == null) return null
+        Log.d(TAG, "onBindSlice: $sliceUri")
+        return getOrPutSliceData(sliceUri)?.value
+    }
+
+    override fun onSlicePinned(sliceUri: Uri) {
+        Log.d(TAG, "onSlicePinned: $sliceUri")
+        super.onSlicePinned(sliceUri)
+        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
+        runBlocking {
+            withContext(Dispatchers.Main) {
+                sliceLiveData.observeForever(this@SpaSliceProvider)
+            }
+        }
+    }
+
+    override fun onSliceUnpinned(sliceUri: Uri) {
+        Log.d(TAG, "onSliceUnpinned: $sliceUri")
+        super.onSliceUnpinned(sliceUri)
+        val sliceLiveData = getOrPutSliceData(sliceUri) ?: return
+        runBlocking {
+            withContext(Dispatchers.Main) {
+                sliceLiveData.removeObserver(this@SpaSliceProvider)
+            }
+        }
+    }
+
+    override fun onChanged(slice: Slice?) {
+        val uri = slice?.uri ?: return
+        Log.d(TAG, "onChanged: $uri")
+        context?.contentResolver?.notifyChange(uri, null)
+    }
+
+    override fun onCreateSliceProvider(): Boolean {
+        Log.d(TAG, "onCreateSliceProvider")
+        return true
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
deleted file mode 100644
index cd8a02a..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/Illustration.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.widget
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.sizeIn
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import com.android.settingslib.spa.framework.theme.SettingsDimension
-import com.android.settingslib.spa.widget.ui.ImageBox
-import com.android.settingslib.spa.widget.ui.Lottie
-enum class ResourceType { IMAGE, LOTTIE }
-
-/**
- * The widget model for [Illustration] widget.
- */
-interface IllustrationModel {
-    /**
-     * The resource id of this [Illustration].
-     */
-    val resId: Int
-
-    /**
-     * The resource type of the [Illustration].
-     *
-     * It should be Lottie or Image.
-     */
-    val resourceType: ResourceType
-}
-
-/**
- * Illustration widget.
- *
- * Data is provided through [IllustrationModel].
- */
-@Composable
-fun Illustration(model: IllustrationModel) {
-    Illustration(
-        resId = model.resId,
-        resourceType = model.resourceType,
-        modifier = Modifier,
-    )
-}
-
-@Composable
-fun Illustration(
-    resId: Int,
-    resourceType: ResourceType,
-    modifier: Modifier = Modifier
-) {
-    Column(
-        modifier = modifier
-            .fillMaxWidth()
-            .padding(horizontal = SettingsDimension.illustrationPadding),
-        horizontalAlignment = Alignment.CenterHorizontally,
-    ) {
-        val illustrationModifier = modifier
-            .sizeIn(
-                maxWidth = SettingsDimension.illustrationMaxWidth,
-                maxHeight = SettingsDimension.illustrationMaxHeight,
-            )
-            .clip(RoundedCornerShape(SettingsDimension.illustrationCornerRadius))
-            .background(color = MaterialTheme.colorScheme.surface)
-
-        when (resourceType) {
-            ResourceType.LOTTIE -> {
-                Lottie(
-                    resId = resId,
-                    modifier = illustrationModifier,
-                )
-            }
-            ResourceType.IMAGE -> {
-                ImageBox(
-                    resId = resId,
-                    contentDescription = null,
-                    modifier = illustrationModifier,
-                )
-            }
-        }
-    }
-}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/illustration/Illustration.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/illustration/Illustration.kt
new file mode 100644
index 0000000..7cc9bf7
--- /dev/null
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/illustration/Illustration.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.illustration
+
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.sizeIn
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
+import com.android.settingslib.spa.framework.theme.SettingsDimension
+import com.android.settingslib.spa.widget.ui.ImageBox
+import com.android.settingslib.spa.widget.ui.Lottie
+enum class ResourceType { IMAGE, LOTTIE }
+
+/**
+ * The widget model for [Illustration] widget.
+ */
+interface IllustrationModel {
+    /**
+     * The resource id of this [Illustration].
+     */
+    val resId: Int
+
+    /**
+     * The resource type of the [Illustration].
+     *
+     * It should be Lottie or Image.
+     */
+    val resourceType: ResourceType
+}
+
+/**
+ * Illustration widget.
+ *
+ * Data is provided through [IllustrationModel].
+ */
+@Composable
+fun Illustration(model: IllustrationModel) {
+    Illustration(
+        resId = model.resId,
+        resourceType = model.resourceType,
+        modifier = Modifier,
+    )
+}
+
+@Composable
+fun Illustration(
+    resId: Int,
+    resourceType: ResourceType,
+    modifier: Modifier = Modifier
+) {
+    Column(
+        modifier = modifier
+            .fillMaxWidth()
+            .padding(horizontal = SettingsDimension.illustrationPadding),
+        horizontalAlignment = Alignment.CenterHorizontally,
+    ) {
+        val illustrationModifier = modifier
+            .sizeIn(
+                maxWidth = SettingsDimension.illustrationMaxWidth,
+                maxHeight = SettingsDimension.illustrationMaxHeight,
+            )
+            .clip(RoundedCornerShape(SettingsDimension.illustrationCornerRadius))
+            .background(color = MaterialTheme.colorScheme.surface)
+
+        when (resourceType) {
+            ResourceType.LOTTIE -> {
+                Lottie(
+                    resId = resId,
+                    modifier = illustrationModifier,
+                )
+            }
+            ResourceType.IMAGE -> {
+                ImageBox(
+                    resId = resId,
+                    contentDescription = null,
+                    modifier = illustrationModifier,
+                )
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
index db95e23..3e04b16 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/MainSwitchPreference.kt
@@ -28,7 +28,7 @@
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsShape
 import com.android.settingslib.spa.framework.theme.SettingsTheme
-import com.android.settingslib.spa.widget.util.EntryHighlight
+import com.android.settingslib.spa.framework.util.EntryHighlight
 
 @Composable
 fun MainSwitchPreference(model: SwitchPreferenceModel) {
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
index 895edf7..b6099e9 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/Preference.kt
@@ -24,12 +24,11 @@
 import androidx.compose.ui.graphics.vector.ImageVector
 import com.android.settingslib.spa.framework.common.EntryMacro
 import com.android.settingslib.spa.framework.common.EntrySearchData
-import com.android.settingslib.spa.framework.common.EntryStatusData
 import com.android.settingslib.spa.framework.compose.navigator
 import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.framework.util.EntryHighlight
 import com.android.settingslib.spa.framework.util.wrapOnClickWithLog
 import com.android.settingslib.spa.widget.ui.createSettingsIcon
-import com.android.settingslib.spa.widget.util.EntryHighlight
 
 data class SimplePreferenceMacro(
     val title: String,
@@ -56,10 +55,6 @@
             keyword = searchKeywords
         )
     }
-
-    override fun getStatusData(): EntryStatusData {
-        return EntryStatusData(isDisabled = false)
-    }
 }
 
 /**
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt
index 4ee2af0..7bca38f 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SliderPreference.kt
@@ -31,8 +31,8 @@
 import androidx.compose.ui.graphics.vector.ImageVector
 import androidx.compose.ui.tooling.preview.Preview
 import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.util.EntryHighlight
 import com.android.settingslib.spa.widget.ui.SettingsSlider
-import com.android.settingslib.spa.widget.util.EntryHighlight
 
 /**
  * The widget model for [SliderPreference] widget.
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
index 2d60619..b67eb3d 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/SwitchPreference.kt
@@ -20,6 +20,8 @@
 import androidx.compose.foundation.interaction.MutableInteractionSource
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.selection.toggleable
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.AirplanemodeActive
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.remember
@@ -31,9 +33,10 @@
 import com.android.settingslib.spa.framework.compose.toState
 import com.android.settingslib.spa.framework.theme.SettingsDimension
 import com.android.settingslib.spa.framework.theme.SettingsTheme
+import com.android.settingslib.spa.framework.util.EntryHighlight
 import com.android.settingslib.spa.framework.util.wrapOnSwitchWithLog
+import com.android.settingslib.spa.widget.ui.SettingsIcon
 import com.android.settingslib.spa.widget.ui.SettingsSwitch
-import com.android.settingslib.spa.widget.util.EntryHighlight
 
 /**
  * The widget model for [SwitchPreference] widget.
@@ -51,6 +54,14 @@
         get() = stateOf("")
 
     /**
+     * The icon of this [Preference].
+     *
+     * Default is `null` which means no icon.
+     */
+    val icon: (@Composable () -> Unit)?
+        get() = null
+
+    /**
      * Indicates whether this [SwitchPreference] is checked.
      *
      * This can be `null` during the data loading before the data is available.
@@ -84,6 +95,7 @@
         InternalSwitchPreference(
             title = model.title,
             summary = model.summary,
+            icon = model.icon,
             checked = model.checked,
             changeable = model.changeable,
             onCheckedChange = model.onCheckedChange,
@@ -95,6 +107,7 @@
 internal fun InternalSwitchPreference(
     title: String,
     summary: State<String> = "".toState(),
+    icon: @Composable (() -> Unit)? = null,
     checked: State<Boolean?>,
     changeable: State<Boolean> = true.toState(),
     paddingStart: Dp = SettingsDimension.itemPaddingStart,
@@ -125,6 +138,7 @@
         paddingStart = paddingStart,
         paddingEnd = paddingEnd,
         paddingVertical = paddingVertical,
+        icon = icon,
     ) {
         SettingsSwitch(
             checked = checked,
@@ -152,6 +166,15 @@
                 checked = false.toState(),
                 onCheckedChange = {},
             )
+            InternalSwitchPreference(
+                title = "Use Dark theme",
+                summary = "Summary".toState(),
+                checked = true.toState(),
+                onCheckedChange = {},
+                icon = @Composable {
+                    SettingsIcon(imageVector = Icons.Outlined.AirplanemodeActive)
+                },
+            )
         }
     }
 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
index fbfcaaa..63de2c8 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/preference/TwoTargetSwitchPreference.kt
@@ -17,7 +17,7 @@
 package com.android.settingslib.spa.widget.preference
 
 import androidx.compose.runtime.Composable
-import com.android.settingslib.spa.widget.util.EntryHighlight
+import com.android.settingslib.spa.framework.util.EntryHighlight
 import com.android.settingslib.spa.widget.ui.SettingsSwitch
 
 @Composable
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index b4852e4..4218489b 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -158,6 +158,7 @@
 private fun SearchBox(query: TextFieldValue, onQueryChange: (TextFieldValue) -> Unit) {
     val focusRequester = remember { FocusRequester() }
     val textStyle = MaterialTheme.typography.bodyLarge
+    val hideKeyboardAction = hideKeyboardAction()
     TextField(
         value = query,
         onValueChange = onQueryChange,
@@ -173,7 +174,7 @@
             )
         },
         keyboardOptions = KeyboardOptions(imeAction = ImeAction.Search),
-        keyboardActions = KeyboardActions(onSearch = hideKeyboardAction()),
+        keyboardActions = KeyboardActions(onSearch = { hideKeyboardAction() }),
         singleLine = true,
         colors = TextFieldDefaults.textFieldColors(
             containerColor = Color.Transparent,
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt
deleted file mode 100644
index e26bdf7..0000000
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/util/EntryHighlight.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.widget.util
-
-import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.core.RepeatMode
-import androidx.compose.animation.core.repeatable
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Box
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.SideEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Modifier
-import com.android.settingslib.spa.framework.common.LocalEntryDataProvider
-import com.android.settingslib.spa.framework.theme.SettingsTheme
-
-@Composable
-internal fun EntryHighlight(UiLayoutFn: @Composable () -> Unit) {
-    val entryData = LocalEntryDataProvider.current
-    val entryIsHighlighted = rememberSaveable { entryData.isHighlighted }
-    var localHighlighted by rememberSaveable { mutableStateOf(false) }
-    SideEffect {
-        localHighlighted = entryIsHighlighted
-    }
-
-    val backgroundColor by animateColorAsState(
-        targetValue = when {
-            localHighlighted -> MaterialTheme.colorScheme.surfaceVariant
-            else -> SettingsTheme.colorScheme.background
-        },
-        animationSpec = repeatable(
-            iterations = 3,
-            animation = tween(durationMillis = 500),
-            repeatMode = RepeatMode.Restart
-        )
-    )
-    Box(modifier = Modifier.background(color = backgroundColor)) {
-        UiLayoutFn()
-    }
-}
diff --git a/packages/SettingsLib/Spa/tests/build.gradle b/packages/SettingsLib/Spa/tests/build.gradle
index 5971895..45f9b23 100644
--- a/packages/SettingsLib/Spa/tests/build.gradle
+++ b/packages/SettingsLib/Spa/tests/build.gradle
@@ -56,6 +56,11 @@
     composeOptions {
         kotlinCompilerExtensionVersion jetpack_compose_compiler_version
     }
+    buildTypes {
+        debug {
+            testCoverageEnabled = true
+        }
+    }
 }
 
 dependencies {
@@ -63,3 +68,21 @@
     androidTestImplementation project(":testutils")
     androidTestImplementation "com.linkedin.dexmaker:dexmaker-mockito:2.28.1"
 }
+
+task coverageReport(type: JacocoReport, dependsOn: "connectedDebugAndroidTest") {
+    group = "Reporting"
+    description = "Generate Jacoco coverage reports after running tests."
+
+    sourceDirectories.from = files("../spa/src")
+    classDirectories.from = fileTree(
+            dir: "../spa/build/tmp/kotlin-classes/debug",
+            excludes: [
+                    "com/android/settingslib/spa/debug/**",
+
+                    // Excludes files forked from Accompanist.
+                    "com/android/settingslib/spa/framework/compose/DrawablePainter*",
+                    "com/android/settingslib/spa/framework/compose/Pager*",
+            ],
+    )
+    executionData.from = fileTree(dir: "$buildDir/outputs/code_coverage/debugAndroidTest/connected")
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
new file mode 100644
index 0000000..bd5884d
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/BrowseActivityTest.kt
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework
+
+import android.content.Context
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.android.settingslib.spa.tests.testutils.SpaLoggerForTest
+import com.android.settingslib.spa.tests.testutils.SppHome
+import com.android.settingslib.spa.testutils.waitUntil
+import com.google.common.truth.Truth
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+const val WAIT_UNTIL_TIMEOUT = 1000L
+
+@RunWith(AndroidJUnit4::class)
+class BrowseActivityTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaLogger = SpaLoggerForTest()
+    private val spaEnvironment =
+        SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()), logger = spaLogger)
+
+    @Test
+    fun testBrowsePage() {
+        spaLogger.reset()
+        SpaEnvironmentFactory.reset(spaEnvironment)
+
+        val sppRepository by spaEnvironment.pageProviderRepository
+        val sppHome = sppRepository.getProviderOrNull("SppHome")!!
+        val pageHome = sppHome.createSettingsPage()
+        val sppLayer1 = sppRepository.getProviderOrNull("SppLayer1")!!
+        val pageLayer1 = sppLayer1.createSettingsPage()
+
+        composeTestRule.setContent { BrowseContent(sppRepository) }
+
+        composeTestRule.onNodeWithText(sppHome.getTitle(null)).assertIsDisplayed()
+        spaLogger.verifyPageEvent(pageHome.id, 1, 0)
+        spaLogger.verifyPageEvent(pageLayer1.id, 0, 0)
+
+        // click to layer1 page
+        composeTestRule.onNodeWithText("SppHome to Layer1").assertIsDisplayed().performClick()
+        waitUntil(WAIT_UNTIL_TIMEOUT) {
+            composeTestRule.onAllNodesWithText(sppLayer1.getTitle(null))
+                .fetchSemanticsNodes().size == 1
+        }
+        spaLogger.verifyPageEvent(pageHome.id, 1, 1)
+        spaLogger.verifyPageEvent(pageLayer1.id, 1, 0)
+    }
+}
+
+private fun SpaLoggerForTest.verifyPageEvent(id: String, entryCount: Int, leaveCount: Int) {
+    Truth.assertThat(getEventCount(id, LogEvent.PAGE_ENTER, LogCategory.FRAMEWORK))
+        .isEqualTo(entryCount)
+    Truth.assertThat(getEventCount(id, LogEvent.PAGE_LEAVE, LogCategory.FRAMEWORK))
+        .isEqualTo(leaveCount)
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
index 9419161..c0b7464 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryRepositoryTest.kt
@@ -19,6 +19,12 @@
 import android.content.Context
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.android.settingslib.spa.tests.testutils.SppHome
+import com.android.settingslib.spa.tests.testutils.SppLayer1
+import com.android.settingslib.spa.tests.testutils.SppLayer2
+import com.android.settingslib.spa.tests.testutils.getUniqueEntryId
+import com.android.settingslib.spa.tests.testutils.getUniquePageId
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -26,7 +32,8 @@
 @RunWith(AndroidJUnit4::class)
 class SettingsEntryRepositoryTest {
     private val context: Context = ApplicationProvider.getApplicationContext()
-    private val spaEnvironment = SpaEnvironmentForTest(context)
+    private val spaEnvironment =
+        SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()))
     private val entryRepository by spaEnvironment.entryRepository
 
     @Test
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
index 2017d53..f98963c 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsEntryTest.kt
@@ -20,6 +20,8 @@
 import androidx.compose.ui.test.junit4.createComposeRule
 import androidx.core.os.bundleOf
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.testutils.getUniqueEntryId
+import com.android.settingslib.spa.tests.testutils.getUniquePageId
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -64,6 +66,7 @@
         assertThat(entry.isAllowSearch).isFalse()
         assertThat(entry.isSearchDataDynamic).isFalse()
         assertThat(entry.hasMutableStatus).isFalse()
+        assertThat(entry.hasSliceSupport).isFalse()
     }
 
     @Test
@@ -121,12 +124,13 @@
     @Test
     fun testSetAttributes() {
         val owner = SettingsPage.create("mySpp")
-        val entry = SettingsEntryBuilder.create(owner, "myEntry")
+        val entryBuilder = SettingsEntryBuilder.create(owner, "myEntry")
             .setDisplayName("myEntryDisplay")
-            .setIsAllowSearch(true)
             .setIsSearchDataDynamic(false)
             .setHasMutableStatus(true)
-            .build()
+            .setSearchDataFn { null }
+            .setSliceDataFn { _, _ -> null }
+        val entry = entryBuilder.build()
         assertThat(entry.id).isEqualTo(getUniqueEntryId("myEntry", owner))
         assertThat(entry.displayName).isEqualTo("myEntryDisplay")
         assertThat(entry.fromPage).isNull()
@@ -134,6 +138,10 @@
         assertThat(entry.isAllowSearch).isTrue()
         assertThat(entry.isSearchDataDynamic).isFalse()
         assertThat(entry.hasMutableStatus).isTrue()
+        assertThat(entry.hasSliceSupport).isTrue()
+
+        val entry2 = entryBuilder.clearSearchDataFn().build()
+        assertThat(entry2.isAllowSearch).isFalse()
     }
 
     @Test
@@ -150,6 +158,10 @@
 
         val rtArguments = bundleOf("rtParam" to "v2")
         composeTestRule.setContent { entry.UiLayout(rtArguments) }
+        assertThat(entry.isAllowSearch).isTrue()
+        assertThat(entry.isSearchDataDynamic).isFalse()
+        assertThat(entry.hasMutableStatus).isFalse()
+        assertThat(entry.hasSliceSupport).isFalse()
         val searchData = entry.getSearchData(rtArguments)
         val statusData = entry.getStatusData(rtArguments)
         assertThat(searchData?.title).isEqualTo("myTitle")
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt
index 7097a5d..1f5de2d 100644
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SettingsPageTest.kt
@@ -22,6 +22,8 @@
 import androidx.navigation.navArgument
 import androidx.test.core.app.ApplicationProvider
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.android.settingslib.spa.tests.testutils.getUniquePageId
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -29,8 +31,7 @@
 @RunWith(AndroidJUnit4::class)
 class SettingsPageTest {
     private val context: Context = ApplicationProvider.getApplicationContext()
-    private val spaLogger = SpaLoggerForTest()
-    private val spaEnvironment = SpaEnvironmentForTest(context, logger = spaLogger)
+    private val spaEnvironment = SpaEnvironmentForTest(context)
 
     @Test
     fun testNullPage() {
@@ -42,9 +43,7 @@
         assertThat(page.isCreateBy("NULL")).isTrue()
         assertThat(page.isCreateBy("Spp")).isFalse()
         assertThat(page.hasRuntimeParam()).isFalse()
-        assertThat(page.isBrowsable(context, MockActivity::class.java)).isFalse()
-        assertThat(page.createBrowseIntent(context, MockActivity::class.java)).isNull()
-        assertThat(page.createBrowseAdbCommand(context, MockActivity::class.java)).isNull()
+        assertThat(page.isBrowsable()).isFalse()
     }
 
     @Test
@@ -57,11 +56,7 @@
         assertThat(page.isCreateBy("NULL")).isFalse()
         assertThat(page.isCreateBy("mySpp")).isTrue()
         assertThat(page.hasRuntimeParam()).isFalse()
-        assertThat(page.isBrowsable(context, MockActivity::class.java)).isTrue()
-        assertThat(page.createBrowseIntent(context, MockActivity::class.java)).isNotNull()
-        assertThat(page.createBrowseAdbCommand(context, MockActivity::class.java)).contains(
-            "-e spaActivityDestination mySpp"
-        )
+        assertThat(page.isBrowsable()).isTrue()
     }
 
     @Test
@@ -71,20 +66,20 @@
             "int_param" to 10,
         )
         val page = spaEnvironment.createPage("SppWithParam", arguments)
-        assertThat(page.id).isEqualTo(getUniquePageId("SppWithParam", listOf(
-            navArgument("string_param") { type = NavType.StringType },
-            navArgument("int_param") { type = NavType.IntType },
-        ), arguments))
+        assertThat(page.id).isEqualTo(
+            getUniquePageId(
+                "SppWithParam", listOf(
+                    navArgument("string_param") { type = NavType.StringType },
+                    navArgument("int_param") { type = NavType.IntType },
+                ), arguments
+            )
+        )
         assertThat(page.sppName).isEqualTo("SppWithParam")
         assertThat(page.displayName).isEqualTo("SppWithParam")
         assertThat(page.buildRoute()).isEqualTo("SppWithParam/myStr/10")
         assertThat(page.isCreateBy("SppWithParam")).isTrue()
         assertThat(page.hasRuntimeParam()).isFalse()
-        assertThat(page.isBrowsable(context, MockActivity::class.java)).isTrue()
-        assertThat(page.createBrowseIntent(context, MockActivity::class.java)).isNotNull()
-        assertThat(page.createBrowseAdbCommand(context, MockActivity::class.java)).contains(
-            "-e spaActivityDestination SppWithParam/myStr/10"
-        )
+        assertThat(page.isBrowsable()).isTrue()
     }
 
     @Test
@@ -95,33 +90,20 @@
             "rt_param" to "rtStr",
         )
         val page = spaEnvironment.createPage("SppWithRtParam", arguments)
-        assertThat(page.id).isEqualTo(getUniquePageId("SppWithRtParam", listOf(
-            navArgument("string_param") { type = NavType.StringType },
-            navArgument("int_param") { type = NavType.IntType },
-            navArgument("rt_param") { type = NavType.StringType },
-        ), arguments))
+        assertThat(page.id).isEqualTo(
+            getUniquePageId(
+                "SppWithRtParam", listOf(
+                    navArgument("string_param") { type = NavType.StringType },
+                    navArgument("int_param") { type = NavType.IntType },
+                    navArgument("rt_param") { type = NavType.StringType },
+                ), arguments
+            )
+        )
         assertThat(page.sppName).isEqualTo("SppWithRtParam")
         assertThat(page.displayName).isEqualTo("SppWithRtParam")
         assertThat(page.buildRoute()).isEqualTo("SppWithRtParam/myStr/10/rtStr")
         assertThat(page.isCreateBy("SppWithRtParam")).isTrue()
         assertThat(page.hasRuntimeParam()).isTrue()
-        assertThat(page.isBrowsable(context, MockActivity::class.java)).isFalse()
-        assertThat(page.createBrowseIntent(context, MockActivity::class.java)).isNull()
-        assertThat(page.createBrowseAdbCommand(context, MockActivity::class.java)).isNull()
-    }
-
-    @Test
-    fun testPageEvent() {
-        spaLogger.reset()
-        SpaEnvironmentFactory.reset(spaEnvironment)
-        val page = spaEnvironment.createPage("SppHome")
-        page.enterPage()
-        page.leavePage()
-        page.enterPage()
-        assertThat(page.createBrowseIntent()).isNotNull()
-        assertThat(spaLogger.getEventCount(page.id, LogEvent.PAGE_ENTER, LogCategory.FRAMEWORK))
-            .isEqualTo(2)
-        assertThat(spaLogger.getEventCount(page.id, LogEvent.PAGE_LEAVE, LogCategory.FRAMEWORK))
-            .isEqualTo(1)
+        assertThat(page.isBrowsable()).isFalse()
     }
 }
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentForTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentForTest.kt
deleted file mode 100644
index b8731a3..0000000
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/SpaEnvironmentForTest.kt
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.common
-
-import android.app.Activity
-import android.content.Context
-import android.os.Bundle
-import androidx.navigation.NavType
-import androidx.navigation.navArgument
-import com.android.settingslib.spa.framework.BrowseActivity
-
-class SpaLoggerForTest : SpaLogger {
-    data class MsgCountKey(val msg: String, val category: LogCategory)
-    data class EventCountKey(val id: String, val event: LogEvent, val category: LogCategory)
-
-    private val messageCount: MutableMap<MsgCountKey, Int> = mutableMapOf()
-    private val eventCount: MutableMap<EventCountKey, Int> = mutableMapOf()
-
-    override fun message(tag: String, msg: String, category: LogCategory) {
-        val key = MsgCountKey("[$tag]$msg", category)
-        messageCount[key] = messageCount.getOrDefault(key, 0) + 1
-    }
-
-    override fun event(id: String, event: LogEvent, category: LogCategory, details: String?) {
-        val key = EventCountKey(id, event, category)
-        eventCount[key] = eventCount.getOrDefault(key, 0) + 1
-    }
-
-    fun getMessageCount(tag: String, msg: String, category: LogCategory): Int {
-        val key = MsgCountKey("[$tag]$msg", category)
-        return messageCount.getOrDefault(key, 0)
-    }
-
-    fun getEventCount(id: String, event: LogEvent, category: LogCategory): Int {
-        val key = EventCountKey(id, event, category)
-        return eventCount.getOrDefault(key, 0)
-    }
-
-    fun reset() {
-        messageCount.clear()
-        eventCount.clear()
-    }
-}
-
-class MockActivity : BrowseActivity()
-
-object SppHome : SettingsPageProvider {
-    override val name = "SppHome"
-
-    override fun getTitle(arguments: Bundle?): String {
-        return "TitleHome"
-    }
-
-    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
-        val owner = this.createSettingsPage()
-        return listOf(
-            SppLayer1.buildInject().setLink(fromPage = owner).build(),
-        )
-    }
-}
-
-object SppLayer1 : SettingsPageProvider {
-    override val name = "SppLayer1"
-
-    override fun getTitle(arguments: Bundle?): String {
-        return "TitleLayer1"
-    }
-
-    fun buildInject(): SettingsEntryBuilder {
-        return SettingsEntryBuilder.createInject(this.createSettingsPage())
-    }
-
-    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
-        val owner = this.createSettingsPage()
-        return listOf(
-            SettingsEntryBuilder.create(owner, "Layer1Entry1").build(),
-            SppLayer2.buildInject().setLink(fromPage = owner).build(),
-            SettingsEntryBuilder.create(owner, "Layer1Entry2").build(),
-        )
-    }
-}
-
-object SppLayer2 : SettingsPageProvider {
-    override val name = "SppLayer2"
-
-    fun buildInject(): SettingsEntryBuilder {
-        return SettingsEntryBuilder.createInject(this.createSettingsPage())
-    }
-
-    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
-        val owner = this.createSettingsPage()
-        return listOf(
-            SettingsEntryBuilder.create(owner, "Layer2Entry1").build(),
-            SettingsEntryBuilder.create(owner, "Layer2Entry2").build(),
-        )
-    }
-}
-
-class SpaEnvironmentForTest(
-    context: Context,
-    override val browseActivityClass: Class<out Activity>? = MockActivity::class.java,
-    override val logger: SpaLogger = SpaLoggerForTest()
-) : SpaEnvironment(context) {
-
-    override val pageProviderRepository = lazy {
-        SettingsPageProviderRepository(
-            listOf(
-                SppHome, SppLayer1, SppLayer2,
-                object : SettingsPageProvider {
-                    override val name = "SppWithParam"
-                    override val parameter = listOf(
-                        navArgument("string_param") { type = NavType.StringType },
-                        navArgument("int_param") { type = NavType.IntType },
-                    )
-                },
-                object : SettingsPageProvider {
-                    override val name = "SppWithRtParam"
-                    override val parameter = listOf(
-                        navArgument("string_param") { type = NavType.StringType },
-                        navArgument("int_param") { type = NavType.IntType },
-                        navArgument("rt_param") { type = NavType.StringType },
-                    )
-                },
-            ),
-            listOf(SettingsPage.create("SppHome"))
-        )
-    }
-
-    fun createPage(sppName: String, arguments: Bundle? = null): SettingsPage {
-        return pageProviderRepository.value
-            .getProviderOrNull(sppName)!!.createSettingsPage(arguments)
-    }
-}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt
deleted file mode 100644
index 93f9afe..0000000
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/common/UniqueIdHelper.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.framework.common
-
-import android.os.Bundle
-import androidx.navigation.NamedNavArgument
-import com.android.settingslib.spa.framework.util.normalize
-
-fun getUniquePageId(
-    name: String,
-    parameter: List<NamedNavArgument> = emptyList(),
-    arguments: Bundle? = null
-): String {
-    val normArguments = parameter.normalize(arguments)
-    return "$name:${normArguments?.toString()}".toHashId()
-}
-
-fun getUniquePageId(page: SettingsPage): String {
-    return getUniquePageId(page.sppName, page.parameter, page.arguments)
-}
-
-fun getUniqueEntryId(
-    name: String,
-    owner: SettingsPage,
-    fromPage: SettingsPage? = null,
-    toPage: SettingsPage? = null
-): String {
-    val ownerId = getUniquePageId(owner)
-    val fromId = if (fromPage == null) "null" else getUniquePageId(fromPage)
-    val toId = if (toPage == null) "null" else getUniquePageId(toPage)
-    return "$name:$ownerId($fromId-$toId)".toHashId()
-}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt
new file mode 100644
index 0000000..944ef7f
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/compose/KeyboardsTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.compose
+
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material3.Text
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.LocalSoftwareKeyboardController
+import androidx.compose.ui.platform.SoftwareKeyboardController
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+
+@OptIn(ExperimentalComposeUiApi::class)
+@RunWith(AndroidJUnit4::class)
+class KeyboardsTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @Mock
+    lateinit var keyboardController: SoftwareKeyboardController
+
+    @Test
+    fun hideKeyboardAction_callControllerHide() {
+        lateinit var action: () -> Unit
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalSoftwareKeyboardController provides keyboardController) {
+                action = hideKeyboardAction()
+            }
+        }
+
+        action()
+
+        verify(keyboardController).hide()
+    }
+
+    @Test
+    fun rememberLazyListStateAndHideKeyboardWhenStartScroll_notCallHideInitially() {
+        setLazyColumn(scroll = false)
+
+        verify(keyboardController, never()).hide()
+    }
+
+    @Test
+    fun rememberLazyListStateAndHideKeyboardWhenStartScroll_callHideWhenScroll() {
+        setLazyColumn(scroll = true)
+
+        verify(keyboardController).hide()
+    }
+
+    private fun setLazyColumn(scroll: Boolean) {
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalSoftwareKeyboardController provides keyboardController) {
+                val lazyListState = rememberLazyListStateAndHideKeyboardWhenStartScroll()
+                LazyColumn(
+                    modifier = Modifier.size(100.dp),
+                    state = lazyListState,
+                ) {
+                    items(count = 10) {
+                        Text(text = it.toString())
+                    }
+                }
+                if (scroll) {
+                    LaunchedEffect(Unit) {
+                        lazyListState.animateScrollToItem(1)
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/FlowsTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/FlowsTest.kt
new file mode 100644
index 0000000..4dcdea9
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/FlowsTest.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.count
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class FlowsTest {
+    @Test
+    fun mapItem() = runTest {
+        val inputFlow = flowOf(listOf("A", "BB", "CCC"))
+
+        val outputFlow = inputFlow.mapItem { it.length }
+
+        assertThat(outputFlow.first()).containsExactly(1, 2, 3).inOrder()
+    }
+
+    @Test
+    fun asyncMapItem() = runTest {
+        val inputFlow = flowOf(listOf("A", "BB", "CCC"))
+
+        val outputFlow = inputFlow.asyncMapItem { it.length }
+
+        assertThat(outputFlow.first()).containsExactly(1, 2, 3).inOrder()
+    }
+
+    @Test
+    fun filterItem() = runTest {
+        val inputFlow = flowOf(listOf("A", "BB", "CCC"))
+
+        val outputFlow = inputFlow.filterItem { it.length >= 2 }
+
+        assertThat(outputFlow.first()).containsExactly("BB", "CCC").inOrder()
+    }
+
+    @Test
+    fun waitFirst_otherFlowEmpty() = runTest {
+        val mainFlow = flowOf("A")
+        val otherFlow = emptyFlow<String>()
+
+        val outputFlow = mainFlow.waitFirst(otherFlow)
+
+        assertThat(outputFlow.count()).isEqualTo(0)
+    }
+
+    @Test
+    fun waitFirst_otherFlowOneValue() = runTest {
+        val mainFlow = flowOf("A")
+        val otherFlow = flowOf("B")
+
+        val outputFlow = mainFlow.waitFirst(otherFlow)
+
+        assertThat(outputFlow.toList()).containsExactly("A")
+    }
+
+    @Test
+    fun waitFirst_otherFlowTwoValues() = runTest {
+        val mainFlow = flowOf("A")
+        val otherFlow = flowOf("B", "B")
+
+        val outputFlow = mainFlow.waitFirst(otherFlow)
+
+        assertThat(outputFlow.toList()).containsExactly("A")
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt
new file mode 100644
index 0000000..1854728
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/SpaIntentTest.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.google.common.truth.Truth
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SpaIntentTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaEnvironment = SpaEnvironmentForTest(context)
+
+    @Before
+    fun setEnvironment() {
+        SpaEnvironmentFactory.reset(spaEnvironment)
+    }
+
+    @Test
+    fun testCreateIntent() {
+        val nullPage = SettingsPage.createNull()
+        Truth.assertThat(nullPage.createIntent()).isNull()
+        Truth.assertThat(SettingsEntryBuilder.createInject(nullPage).build().createIntent())
+            .isNull()
+
+        val page = spaEnvironment.createPage("SppHome")
+        val pageIntent = page.createIntent()
+        Truth.assertThat(pageIntent).isNotNull()
+        Truth.assertThat(pageIntent!!.getDestination()).isEqualTo(page.buildRoute())
+        Truth.assertThat(pageIntent.getEntryId()).isNull()
+        Truth.assertThat(pageIntent.getSessionName()).isNull()
+
+        val entry = SettingsEntryBuilder.createInject(page).build()
+        val entryIntent = entry.createIntent(SESSION_SEARCH)
+        Truth.assertThat(entryIntent).isNotNull()
+        Truth.assertThat(entryIntent!!.getDestination()).isEqualTo(page.buildRoute())
+        Truth.assertThat(entryIntent.getEntryId()).isEqualTo(entry.id)
+        Truth.assertThat(entryIntent.getSessionName()).isEqualTo(SESSION_SEARCH)
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
new file mode 100644
index 0000000..e1d9a28
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/framework/util/StateFlowBridgeTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.framework.util
+
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runTest
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class StateFlowBridgeTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun stateFlowBridge_initial() = runTest {
+        val stateFlowBridge = StateFlowBridge<String>()
+
+        val flow = stateFlowBridge.flow
+
+        val first = flow.firstWithTimeoutOrNull()
+        assertThat(first).isNull()
+    }
+
+    @Test
+    fun stateFlowBridge_setIfAbsent() = runTest {
+        val stateFlowBridge = StateFlowBridge<String>()
+
+        stateFlowBridge.setIfAbsent("A")
+
+        val first = stateFlowBridge.flow.firstWithTimeoutOrNull()
+        assertThat(first).isEqualTo("A")
+    }
+
+    @Test
+    fun stateFlowBridge_sync() = runTest {
+        val stateFlowBridge = StateFlowBridge<String>()
+
+        composeTestRule.setContent {
+            stateFlowBridge.Sync(stateOf("A"))
+        }
+
+        val first = stateFlowBridge.flow.firstWithTimeoutOrNull()
+        assertThat(first).isEqualTo("A")
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
new file mode 100644
index 0000000..cdb0f3a
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/search/SpaSearchProviderTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.search
+
+import android.content.Context
+import android.database.Cursor
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.ColumnEnum
+import com.android.settingslib.spa.framework.common.QueryEnum
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.framework.common.getIndex
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.android.settingslib.spa.tests.testutils.SppForSearch
+import com.google.common.truth.Truth
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SpaSearchProviderTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaEnvironment =
+        SpaEnvironmentForTest(context, listOf(SppForSearch.createSettingsPage()))
+    private val searchProvider = SpaSearchProvider()
+
+    @Test
+    fun testQuerySearchStatusData() {
+        SpaEnvironmentFactory.reset(spaEnvironment)
+        val pageOwner = spaEnvironment.createPage("SppForSearch")
+
+        val immutableStatus = searchProvider.querySearchImmutableStatusData()
+        Truth.assertThat(immutableStatus.count).isEqualTo(1)
+        immutableStatus.moveToFirst()
+        immutableStatus.checkValue(
+            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_ID,
+            pageOwner.getEntryId("SearchDynamicWithImmutableStatus")
+        )
+
+        val mutableStatus = searchProvider.querySearchMutableStatusData()
+        Truth.assertThat(mutableStatus.count).isEqualTo(2)
+        mutableStatus.moveToFirst()
+        mutableStatus.checkValue(
+            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_ID,
+            pageOwner.getEntryId("SearchStaticWithMutableStatus")
+        )
+
+        mutableStatus.moveToNext()
+        mutableStatus.checkValue(
+            QueryEnum.SEARCH_IMMUTABLE_STATUS_DATA_QUERY,
+            ColumnEnum.ENTRY_ID,
+            pageOwner.getEntryId("SearchDynamicWithMutableStatus")
+        )
+    }
+
+    @Test
+    fun testQuerySearchIndexData() {
+        SpaEnvironmentFactory.reset(spaEnvironment)
+        val staticData = searchProvider.querySearchStaticData()
+        Truth.assertThat(staticData.count).isEqualTo(2)
+
+        val dynamicData = searchProvider.querySearchDynamicData()
+        Truth.assertThat(dynamicData.count).isEqualTo(2)
+    }
+}
+
+private fun Cursor.checkValue(query: QueryEnum, column: ColumnEnum, value: String) {
+    Truth.assertThat(getString(query.getIndex(column))).isEqualTo(value)
+}
+
+private fun SettingsPage.getEntryId(name: String): String {
+    return SettingsEntryBuilder.create(this, name).build().id
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt
new file mode 100644
index 0000000..1bdba29
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SettingsSliceDataRepositoryTest.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.slice
+
+import android.content.Context
+import android.net.Uri
+import androidx.arch.core.executor.testing.InstantTaskExecutorRule
+import androidx.lifecycle.Observer
+import androidx.slice.Slice
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.android.settingslib.spa.tests.testutils.SppHome
+import com.android.settingslib.spa.tests.testutils.SppLayer2
+import com.android.settingslib.spa.tests.testutils.getUniqueEntryId
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SettingsSliceDataRepositoryTest {
+    @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaEnvironment =
+        SpaEnvironmentForTest(context, listOf(SppHome.createSettingsPage()))
+    private val sliceDataRepository by spaEnvironment.sliceDataRepository
+
+    @Test
+    fun getOrBuildSliceDataTest() {
+        // Slice empty
+        assertThat(sliceDataRepository.getOrBuildSliceData(Uri.EMPTY)).isNull()
+
+        // Slice supported
+        val page = SppLayer2.createSettingsPage()
+        val entryId = getUniqueEntryId("Layer2Entry1", page)
+        val sliceUri = Uri.Builder().appendSpaParams(page.buildRoute(), entryId).build()
+        assertThat(sliceUri.getDestination()).isEqualTo("SppLayer2")
+        assertThat(sliceUri.getSliceId()).isEqualTo("${entryId}_Bundle[{}]")
+        val sliceData = sliceDataRepository.getOrBuildSliceData(sliceUri)
+        assertThat(sliceData).isNotNull()
+        assertThat(sliceDataRepository.getOrBuildSliceData(sliceUri)).isSameInstanceAs(sliceData)
+
+        // Slice unsupported
+        val entryId2 = getUniqueEntryId("Layer2Entry2", page)
+        val sliceUri2 = Uri.Builder().appendSpaParams(page.buildRoute(), entryId2).build()
+        assertThat(sliceUri2.getDestination()).isEqualTo("SppLayer2")
+        assertThat(sliceUri2.getSliceId()).isEqualTo("${entryId2}_Bundle[{}]")
+        assertThat(sliceDataRepository.getOrBuildSliceData(sliceUri2)).isNull()
+    }
+
+    @Test
+    fun getActiveSliceDataTest() {
+        val page = SppLayer2.createSettingsPage()
+        val entryId = getUniqueEntryId("Layer2Entry1", page)
+        val sliceUri = Uri.Builder().appendSpaParams(page.buildRoute(), entryId).build()
+
+        // build slice data first
+        val sliceData = sliceDataRepository.getOrBuildSliceData(sliceUri)
+
+        // slice data is inactive
+        assertThat(sliceData!!.isActive()).isFalse()
+        assertThat(sliceDataRepository.getActiveSliceData(sliceUri)).isNull()
+
+        // slice data is active
+        val observer = Observer<Slice?> { }
+        sliceData.observeForever(observer)
+        assertThat(sliceData.isActive()).isTrue()
+        assertThat(sliceDataRepository.getActiveSliceData(sliceUri)).isSameInstanceAs(sliceData)
+
+        // slice data is inactive again
+        sliceData.removeObserver(observer)
+        assertThat(sliceData.isActive()).isFalse()
+        assertThat(sliceDataRepository.getActiveSliceData(sliceUri)).isNull()
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt
new file mode 100644
index 0000000..d1c4e51
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/slice/SliceUtilTest.kt
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.slice
+
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import androidx.core.os.bundleOf
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.common.SpaEnvironmentFactory
+import com.android.settingslib.spa.tests.testutils.SpaEnvironmentForTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class SliceUtilTest {
+    private val context: Context = ApplicationProvider.getApplicationContext()
+    private val spaEnvironment = SpaEnvironmentForTest(context)
+
+    @Test
+    fun sliceUriTest() {
+        assertThat(Uri.EMPTY.getEntryId()).isNull()
+        assertThat(Uri.EMPTY.getDestination()).isNull()
+        assertThat(Uri.EMPTY.getRuntimeArguments().size()).isEqualTo(0)
+        assertThat(Uri.EMPTY.getSliceId()).isNull()
+
+        // valid slice uri
+        val dest = "myRoute"
+        val entryId = "myEntry"
+        val sliceUriWithoutParams = Uri.Builder().appendSpaParams(dest, entryId).build()
+        assertThat(sliceUriWithoutParams.getEntryId()).isEqualTo(entryId)
+        assertThat(sliceUriWithoutParams.getDestination()).isEqualTo(dest)
+        assertThat(sliceUriWithoutParams.getRuntimeArguments().size()).isEqualTo(0)
+        assertThat(sliceUriWithoutParams.getSliceId()).isEqualTo("${entryId}_Bundle[{}]")
+
+        val sliceUriWithParams =
+            Uri.Builder().appendSpaParams(dest, entryId, bundleOf("p1" to "v1")).build()
+        assertThat(sliceUriWithParams.getEntryId()).isEqualTo(entryId)
+        assertThat(sliceUriWithParams.getDestination()).isEqualTo(dest)
+        assertThat(sliceUriWithParams.getRuntimeArguments().size()).isEqualTo(1)
+        assertThat(sliceUriWithParams.getSliceId()).isEqualTo("${entryId}_Bundle[{p1=v1}]")
+    }
+
+    @Test
+    fun createBroadcastPendingIntentTest() {
+        SpaEnvironmentFactory.reset(spaEnvironment)
+
+        // Empty Slice Uri
+        assertThat(Uri.EMPTY.createBroadcastPendingIntent()).isNull()
+
+        // Valid Slice Uri
+        val dest = "myRoute"
+        val entryId = "myEntry"
+        val sliceUriWithoutParams = Uri.Builder().appendSpaParams(dest, entryId).build()
+        val pendingIntent = sliceUriWithoutParams.createBroadcastPendingIntent()
+        assertThat(pendingIntent).isNotNull()
+        assertThat(pendingIntent!!.isBroadcast).isTrue()
+        assertThat(pendingIntent.isImmutable).isFalse()
+    }
+
+    @Test
+    fun createBrowsePendingIntentTest() {
+        SpaEnvironmentFactory.reset(spaEnvironment)
+
+        // Empty Slice Uri
+        assertThat(Uri.EMPTY.createBrowsePendingIntent()).isNull()
+
+        // Empty Intent
+        assertThat(Intent().createBrowsePendingIntent()).isNull()
+
+        // Valid Slice Uri
+        val dest = "myRoute"
+        val entryId = "myEntry"
+        val sliceUri = Uri.Builder().appendSpaParams(dest, entryId).build()
+        val pendingIntent = sliceUri.createBrowsePendingIntent()
+        assertThat(pendingIntent).isNotNull()
+        assertThat(pendingIntent!!.isActivity).isTrue()
+        assertThat(pendingIntent.isImmutable).isTrue()
+
+        // Valid Intent
+        val intent = Intent().apply {
+            putExtra("spaActivityDestination", dest)
+            putExtra("highlightEntry", entryId)
+        }
+        val pendingIntent2 = intent.createBrowsePendingIntent()
+        assertThat(pendingIntent2).isNotNull()
+        assertThat(pendingIntent2!!.isActivity).isTrue()
+        assertThat(pendingIntent2.isImmutable).isTrue()
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt
new file mode 100644
index 0000000..f38bd08
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/SpaEnvironmentForTest.kt
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.tests.testutils
+
+import android.app.Activity
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import androidx.navigation.NavType
+import androidx.navigation.navArgument
+import com.android.settingslib.spa.framework.BrowseActivity
+import com.android.settingslib.spa.framework.common.EntrySearchData
+import com.android.settingslib.spa.framework.common.EntrySliceData
+import com.android.settingslib.spa.framework.common.EntryStatusData
+import com.android.settingslib.spa.framework.common.LogCategory
+import com.android.settingslib.spa.framework.common.LogEvent
+import com.android.settingslib.spa.framework.common.SettingsEntry
+import com.android.settingslib.spa.framework.common.SettingsEntryBuilder
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.SettingsPageProvider
+import com.android.settingslib.spa.framework.common.SettingsPageProviderRepository
+import com.android.settingslib.spa.framework.common.SpaEnvironment
+import com.android.settingslib.spa.framework.common.SpaLogger
+import com.android.settingslib.spa.framework.common.createSettingsPage
+import com.android.settingslib.spa.widget.preference.SimplePreferenceMacro
+
+class SpaLoggerForTest : SpaLogger {
+    data class MsgCountKey(val msg: String, val category: LogCategory)
+    data class EventCountKey(val id: String, val event: LogEvent, val category: LogCategory)
+
+    private val messageCount: MutableMap<MsgCountKey, Int> = mutableMapOf()
+    private val eventCount: MutableMap<EventCountKey, Int> = mutableMapOf()
+
+    override fun message(tag: String, msg: String, category: LogCategory) {
+        val key = MsgCountKey("[$tag]$msg", category)
+        messageCount[key] = (messageCount[key] ?: 0) + 1
+    }
+
+    override fun event(id: String, event: LogEvent, category: LogCategory, extraData: Bundle) {
+        val key = EventCountKey(id, event, category)
+        eventCount[key] = (eventCount[key] ?: 0) + 1
+    }
+
+    fun getMessageCount(tag: String, msg: String, category: LogCategory): Int {
+        val key = MsgCountKey("[$tag]$msg", category)
+        return messageCount[key] ?: 0
+    }
+
+    fun getEventCount(id: String, event: LogEvent, category: LogCategory): Int {
+        val key = EventCountKey(id, event, category)
+        return eventCount[key] ?: 0
+    }
+
+    fun reset() {
+        messageCount.clear()
+        eventCount.clear()
+    }
+}
+
+class BlankActivity : BrowseActivity()
+class BlankSliceBroadcastReceiver : BroadcastReceiver() {
+    override fun onReceive(p0: Context?, p1: Intent?) {}
+}
+
+object SppHome : SettingsPageProvider {
+    override val name = "SppHome"
+
+    override fun getTitle(arguments: Bundle?): String {
+        return "TitleHome"
+    }
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = this.createSettingsPage()
+        return listOf(
+            SppLayer1.buildInject().setLink(fromPage = owner).build(),
+        )
+    }
+}
+
+object SppLayer1 : SettingsPageProvider {
+    override val name = "SppLayer1"
+
+    override fun getTitle(arguments: Bundle?): String {
+        return "TitleLayer1"
+    }
+
+    fun buildInject(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(this.createSettingsPage())
+            .setMacro {
+                SimplePreferenceMacro(
+                    title = "SppHome to Layer1",
+                    clickRoute = name
+                )
+            }
+    }
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = this.createSettingsPage()
+        return listOf(
+            SettingsEntryBuilder.create(owner, "Layer1Entry1").build(),
+            SppLayer2.buildInject().setLink(fromPage = owner).build(),
+            SettingsEntryBuilder.create(owner, "Layer1Entry2").build(),
+        )
+    }
+}
+
+object SppLayer2 : SettingsPageProvider {
+    override val name = "SppLayer2"
+
+    fun buildInject(): SettingsEntryBuilder {
+        return SettingsEntryBuilder.createInject(this.createSettingsPage())
+    }
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = this.createSettingsPage()
+        return listOf(
+            SettingsEntryBuilder.create(owner, "Layer2Entry1")
+                .setSliceDataFn { _, _ ->
+                    return@setSliceDataFn object : EntrySliceData() {
+                        init {
+                            postValue(null)
+                        }
+                    }
+                }
+                .build(),
+            SettingsEntryBuilder.create(owner, "Layer2Entry2").build(),
+        )
+    }
+}
+
+object SppForSearch : SettingsPageProvider {
+    override val name = "SppForSearch"
+
+    override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
+        val owner = this.createSettingsPage()
+        return listOf(
+            SettingsEntryBuilder.create(owner, "SearchStaticWithNoStatus")
+                .setSearchDataFn { EntrySearchData(title = "SearchStaticWithNoStatus") }
+                .build(),
+            SettingsEntryBuilder.create(owner, "SearchStaticWithMutableStatus")
+                .setHasMutableStatus(true)
+                .setSearchDataFn { EntrySearchData(title = "SearchStaticWithMutableStatus") }
+                .setStatusDataFn { EntryStatusData(isSwitchOff = true) }
+                .build(),
+            SettingsEntryBuilder.create(owner, "SearchDynamicWithMutableStatus")
+                .setIsSearchDataDynamic(true)
+                .setHasMutableStatus(true)
+                .setSearchDataFn { EntrySearchData(title = "SearchDynamicWithMutableStatus") }
+                .setStatusDataFn { EntryStatusData(isDisabled = true) }
+                .build(),
+            SettingsEntryBuilder.create(owner, "SearchDynamicWithImmutableStatus")
+                .setIsSearchDataDynamic(true)
+                .setSearchDataFn {
+                    EntrySearchData(
+                        title = "SearchDynamicWithImmutableStatus",
+                        keyword = listOf("kw1", "kw2")
+                    )
+                }
+                .setStatusDataFn { EntryStatusData(isDisabled = true) }
+                .build(),
+        )
+    }
+}
+
+class SpaEnvironmentForTest(
+    context: Context,
+    rootPages: List<SettingsPage> = emptyList(),
+    override val browseActivityClass: Class<out Activity>? = BlankActivity::class.java,
+    override val sliceBroadcastReceiverClass: Class<out BroadcastReceiver>? =
+        BlankSliceBroadcastReceiver::class.java,
+    override val logger: SpaLogger = object : SpaLogger {}
+) : SpaEnvironment(context) {
+
+    override val pageProviderRepository = lazy {
+        SettingsPageProviderRepository(
+            listOf(
+                SppHome, SppLayer1, SppLayer2,
+                SppForSearch,
+                object : SettingsPageProvider {
+                    override val name = "SppWithParam"
+                    override val parameter = listOf(
+                        navArgument("string_param") { type = NavType.StringType },
+                        navArgument("int_param") { type = NavType.IntType },
+                    )
+                },
+                object : SettingsPageProvider {
+                    override val name = "SppWithRtParam"
+                    override val parameter = listOf(
+                        navArgument("string_param") { type = NavType.StringType },
+                        navArgument("int_param") { type = NavType.IntType },
+                        navArgument("rt_param") { type = NavType.StringType },
+                    )
+                },
+            ),
+            rootPages
+        )
+    }
+
+    fun createPage(sppName: String, arguments: Bundle? = null): SettingsPage {
+        return pageProviderRepository.value
+            .getProviderOrNull(sppName)!!.createSettingsPage(arguments)
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt
new file mode 100644
index 0000000..7e51fea
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/tests/testutils/UniqueIdHelper.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.tests.testutils
+
+import android.os.Bundle
+import androidx.navigation.NamedNavArgument
+import com.android.settingslib.spa.framework.common.SettingsPage
+import com.android.settingslib.spa.framework.common.toHashId
+import com.android.settingslib.spa.framework.util.normalize
+
+fun getUniquePageId(
+    name: String,
+    parameter: List<NamedNavArgument> = emptyList(),
+    arguments: Bundle? = null
+): String {
+    val normArguments = parameter.normalize(arguments)
+    return "$name:${normArguments?.toString()}".toHashId()
+}
+
+fun getUniquePageId(page: SettingsPage): String {
+    return getUniquePageId(page.sppName, page.parameter, page.arguments)
+}
+
+fun getUniqueEntryId(
+    name: String,
+    owner: SettingsPage,
+    fromPage: SettingsPage? = null,
+    toPage: SettingsPage? = null
+): String {
+    val ownerId = getUniquePageId(owner)
+    val fromId = if (fromPage == null) "null" else getUniquePageId(fromPage)
+    val toId = if (toPage == null) "null" else getUniquePageId(toPage)
+    return "$name:$ownerId($fromId-$toId)".toHashId()
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ChartTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ChartTest.kt
deleted file mode 100644
index fa7a98a..0000000
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/ChartTest.kt
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.widget
-
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.semantics.SemanticsPropertyKey
-import androidx.compose.ui.semantics.SemanticsPropertyReceiver
-import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.widget.chart.BarChart
-import com.android.settingslib.spa.widget.chart.BarChartData
-import com.android.settingslib.spa.widget.chart.LineChart
-import com.android.settingslib.spa.widget.chart.LineChartData
-import com.android.settingslib.spa.widget.chart.PieChart
-import com.android.settingslib.spa.widget.chart.PieChartData
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class ChartTest {
-    @get:Rule
-    val composeTestRule = createComposeRule()
-
-    private val Chart = SemanticsPropertyKey<String>("Chart")
-    private var SemanticsPropertyReceiver.chart by Chart
-    private fun hasChart(chart: String): SemanticsMatcher =
-        SemanticsMatcher.expectValue(Chart, chart)
-
-    @Test
-    fun line_chart_displayed() {
-        composeTestRule.setContent {
-            LineChart(
-                chartDataList = listOf(
-                    LineChartData(x = 0f, y = 0f),
-                    LineChartData(x = 1f, y = 0.1f),
-                    LineChartData(x = 2f, y = 0.2f),
-                    LineChartData(x = 3f, y = 0.7f),
-                    LineChartData(x = 4f, y = 0.9f),
-                    LineChartData(x = 5f, y = 1.0f),
-                    LineChartData(x = 6f, y = 0.8f),
-                ),
-                modifier = Modifier.semantics { chart = "line" }
-            )
-        }
-
-        composeTestRule.onNode(hasChart("line")).assertIsDisplayed()
-    }
-
-    @Test
-    fun bar_chart_displayed() {
-        composeTestRule.setContent {
-            BarChart(
-                chartDataList = listOf(
-                    BarChartData(x = 0f, y = 12f),
-                    BarChartData(x = 1f, y = 5f),
-                    BarChartData(x = 2f, y = 21f),
-                    BarChartData(x = 3f, y = 5f),
-                    BarChartData(x = 4f, y = 10f),
-                    BarChartData(x = 5f, y = 9f),
-                    BarChartData(x = 6f, y = 1f),
-                ),
-                yAxisMaxValue = 30f,
-                modifier = Modifier.semantics { chart = "bar" }
-            )
-        }
-
-        composeTestRule.onNode(hasChart("bar")).assertIsDisplayed()
-    }
-
-    @Test
-    fun pie_chart_displayed() {
-        composeTestRule.setContent {
-            PieChart(
-                chartDataList = listOf(
-                    PieChartData(label = "Settings", value = 20f),
-                    PieChartData(label = "Chrome", value = 5f),
-                    PieChartData(label = "Gmail", value = 3f),
-                ),
-                centerText = "Today",
-                modifier = Modifier.semantics { chart = "pie" }
-            )
-        }
-
-        composeTestRule.onNode(hasChart("pie")).assertIsDisplayed()
-    }
-}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
deleted file mode 100644
index 54abec9..0000000
--- a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/IllustrationTest.kt
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.settingslib.spa.widget
-
-import androidx.annotation.DrawableRes
-import androidx.annotation.RawRes
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.semantics.SemanticsPropertyKey
-import androidx.compose.ui.semantics.SemanticsPropertyReceiver
-import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.test.SemanticsMatcher
-import androidx.compose.ui.test.assertIsDisplayed
-import androidx.compose.ui.test.assertIsNotDisplayed
-import androidx.compose.ui.test.filterToOne
-import androidx.compose.ui.test.hasAnyAncestor
-import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.settingslib.spa.tests.R
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class IllustrationTest {
-    @get:Rule
-    val composeTestRule = createComposeRule()
-
-    private val DrawableId = SemanticsPropertyKey<Int>("DrawableResId")
-    private var SemanticsPropertyReceiver.drawableId by DrawableId
-
-    @Test
-    fun image_displayed() {
-        val resId = R.drawable.accessibility_captioning_banner
-        composeTestRule.setContent {
-            Illustration(
-                resId = resId,
-                resourceType = ResourceType.IMAGE,
-                modifier = Modifier.semantics { drawableId = resId }
-            )
-        }
-
-        fun hasDrawable(@DrawableRes id: Int): SemanticsMatcher =
-            SemanticsMatcher.expectValue(DrawableId, id)
-
-        val isIllustrationNode = hasAnyAncestor(hasDrawable(resId))
-        composeTestRule.onAllNodes(hasDrawable(resId))
-            .filterToOne(isIllustrationNode)
-            .assertIsDisplayed()
-    }
-
-    private val RawId = SemanticsPropertyKey<Int>("RawResId")
-    private var SemanticsPropertyReceiver.rawId by RawId
-
-    @Test
-    fun empty_lottie_not_displayed() {
-        val resId = R.raw.empty
-        composeTestRule.setContent {
-            Illustration(
-                resId = resId,
-                resourceType = ResourceType.LOTTIE,
-                modifier = Modifier.semantics { rawId = resId }
-            )
-        }
-
-        fun hasRaw(@RawRes id: Int): SemanticsMatcher =
-            SemanticsMatcher.expectValue(RawId, id)
-
-        val isIllustrationNode = hasAnyAncestor(hasRaw(resId))
-        composeTestRule.onAllNodes(hasRaw(resId))
-            .filterToOne(isIllustrationNode)
-            .assertIsNotDisplayed()
-    }
-}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
new file mode 100644
index 0000000..2230d6c
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/chart/ChartTest.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.chart
+
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.SemanticsPropertyKey
+import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ChartTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val chart = SemanticsPropertyKey<String>("Chart")
+    private var SemanticsPropertyReceiver.chart by chart
+    private fun hasChart(chart: String): SemanticsMatcher =
+        SemanticsMatcher.expectValue(this.chart, chart)
+
+    @Test
+    fun line_chart_displayed() {
+        composeTestRule.setContent {
+            LineChart(
+                chartDataList = listOf(
+                    LineChartData(x = 0f, y = 0f),
+                    LineChartData(x = 1f, y = 0.1f),
+                    LineChartData(x = 2f, y = 0.2f),
+                    LineChartData(x = 3f, y = 0.7f),
+                    LineChartData(x = 4f, y = 0.9f),
+                    LineChartData(x = 5f, y = 1.0f),
+                    LineChartData(x = 6f, y = 0.8f),
+                ),
+                modifier = Modifier.semantics { chart = "line" }
+            )
+        }
+
+        composeTestRule.onNode(hasChart("line")).assertIsDisplayed()
+    }
+
+    @Test
+    fun bar_chart_displayed() {
+        composeTestRule.setContent {
+            BarChart(
+                chartDataList = listOf(
+                    BarChartData(x = 0f, y = 12f),
+                    BarChartData(x = 1f, y = 5f),
+                    BarChartData(x = 2f, y = 21f),
+                    BarChartData(x = 3f, y = 5f),
+                    BarChartData(x = 4f, y = 10f),
+                    BarChartData(x = 5f, y = 9f),
+                    BarChartData(x = 6f, y = 1f),
+                ),
+                yAxisMaxValue = 30f,
+                modifier = Modifier.semantics { chart = "bar" }
+            )
+        }
+
+        composeTestRule.onNode(hasChart("bar")).assertIsDisplayed()
+    }
+
+    @Test
+    fun pie_chart_displayed() {
+        composeTestRule.setContent {
+            PieChart(
+                chartDataList = listOf(
+                    PieChartData(label = "Settings", value = 20f),
+                    PieChartData(label = "Chrome", value = 5f),
+                    PieChartData(label = "Gmail", value = 3f),
+                ),
+                centerText = "Today",
+                modifier = Modifier.semantics { chart = "pie" }
+            )
+        }
+
+        composeTestRule.onNode(hasChart("pie")).assertIsDisplayed()
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/illustration/IllustrationTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/illustration/IllustrationTest.kt
new file mode 100644
index 0000000..77c505d
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/illustration/IllustrationTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.illustration
+
+import androidx.annotation.DrawableRes
+import androidx.annotation.RawRes
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.semantics.SemanticsPropertyKey
+import androidx.compose.ui.semantics.SemanticsPropertyReceiver
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.test.SemanticsMatcher
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
+import androidx.compose.ui.test.filterToOne
+import androidx.compose.ui.test.hasAnyAncestor
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.tests.R
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class IllustrationTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val drawableId = SemanticsPropertyKey<Int>("DrawableResId")
+    private var SemanticsPropertyReceiver.drawableId by drawableId
+
+    @Test
+    fun image_displayed() {
+        val resId = R.drawable.accessibility_captioning_banner
+        composeTestRule.setContent {
+            Illustration(
+                resId = resId,
+                resourceType = ResourceType.IMAGE,
+                modifier = Modifier.semantics { drawableId = resId }
+            )
+        }
+
+        fun hasDrawable(@DrawableRes id: Int): SemanticsMatcher =
+            SemanticsMatcher.expectValue(drawableId, id)
+
+        val isIllustrationNode = hasAnyAncestor(hasDrawable(resId))
+        composeTestRule.onAllNodes(hasDrawable(resId))
+            .filterToOne(isIllustrationNode)
+            .assertIsDisplayed()
+    }
+
+    private val rawId = SemanticsPropertyKey<Int>("RawResId")
+    private var SemanticsPropertyReceiver.rawId by rawId
+
+    @Test
+    fun empty_lottie_not_displayed() {
+        val resId = R.raw.empty
+        composeTestRule.setContent {
+            Illustration(
+                resId = resId,
+                resourceType = ResourceType.LOTTIE,
+                modifier = Modifier.semantics { rawId = resId }
+            )
+        }
+
+        fun hasRaw(@RawRes id: Int): SemanticsMatcher =
+            SemanticsMatcher.expectValue(rawId, id)
+
+        val isIllustrationNode = hasAnyAncestor(hasRaw(resId))
+        composeTestRule.onAllNodes(hasRaw(resId))
+            .filterToOne(isIllustrationNode)
+            .assertIsNotDisplayed()
+    }
+}
diff --git a/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/HomeScaffoldTest.kt b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/HomeScaffoldTest.kt
new file mode 100644
index 0000000..6ccbbd0
--- /dev/null
+++ b/packages/SettingsLib/Spa/tests/src/com/android/settingslib/spa/widget/scaffold/HomeScaffoldTest.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.widget.scaffold
+
+import androidx.compose.material3.Text
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class HomeScaffoldTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun title_isDisplayed() {
+        composeTestRule.setContent {
+            HomeScaffold(title = TITLE) {
+                Text(text = "AAA")
+                Text(text = "BBB")
+            }
+        }
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+    }
+
+    @Test
+    fun items_areDisplayed() {
+        composeTestRule.setContent {
+            HomeScaffold(title = TITLE) {
+                Text(text = "AAA")
+                Text(text = "BBB")
+            }
+        }
+
+        composeTestRule.onNodeWithText("AAA").assertIsDisplayed()
+        composeTestRule.onNodeWithText("BBB").assertIsDisplayed()
+    }
+
+    private companion object {
+        const val TITLE = "title"
+    }
+}
diff --git a/packages/SettingsLib/Spa/testutils/Android.bp b/packages/SettingsLib/Spa/testutils/Android.bp
index 0f618fa..2c1e1c2 100644
--- a/packages/SettingsLib/Spa/testutils/Android.bp
+++ b/packages/SettingsLib/Spa/testutils/Android.bp
@@ -24,6 +24,9 @@
     srcs: ["src/**/*.kt"],
 
     static_libs: [
+        "SpaLib",
+        "androidx.arch.core_core-testing",
+        "androidx.compose.runtime_runtime",
         "androidx.compose.ui_ui-test-junit4",
         "androidx.compose.ui_ui-test-manifest",
         "mockito",
diff --git a/packages/SettingsLib/Spa/testutils/build.gradle b/packages/SettingsLib/Spa/testutils/build.gradle
index 58b4d42..e31eb02 100644
--- a/packages/SettingsLib/Spa/testutils/build.gradle
+++ b/packages/SettingsLib/Spa/testutils/build.gradle
@@ -44,9 +44,18 @@
         jvmTarget = '1.8'
         freeCompilerArgs = ["-Xjvm-default=all"]
     }
+    buildFeatures {
+        compose true
+    }
+    composeOptions {
+        kotlinCompilerExtensionVersion jetpack_compose_compiler_version
+    }
 }
 
 dependencies {
+    api project(":SpaLib")
+
+    api "androidx.arch.core:core-testing:2.1.0"
     api "androidx.compose.ui:ui-test-junit4:$jetpack_compose_version"
     api "com.google.truth:truth:1.1.3"
     api "org.mockito:mockito-core:2.21.0"
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FakeNavControllerWrapper.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FakeNavControllerWrapper.kt
new file mode 100644
index 0000000..5a3044d
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FakeNavControllerWrapper.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.testutils
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import com.android.settingslib.spa.framework.compose.LocalNavController
+import com.android.settingslib.spa.framework.compose.NavControllerWrapper
+
+class FakeNavControllerWrapper : NavControllerWrapper {
+    var navigateCalledWith: String? = null
+    var navigateBackIsCalled = false
+
+    override fun navigate(route: String) {
+        navigateCalledWith = route
+    }
+
+    override fun navigateBack() {
+        navigateBackIsCalled = true
+    }
+
+    @Composable
+    fun Wrapper(content: @Composable () -> Unit) {
+        CompositionLocalProvider(LocalNavController provides this) {
+            content()
+        }
+    }
+}
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FlowTestUtil.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FlowTestUtil.kt
new file mode 100644
index 0000000..7a11499
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/FlowTestUtil.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.testutils
+
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.withTimeoutOrNull
+
+suspend fun <T> Flow<T>.firstWithTimeoutOrNull(timeMillis: Long = 500): T? =
+    withTimeoutOrNull(timeMillis) {
+        first()
+    }
diff --git a/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt
new file mode 100644
index 0000000..dddda55
--- /dev/null
+++ b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/LiveDataTestUtil.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spa.testutils
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.Observer
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+fun <T> LiveData<T>.getOrAwaitValue(
+    timeout: Long = 1,
+    timeUnit: TimeUnit = TimeUnit.SECONDS,
+    afterObserve: () -> Unit = {},
+): T? {
+    var data: T? = null
+    val latch = CountDownLatch(1)
+    val observer = Observer<T> { newData ->
+        data = newData
+        latch.countDown()
+    }
+    this.observeForever(observer)
+
+    afterObserve()
+
+    try {
+        // Don't wait indefinitely if the LiveData is not set.
+        if (!latch.await(timeout, timeUnit)) {
+            throw TimeoutException("LiveData value was never set.")
+        }
+    } finally {
+        this.removeObserver(observer)
+    }
+
+    return data
+}
diff --git a/packages/SettingsLib/Spa/testutils/src/MockitoHelper.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/MockitoHelper.kt
similarity index 100%
rename from packages/SettingsLib/Spa/testutils/src/MockitoHelper.kt
rename to packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/MockitoHelper.kt
diff --git a/packages/SettingsLib/Spa/testutils/src/SpaTest.kt b/packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/SpaTest.kt
similarity index 100%
rename from packages/SettingsLib/Spa/testutils/src/SpaTest.kt
rename to packages/SettingsLib/Spa/testutils/src/com/android/settingslib/spa/testutils/SpaTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml
new file mode 100644
index 0000000..3ad7bb0
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-af/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Geen apps nie."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Wys stelsel"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Versteek stelsel"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Toegelaat"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nie toegelaat nie"</string>
+    <string name="version_text" msgid="4001669804596458577">"weergawe <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml
new file mode 100644
index 0000000..4c2525bfd
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-am/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"መተግበሪያዎች የሉም።"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ሥርዓትን አሳይ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ሥርዓትን ደብቅ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ይፈቀዳል"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"አይፈቀድም"</string>
+    <string name="version_text" msgid="4001669804596458577">"ሥሪት <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml
new file mode 100644
index 0000000..436914d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ar/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ليس هناك أي تطبيقات."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"إظهار عمليات النظام"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"إخفاء عمليات النظام"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"مسموح به"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غير مسموح به"</string>
+    <string name="version_text" msgid="4001669804596458577">"الإصدار <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml
new file mode 100644
index 0000000..c1c88f2
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-as/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"কোনো এপ্‌ নাই।"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ছিষ্টেম দেখুৱাওক"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ছিষ্টেম লুকুৱাওক"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"অনুমতি দিয়া হৈছে"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"অনুমতি নাই"</string>
+    <string name="version_text" msgid="4001669804596458577">"সংস্কৰণ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml
new file mode 100644
index 0000000..4fc090a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-az/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Tətbiq yoxdur."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Sistemi göstərin"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sistemi gizlədin"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"İcazə verildi"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"İcazə verilməyib"</string>
+    <string name="version_text" msgid="4001669804596458577">"versiya <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000..3708503
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nema aplikacija."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Prikaži sistemske"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sakrij sistemske"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozvoljeno"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dozvoljeno"</string>
+    <string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml
new file mode 100644
index 0000000..38fb12b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-be/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Няма праграм."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Паказаць сістэмныя працэсы"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Схаваць сістэмныя працэсы"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дазволена"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Забаронена"</string>
+    <string name="version_text" msgid="4001669804596458577">"версія <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml
new file mode 100644
index 0000000..b9b03bf
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bg/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Няма приложения."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Показване на системните процеси"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Скриване на системните процеси"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Разрешено"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Не е разрешено"</string>
+    <string name="version_text" msgid="4001669804596458577">"версия <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml
new file mode 100644
index 0000000..b805b3c
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"কোনও অ্যাপ নেই।"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"সিস্টেম দেখুন"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"সিস্টেম লুকান"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"অনুমোদিত"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"অননুমোদিত"</string>
+    <string name="version_text" msgid="4001669804596458577">"ভার্সন <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml
new file mode 100644
index 0000000..9ceb340
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-bs/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nema aplikacija."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Prikaži sistemske aplikacije"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sakrij sistemske aplikacije"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozvoljeno"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dozvoljeno"</string>
+    <string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml
new file mode 100644
index 0000000..00cb41b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ca/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No hi ha cap aplicació."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostra el sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Amaga el sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Amb permís"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Sense permís"</string>
+    <string name="version_text" msgid="4001669804596458577">"versió <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml
new file mode 100644
index 0000000..7b28f11
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-cs/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Žádné aplikace"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Zobrazit systémové aplikace"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Skrýt systémové aplikace"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Povoleno"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepovoleno"</string>
+    <string name="version_text" msgid="4001669804596458577">"verze <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml
new file mode 100644
index 0000000..f1893be
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-da/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ingen apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Vis system"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Skjul system"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tilladt"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ikke tilladt"</string>
+    <string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml
new file mode 100644
index 0000000..471a7a7
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-de/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Keine Apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"System-Apps anzeigen"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"System-Apps ausblenden"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Zulässig"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nicht zulässig"</string>
+    <string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml
new file mode 100644
index 0000000..6c46e27
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-el/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Δεν υπάρχουν εφαρμογές."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Εμφάνιση συστήματος"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Απόκρυψη συστήματος"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Επιτρέπεται"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Δεν επιτρέπεται"</string>
+    <string name="version_text" msgid="4001669804596458577">"έκδοση <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000..de48ff1
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rAU/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Show system"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Hide system"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
+    <string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000..de48ff1
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rGB/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Show system"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Hide system"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
+    <string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000..de48ff1
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-en-rIN/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Show system"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Hide system"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Allowed"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Not allowed"</string>
+    <string name="version_text" msgid="4001669804596458577">"Version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000..d211eeb
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-es-rUS/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No hay apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"No se permite"</string>
+    <string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml
new file mode 100644
index 0000000..d907cb8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-es/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"No hay aplicaciones."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"No permitida"</string>
+    <string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml
new file mode 100644
index 0000000..2be2967
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-et/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Rakendusi pole."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Kuva süsteem"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Peida süsteem"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Lubatud"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Pole lubatud"</string>
+    <string name="version_text" msgid="4001669804596458577">"versioon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml
new file mode 100644
index 0000000..7fb2ee28
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-eu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ez dago aplikaziorik."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Erakutsi sistemaren aplikazioak"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ezkutatu sistemaren aplikazioak"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Baimena dauka"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ez dauka baimenik"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> bertsioa"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml
new file mode 100644
index 0000000..7711cac
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fa/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"برنامه‌ای وجود ندارد."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"نمایش سیستم"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"پنهان کردن سیستم"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"مجاز"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"غیرمجاز"</string>
+    <string name="version_text" msgid="4001669804596458577">"نسخه <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml
new file mode 100644
index 0000000..af65bfe
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ei sovelluksia."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Näytä järjestelmä"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Piilota järjestelmä"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Sallittu"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ei sallittu"</string>
+    <string name="version_text" msgid="4001669804596458577">"versio <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000..31f1ee0
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fr-rCA/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Aucune application"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Afficher le système"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Masquer le système"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Autorisé"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non autorisée"</string>
+    <string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml
new file mode 100644
index 0000000..5b7b5e6
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-fr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Aucune appli."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Afficher le système"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Masquer le système"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Autorisé"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non autorisé"</string>
+    <string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml
new file mode 100644
index 0000000..3d1f9d8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-gl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ningunha aplicación"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non permitida"</string>
+    <string name="version_text" msgid="4001669804596458577">"versión <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml
new file mode 100644
index 0000000..c598b70
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-gu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"કોઈ ઍપ નથી."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"સિસ્ટમ બતાવો"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"સિસ્ટમ છુપાવો"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"મંજૂરી છે"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"મંજૂરી નથી"</string>
+    <string name="version_text" msgid="4001669804596458577">"વર્ઝન <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml
new file mode 100644
index 0000000..809afd3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"कोई ऐप्लिकेशन नहीं है."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"सिस्टम के ऐप्लिकेशन दिखाएं"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"सिस्टम के ऐप्लिकेशन छिपाएं"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमति है"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमति नहीं है"</string>
+    <string name="version_text" msgid="4001669804596458577">"वर्शन <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml
new file mode 100644
index 0000000..1a87974
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nema aplikacija."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Prikaži sustav"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sakrij sustav"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dopušteno"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nije dopušteno"</string>
+    <string name="version_text" msgid="4001669804596458577">"verzija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml
new file mode 100644
index 0000000..1ae7cdf
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nincsenek alkalmazások."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Rendszerfolyamatok megjelenítése"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Rendszerfolyamatok elrejtése"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Engedélyezve"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nem engedélyezett"</string>
+    <string name="version_text" msgid="4001669804596458577">"verzió: <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml
new file mode 100644
index 0000000..353af77
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-hy/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Հավելվածներ չկան։"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Ցույց տալ համակարգային գործընթացները"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Թաքցնել համակարգային գործընթացները"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Թույլատրված է"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Արգելված է"</string>
+    <string name="version_text" msgid="4001669804596458577">"տարբերակ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml
new file mode 100644
index 0000000..8b766b0
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-in/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Tidak ada aplikasi."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Tampilkan sistem"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sembunyikan sistem"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Diizinkan"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tidak diizinkan"</string>
+    <string name="version_text" msgid="4001669804596458577">"versi <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml
new file mode 100644
index 0000000..cbd412d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-is/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Engin forrit."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Sýna kerfi"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Fela kerfi"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Leyft"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ekki leyft"</string>
+    <string name="version_text" msgid="4001669804596458577">"útgáfa <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml
new file mode 100644
index 0000000..d83c70d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-it/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nessuna app."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostra sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Nascondi sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Consentita"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Non consentita"</string>
+    <string name="version_text" msgid="4001669804596458577">"versione <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml
new file mode 100644
index 0000000..7ed8a6b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-iw/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"אין אפליקציות."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"הצגת תהליכי מערכת"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"הסתרת תהליכי מערכת"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"יש הרשאה"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"אין הרשאה"</string>
+    <string name="version_text" msgid="4001669804596458577">"גרסה <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml
new file mode 100644
index 0000000..b12cb5c
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ja/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"アプリはありません。"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"システムアプリを表示"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"システムアプリを表示しない"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"許可"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"許可しない"</string>
+    <string name="version_text" msgid="4001669804596458577">"バージョン <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml
new file mode 100644
index 0000000..c01a028
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ka/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"არ არის აპები."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"სისტემის ჩვენება"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"სისტემის დამალვა"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"დაშვებულია"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"დაუშვებელია"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> ვერსია"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml
new file mode 100644
index 0000000..fb94404
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-kk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Қолданба жоқ."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Жүйені көрсету"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Жүйені жасыру"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Рұқсат етілген"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Рұқсат етілмеген"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> нұсқасы"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml
new file mode 100644
index 0000000..610123d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-km/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"គ្មាន​កម្មវិធី។"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"បង្ហាញ​ប្រព័ន្ធ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"លាក់ប្រព័ន្ធ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"បាន​អនុញ្ញាត"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"មិន​អនុញ្ញាត​ទេ"</string>
+    <string name="version_text" msgid="4001669804596458577">"កំណែ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml
new file mode 100644
index 0000000..b61c008
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-kn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ಯಾವುದೇ ಆ್ಯಪ್‍‍ಗಳಿಲ್ಲ."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ಸಿಸ್ಟಂ ತೋರಿಸಿ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ಸಿಸ್ಟಂ ಮರೆಮಾಡಿ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ಅನುಮತಿಸಲಾಗಿದೆ"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ಅನುಮತಿಸಲಾಗುವುದಿಲ್ಲ"</string>
+    <string name="version_text" msgid="4001669804596458577">"ಆವೃತ್ತಿ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml
new file mode 100644
index 0000000..660dc0e
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ko/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"앱 없음"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"시스템 표시"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"시스템 숨기기"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"허용됨"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"허용되지 않음"</string>
+    <string name="version_text" msgid="4001669804596458577">"버전 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml
new file mode 100644
index 0000000..898ec09
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ky/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Бир дагы колдонмо жок."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Системаны көрсөтүү"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Системаны жашыруу"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Уруксат берилген"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Тыюу салынган"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> версиясы"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml
new file mode 100644
index 0000000..d0f77e4
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lo/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ບໍ່ມີແອັບ."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ສະແດງລະບົບ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ເຊື່ອງລະບົບ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ອະນຸຍາດແລ້ວ"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ບໍ່ໄດ້ອະນຸຍາດ"</string>
+    <string name="version_text" msgid="4001669804596458577">"ເວີຊັນ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml
new file mode 100644
index 0000000..7d33f91
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nėra programų"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Rodyti sistemą"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Slėpti sistemą"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Leidžiama"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Neleidžiama"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> versija"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml
new file mode 100644
index 0000000..66dc44d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-lv/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nav lietotņu."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Rādīt sistēmas procesus"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Slēpt sistēmas procesus"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Atļauja piešķirta"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Atļauja nav piešķirta"</string>
+    <string name="version_text" msgid="4001669804596458577">"versija <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml
new file mode 100644
index 0000000..db55600
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Нема апликации."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Прикажи го системот"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Сокриј го системот"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Со дозволен пристап"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Без дозволен пристап"</string>
+    <string name="version_text" msgid="4001669804596458577">"верзија <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml
new file mode 100644
index 0000000..c99d0d3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ml/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ആപ്പുകളൊന്നുമില്ല."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"സിസ്‌റ്റം കാണിക്കുക"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"സിസ്‌റ്റം മറയ്ക്കുക"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"അനുവാദം ലഭിച്ചു"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"അനുവാദം ലഭിച്ചില്ല"</string>
+    <string name="version_text" msgid="4001669804596458577">"പതിപ്പ് <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml
new file mode 100644
index 0000000..bc0864b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mn/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Апп байхгүй."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Системийг харуулах"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Системийг нуух"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Зөвшөөрсөн"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Зөвшөөрөөгүй"</string>
+    <string name="version_text" msgid="4001669804596458577">"хувилбар <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml
new file mode 100644
index 0000000..55a178b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-mr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"अ‍ॅप्स नाहीत."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"सिस्टीम दाखवा"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"सिस्टीम लपवा"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमती असलेले"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमती नाही"</string>
+    <string name="version_text" msgid="4001669804596458577">"आवृत्ती <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml
new file mode 100644
index 0000000..a736de9
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ms/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Tiada aplikasi."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Tunjukkan sistem"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sembunyikan sistem"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dibenarkan"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tidak dibenarkan"</string>
+    <string name="version_text" msgid="4001669804596458577">"versi <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml
new file mode 100644
index 0000000..3bed608
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-my/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"အက်ပ်မရှိပါ။"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"စနစ်ကိုပြပါ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"စနစ်ကိုဖျောက်ထားရန်"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ခွင့်ပြုထားသည်"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ခွင့်ပြုမထားပါ"</string>
+    <string name="version_text" msgid="4001669804596458577">"ဗားရှင်း <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml
new file mode 100644
index 0000000..d6bd063
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-nb/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ingen apper."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Vis systemprosesser"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Skjul systemprosesser"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tillatt"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ikke tillatt"</string>
+    <string name="version_text" msgid="4001669804596458577">"versjon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml
new file mode 100644
index 0000000..97db4ea
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ne/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"कुनै पनि एप छैन।"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"सिस्टम देखाइयोस्"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"सिस्टम लुकाइयोस्"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"अनुमति दिइएका एप"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"अनुमति नदिइएका एप"</string>
+    <string name="version_text" msgid="4001669804596458577">"संस्करण <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml
new file mode 100644
index 0000000..7157e3f
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-nl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Geen apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Systeem-apps tonen"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Systeem-apps verbergen"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Toegestaan"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Niet toegestaan"</string>
+    <string name="version_text" msgid="4001669804596458577">"versie <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml
new file mode 100644
index 0000000..24779e3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-or/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"କୌଣସି ଆପ୍ସ ନାହିଁ।"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ସିଷ୍ଟମ ଦେଖାନ୍ତୁ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ସିଷ୍ଟମକୁ ଲୁଚାନ୍ତୁ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ଅନୁମତି ଦିଆଯାଇଛି"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ଅନୁମତି ଦିଆଯାଇନାହିଁ"</string>
+    <string name="version_text" msgid="4001669804596458577">"ଭର୍ସନ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml
new file mode 100644
index 0000000..fe1a3eb
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pa/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ਕੋਈ ਐਪ ਨਹੀਂ।"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"ਸਿਸਟਮ ਦਿਖਾਓ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ਸਿਸਟਮ ਲੁਕਾਓ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ਆਗਿਆ ਹੈ"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ਆਗਿਆ ਨਹੀਂ ਹੈ"</string>
+    <string name="version_text" msgid="4001669804596458577">"ਵਰਜਨ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml
new file mode 100644
index 0000000..9d5ba9d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Brak aplikacji."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Pokaż systemowe"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ukryj systemowe"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dozwolone"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Niedozwolone"</string>
+    <string name="version_text" msgid="4001669804596458577">"wersja <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml
new file mode 100644
index 0000000..18a31d8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt-rBR/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nenhum app."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitido"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitido"</string>
+    <string name="version_text" msgid="4001669804596458577">"Versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000..ddf5e51
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt-rPT/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Sem apps."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitida"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitida"</string>
+    <string name="version_text" msgid="4001669804596458577">"versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml
new file mode 100644
index 0000000..18a31d8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-pt/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nenhum app."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Mostrar sistema"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ocultar sistema"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permitido"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Não permitido"</string>
+    <string name="version_text" msgid="4001669804596458577">"Versão <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml
new file mode 100644
index 0000000..ef58fb8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ro/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Nu există aplicații."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Afișează procesele de sistem"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ascunde procesele de sistem"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Permisă"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepermisă"</string>
+    <string name="version_text" msgid="4001669804596458577">"versiunea <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml
new file mode 100644
index 0000000..6d69c80
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ru/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Нет приложений."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Показать системные процессы"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Скрыть системные процессы"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Разрешено"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Запрещено"</string>
+    <string name="version_text" msgid="4001669804596458577">"версия <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml
new file mode 100644
index 0000000..d2c20e6
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-si/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"යෙදුම් නොමැත."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"පද්ධතිය පෙන්වන්න"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"පද්ධතිය සඟවන්න"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"ඉඩ දුන්"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ඉඩ නොදෙන"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> අනුවාදය"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml
new file mode 100644
index 0000000..0d0984f
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Žiadne aplikácie."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Zobraziť systémové procesy"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Skryť systémové procesy"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Povolené"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nepovolené"</string>
+    <string name="version_text" msgid="4001669804596458577">"verzia <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml
new file mode 100644
index 0000000..c8bd15a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Ni aplikacij."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Prikaži sistemske procese"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Skrij sistemske procese"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Dovoljeno"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ni dovoljeno"</string>
+    <string name="version_text" msgid="4001669804596458577">"različica <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml
new file mode 100644
index 0000000..112868a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sq/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Asnjë aplikacion"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Shfaq sistemin"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Fshih sistemin"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Lejohet"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Nuk lejohet"</string>
+    <string name="version_text" msgid="4001669804596458577">"versioni <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml
new file mode 100644
index 0000000..4c99d60
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Нема апликација."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Прикажи системске"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Сакриј системске"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дозвољено"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Није дозвољено"</string>
+    <string name="version_text" msgid="4001669804596458577">"верзија <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml
new file mode 100644
index 0000000..1dd5efd
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sv/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Inga appar."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Visa systemet"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Dölj systemet"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Tillåts"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Tillåts inte"</string>
+    <string name="version_text" msgid="4001669804596458577">"version <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml
new file mode 100644
index 0000000..a0ee70c
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-sw/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Hakuna programu yoyote."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Onyesha mfumo"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ficha mfumo"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Inaruhusiwa"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Hairuhusiwi"</string>
+    <string name="version_text" msgid="4001669804596458577">"toleo la <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml
new file mode 100644
index 0000000..36d64e8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ta/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ஆப்ஸ் இல்லை."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"சிஸ்டம் ஆப்ஸைக் காட்டு"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"சிஸ்டம் ஆப்ஸை மறை"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"அனுமதிக்கப்பட்டது"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"அனுமதிக்கப்படவில்லை"</string>
+    <string name="version_text" msgid="4001669804596458577">"பதிப்பு <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml
new file mode 100644
index 0000000..a908dd4
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-te/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"యాప్‌లు ఏవి లేవు."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"సిస్టమ్ ప్రాసెస్‌లను చూపించండి"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"సిస్టమ్‌ను దాచండి"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"అనుమతించబడినవి"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"అనుమతించబడలేదు"</string>
+    <string name="version_text" msgid="4001669804596458577">"వెర్షన్ <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml
new file mode 100644
index 0000000..1d7db1a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-th/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"ไม่มีแอป"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"แสดงระบบ"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"ซ่อนระบบ"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"อนุญาต"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"ไม่อนุญาต"</string>
+    <string name="version_text" msgid="4001669804596458577">"เวอร์ชัน <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml
new file mode 100644
index 0000000..fb56559a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-tl/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Walang app."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Ipakita ang system"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Itago ang system"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Pinapahintulutan"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Hindi pinapahintulutan"</string>
+    <string name="version_text" msgid="4001669804596458577">"bersyon <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml
new file mode 100644
index 0000000..5f5722b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-tr/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Uygulama yok"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Sistemi göster"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Sistemi gizle"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"İzin veriliyor"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"İzin verilmiyor"</string>
+    <string name="version_text" msgid="4001669804596458577">"sürüm: <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml
new file mode 100644
index 0000000..a8632ca
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-uk/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Додатків немає."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Показати системні додатки"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Сховати системні додатки"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Дозволено"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Заборонено"</string>
+    <string name="version_text" msgid="4001669804596458577">"версія <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml
new file mode 100644
index 0000000..4b969bb
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-ur/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"کوئی ایپ نہیں ہے۔"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"سسٹم دکھائیں"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"سسٹم چھپائیں"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"اجازت ہے"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"اجازت نہیں ہے"</string>
+    <string name="version_text" msgid="4001669804596458577">"ورژن <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-uz/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-uz/strings.xml
new file mode 100644
index 0000000..aed34e6
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-uz/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Hech narsa topilmadi."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Tizimga oid jarayonlar"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Tizimga oid jarayonlarni berkitish"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Ruxsat berilgan"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Ruxsat berilmagan"</string>
+    <string name="version_text" msgid="4001669804596458577">"<xliff:g id="VERSION_NUM">%1$s</xliff:g> versiya"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml
new file mode 100644
index 0000000..75700c7
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-vi/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Không có ứng dụng nào."</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Hiện hệ thống"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Ẩn hệ thống"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Được phép"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Không được phép"</string>
+    <string name="version_text" msgid="4001669804596458577">"phiên bản <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000..2c864cb
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rCN/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"没有应用。"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"显示系统进程"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"隐藏系统进程"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"已允许"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允许"</string>
+    <string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000..667a10a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rHK/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"沒有應用程式。"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"顯示系統程序"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"隱藏系統程序"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"允許"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允許"</string>
+    <string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000..667a10a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zh-rTW/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"沒有應用程式。"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"顯示系統程序"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"隱藏系統程序"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"允許"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"不允許"</string>
+    <string name="version_text" msgid="4001669804596458577">"版本 <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml b/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml
new file mode 100644
index 0000000..d3a614a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/res/values-zu/strings.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="no_applications" msgid="5800789569715871963">"Awekho ama-app"</string>
+    <string name="menu_show_system" msgid="906304605807554788">"Bonisa isistimu"</string>
+    <string name="menu_hide_system" msgid="374571689914923020">"Fihla isistimu"</string>
+    <string name="app_permission_summary_allowed" msgid="6115213465364138103">"Kuvumelekile"</string>
+    <string name="app_permission_summary_not_allowed" msgid="58396132188553920">"Akuvumelekile"</string>
+    <string name="version_text" msgid="4001669804596458577">"Uhlobo <xliff:g id="VERSION_NUM">%1$s</xliff:g>"</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
index bb1cd6e..76f6611 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/framework/common/Contexts.kt
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.spaprivileged.framework.common
 
+import android.app.ActivityManager
 import android.app.AlarmManager
 import android.app.AppOpsManager
 import android.app.admin.DevicePolicyManager
@@ -28,6 +29,9 @@
 import android.os.UserManager
 import android.permission.PermissionControllerManager
 
+/** The [ActivityManager] instance. */
+val Context.activityManager get() = getSystemService(ActivityManager::class.java)!!
+
 /** The [AlarmManager] instance. */
 val Context.alarmManager get() = getSystemService(AlarmManager::class.java)!!
 
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
index a7122d0..6999908 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListModel.kt
@@ -33,7 +33,8 @@
      *
      * @return the [AppRecord] list which will be displayed.
      */
-    fun filter(userIdFlow: Flow<Int>, option: Int, recordListFlow: Flow<List<T>>): Flow<List<T>>
+    fun filter(userIdFlow: Flow<Int>, option: Int, recordListFlow: Flow<List<T>>): Flow<List<T>> =
+        recordListFlow
 
     /**
      * This function is called when the App List's loading is finished and displayed to the user.
@@ -67,5 +68,5 @@
      * @return null if no summary should be displayed.
      */
     @Composable
-    fun getSummary(option: Int, record: T): State<String>?
+    fun getSummary(option: Int, record: T): State<String>? = null
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
index 487dbcb..4c144b2 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppListRepository.kt
@@ -29,7 +29,7 @@
 /**
  * The config used to load the App List.
  */
-internal data class AppListConfig(
+data class AppListConfig(
     val userId: Int,
     val showInstantApps: Boolean,
 )
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
index 71cf23c..c08169e 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/app/AppOpsController.kt
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.spaprivileged.model.app
 
-import android.app.AppOpsManager
 import android.app.AppOpsManager.MODE_ALLOWED
 import android.app.AppOpsManager.MODE_ERRORED
 import android.app.AppOpsManager.Mode
@@ -25,34 +24,41 @@
 import androidx.lifecycle.LiveData
 import androidx.lifecycle.MutableLiveData
 import androidx.lifecycle.map
+import com.android.settingslib.spaprivileged.framework.common.appOpsManager
+
+interface IAppOpsController {
+    val mode: LiveData<Int>
+    val isAllowed: LiveData<Boolean>
+        get() = mode.map { it == MODE_ALLOWED }
+
+    fun setAllowed(allowed: Boolean)
+
+    @Mode
+    fun getMode(): Int
+}
 
 class AppOpsController(
     context: Context,
     private val app: ApplicationInfo,
     private val op: Int,
-) {
-    private val appOpsManager = checkNotNull(context.getSystemService(AppOpsManager::class.java))
+) : IAppOpsController {
+    private val appOpsManager = context.appOpsManager
 
-    val mode: LiveData<Int>
+    override val mode: LiveData<Int>
         get() = _mode
-    val isAllowed: LiveData<Boolean>
-        get() = _mode.map { it == MODE_ALLOWED }
 
-    fun setAllowed(allowed: Boolean) {
+    override fun setAllowed(allowed: Boolean) {
         val mode = if (allowed) MODE_ALLOWED else MODE_ERRORED
         appOpsManager.setMode(op, app.uid, app.packageName, mode)
         _mode.postValue(mode)
     }
 
     @Mode
-    fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
+    override fun getMode(): Int = appOpsManager.checkOpNoThrow(op, app.uid, app.packageName)
 
     private val _mode = object : MutableLiveData<Int>() {
         override fun onActive() {
             postValue(getMode())
         }
-
-        override fun onInactive() {
-        }
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
index b1adc9d..ae362c8 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictionsProvider.kt
@@ -20,27 +20,41 @@
 import android.content.Context
 import android.os.UserHandle
 import android.os.UserManager
-import androidx.lifecycle.liveData
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.lifecycle.compose.ExperimentalLifecycleComposeApi
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
+import com.android.settingslib.RestrictedLockUtils
 import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin
 import com.android.settingslib.RestrictedLockUtilsInternal
 import com.android.settingslib.spaprivileged.R
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOn
 
 data class Restrictions(
     val userId: Int,
     val keys: List<String>,
 )
 
-sealed class RestrictedMode
+sealed interface RestrictedMode
 
-object NoRestricted : RestrictedMode()
+object NoRestricted : RestrictedMode
 
-object BaseUserRestricted : RestrictedMode()
+object BaseUserRestricted : RestrictedMode
 
-data class BlockedByAdmin(
-    val enterpriseRepository: EnterpriseRepository,
-    val enforcedAdmin: EnforcedAdmin,
-) : RestrictedMode() {
-    fun getSummary(checked: Boolean?): String = when (checked) {
+interface BlockedByAdmin : RestrictedMode {
+    fun getSummary(checked: Boolean?): String
+    fun sendShowAdminSupportDetailsIntent()
+}
+
+private data class BlockedByAdminImpl(
+    private val context: Context,
+    private val enforcedAdmin: EnforcedAdmin,
+) : BlockedByAdmin {
+    private val enterpriseRepository by lazy { EnterpriseRepository(context) }
+
+    override fun getSummary(checked: Boolean?) = when (checked) {
         true -> enterpriseRepository.getEnterpriseString(
             Settings.ENABLED_BY_ADMIN_SWITCH_SUMMARY, R.string.enabled_by_admin
         )
@@ -49,18 +63,33 @@
         )
         else -> ""
     }
+
+    override fun sendShowAdminSupportDetailsIntent() {
+        RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, enforcedAdmin)
+    }
 }
 
-class RestrictionsProvider(
+interface RestrictionsProvider {
+    @Composable
+    fun restrictedModeState(): State<RestrictedMode?>
+}
+
+typealias RestrictionsProviderFactory = (Context, Restrictions) -> RestrictionsProvider
+
+internal class RestrictionsProviderImpl(
     private val context: Context,
     private val restrictions: Restrictions,
-) {
+) : RestrictionsProvider {
     private val userManager by lazy { UserManager.get(context) }
-    private val enterpriseRepository by lazy { EnterpriseRepository(context) }
 
-    val restrictedMode = liveData {
+    private val restrictedMode = flow {
         emit(getRestrictedMode())
-    }
+    }.flowOn(Dispatchers.IO)
+
+    @OptIn(ExperimentalLifecycleComposeApi::class)
+    @Composable
+    override fun restrictedModeState() =
+        restrictedMode.collectAsStateWithLifecycle(initialValue = null)
 
     private fun getRestrictedMode(): RestrictedMode {
         for (key in restrictions.keys) {
@@ -71,12 +100,7 @@
         for (key in restrictions.keys) {
             RestrictedLockUtilsInternal
                 .checkIfRestrictionEnforced(context, key, restrictions.userId)
-                ?.let {
-                    return BlockedByAdmin(
-                        enterpriseRepository = enterpriseRepository,
-                        enforcedAdmin = it,
-                    )
-                }
+                ?.let { return BlockedByAdminImpl(context = context, enforcedAdmin = it) }
         }
         return NoRestricted
     }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
index 8b19c5b..0b45da6 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppInfoPage.kt
@@ -16,11 +16,12 @@
 
 package com.android.settingslib.spaprivileged.template.app
 
+import android.content.pm.PackageInfo
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.remember
 import com.android.settingslib.spa.widget.scaffold.RegularScaffold
 import com.android.settingslib.spa.widget.ui.Footer
-import com.android.settingslib.spaprivileged.model.app.PackageManagers
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 
 @Composable
 fun AppInfoPage(
@@ -28,18 +29,16 @@
     packageName: String,
     userId: Int,
     footerText: String,
-    content: @Composable () -> Unit,
+    packageManagers: IPackageManagers,
+    content: @Composable PackageInfo.() -> Unit,
 ) {
+    val packageInfo = remember(packageName, userId) {
+        packageManagers.getPackageInfoAsUser(packageName, userId)
+    } ?: return
     RegularScaffold(title = title) {
-        val appInfoProvider = remember {
-            PackageManagers.getPackageInfoAsUser(packageName, userId)?.let { packageInfo ->
-                AppInfoProvider(packageInfo)
-            }
-        } ?: return@RegularScaffold
+        remember(packageInfo) { AppInfoProvider(packageInfo) }.AppInfo(displayVersion = true)
 
-        appInfoProvider.AppInfo(displayVersion = true)
-
-        content()
+        packageInfo.content()
 
         Footer(footerText)
     }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
index 681eb1c..2e0d853 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppList.kt
@@ -49,28 +49,34 @@
 private const val TAG = "AppList"
 private const val CONTENT_TYPE_HEADER = "header"
 
-internal data class AppListState(
+data class AppListState(
     val showSystem: State<Boolean>,
     val option: State<Int>,
     val searchQuery: State<String>,
 )
 
+data class AppListInput<T : AppRecord>(
+    val config: AppListConfig,
+    val listModel: AppListModel<T>,
+    val state: AppListState,
+    val header: @Composable () -> Unit,
+    val appItem: @Composable AppListItemModel<T>.() -> Unit,
+    val bottomPadding: Dp,
+)
+
 /**
  * The template to render an App List.
  *
  * This UI element will take the remaining space on the screen to show the App List.
  */
 @Composable
-internal fun <T : AppRecord> AppList(
-    config: AppListConfig,
-    listModel: AppListModel<T>,
-    state: AppListState,
-    header: @Composable () -> Unit,
-    appItem: @Composable (itemState: AppListItemModel<T>) -> Unit,
-    bottomPadding: Dp,
-    appListDataSupplier: @Composable () -> State<AppListData<T>?> = {
-        loadAppListData(config, listModel, state)
-    },
+fun <T : AppRecord> AppListInput<T>.AppList() {
+    AppListImpl { loadAppListData(config, listModel, state) }
+}
+
+@Composable
+internal fun <T : AppRecord> AppListInput<T>.AppListImpl(
+    appListDataSupplier: @Composable () -> State<AppListData<T>?>,
 ) {
     LogCompositions(TAG, config.userId.toString())
     val appListData = appListDataSupplier()
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListItem.kt
index ac3f8ff..6d0d7d6 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListItem.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListItem.kt
@@ -28,23 +28,20 @@
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 
-class AppListItemModel<T : AppRecord>(
+data class AppListItemModel<T : AppRecord>(
     val record: T,
     val label: String,
     val summary: State<String>,
 )
 
 @Composable
-fun <T : AppRecord> AppListItem(
-    itemModel: AppListItemModel<T>,
-    onClick: () -> Unit,
-) {
+fun <T : AppRecord> AppListItemModel<T>.AppListItem(onClick: () -> Unit) {
     Preference(remember {
         object : PreferenceModel {
-            override val title = itemModel.label
-            override val summary = itemModel.summary
+            override val title = label
+            override val summary = this@AppListItem.summary
             override val icon = @Composable {
-                AppIcon(app = itemModel.record.app, size = SettingsDimension.appIconItemSize)
+                AppIcon(app = record.app, size = SettingsDimension.appIconItemSize)
             }
             override val onClick = onClick
         }
@@ -58,7 +55,6 @@
         val record = object : AppRecord {
             override val app = LocalContext.current.applicationInfo
         }
-        val itemModel = AppListItemModel<AppRecord>(record, "Chrome", "Allowed".toState())
-        AppListItem(itemModel) {}
+        AppListItemModel<AppRecord>(record, "Chrome", "Allowed".toState()).AppListItem {}
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
index f371ce9..cb35fb0 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListPage.kt
@@ -47,7 +47,8 @@
     primaryUserOnly: Boolean = false,
     moreOptions: @Composable MoreOptionsScope.() -> Unit = {},
     header: @Composable () -> Unit = {},
-    appItem: @Composable (itemState: AppListItemModel<T>) -> Unit,
+    appList: @Composable AppListInput<T>.() -> Unit = { AppList() },
+    appItem: @Composable AppListItemModel<T>.() -> Unit,
 ) {
     val showSystem = rememberSaveable { mutableStateOf(false) }
     SearchScaffold(
@@ -64,7 +65,7 @@
                 val options = remember { listModel.getSpinnerOptions() }
                 val selectedOption = rememberSaveable { mutableStateOf(0) }
                 Spinner(options, selectedOption.value) { selectedOption.value = it }
-                AppList(
+                val appListInput = AppListInput(
                     config = AppListConfig(
                         userId = userInfo.id,
                         showInstantApps = showInstantApps,
@@ -79,6 +80,7 @@
                     appItem = appItem,
                     bottomPadding = bottomPadding,
                 )
+                appList(appListInput)
             }
         }
     }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt
index 5290bec..452971b 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItem.kt
@@ -9,8 +9,7 @@
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 
 @Composable
-fun <T : AppRecord> AppListSwitchItem(
-    itemModel: AppListItemModel<T>,
+fun <T : AppRecord> AppListItemModel<T>.AppListSwitchItem(
     onClick: () -> Unit,
     checked: State<Boolean?>,
     changeable: State<Boolean>,
@@ -19,14 +18,14 @@
     TwoTargetSwitchPreference(
         model = remember {
             object : SwitchPreferenceModel {
-                override val title = itemModel.label
-                override val summary = itemModel.summary
+                override val title = label
+                override val summary = this@AppListSwitchItem.summary
                 override val checked = checked
                 override val changeable = changeable
                 override val onCheckedChange = onCheckedChange
             }
         },
-        icon = { AppIcon(itemModel.record.app, SettingsDimension.appIconItemSize) },
+        icon = { AppIcon(record.app, SettingsDimension.appIconItemSize) },
         onClick = onClick,
     )
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
index c6f41d3..a357832 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppList.kt
@@ -25,11 +25,12 @@
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
+import com.android.settingslib.spa.framework.util.filterItem
 import com.android.settingslib.spaprivileged.model.app.AppOpsController
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
-import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasGrantPermission
-import com.android.settingslib.spaprivileged.model.app.PackageManagers.hasRequestPermission
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.map
@@ -37,21 +38,24 @@
 data class AppOpPermissionRecord(
     override val app: ApplicationInfo,
     val hasRequestPermission: Boolean,
-    var appOpsController: AppOpsController,
+    var appOpsController: IAppOpsController,
 ) : AppRecord
 
-abstract class AppOpPermissionListModel(private val context: Context) :
-    TogglePermissionAppListModel<AppOpPermissionRecord> {
+abstract class AppOpPermissionListModel(
+    private val context: Context,
+    private val packageManagers: IPackageManagers = PackageManagers,
+) : TogglePermissionAppListModel<AppOpPermissionRecord> {
 
     abstract val appOp: Int
     abstract val permission: String
 
+    /** These not changeable packages will also be hidden from app list. */
     private val notChangeablePackages =
         setOf("android", "com.android.systemui", context.packageName)
 
     override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
         userIdFlow.map { userId ->
-            PackageManagers.getAppOpPermissionPackages(userId, permission)
+            packageManagers.getAppOpPermissionPackages(userId, permission)
         }.combine(appListFlow) { packageNames, appList ->
             appList.map { app ->
                 AppOpPermissionRecord(
@@ -64,14 +68,12 @@
 
     override fun transformItem(app: ApplicationInfo) = AppOpPermissionRecord(
         app = app,
-        hasRequestPermission = app.hasRequestPermission(permission),
+        hasRequestPermission = with(packageManagers) { app.hasRequestPermission(permission) },
         appOpsController = AppOpsController(context = context, app = app, op = appOp),
     )
 
     override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<AppOpPermissionRecord>>) =
-        recordListFlow.map { recordList ->
-            recordList.filter { it.hasRequestPermission }
-        }
+        recordListFlow.filterItem(::isChangeable)
 
     /**
      * Defining the default behavior as permissible as long as the package requested this permission
@@ -85,7 +87,9 @@
                 when (mode.value) {
                     null -> null
                     MODE_ALLOWED -> true
-                    MODE_DEFAULT -> record.app.hasGrantPermission(permission)
+                    MODE_DEFAULT -> with(packageManagers) {
+                        record.app.hasGrantPermission(permission)
+                    }
                     else -> false
                 }
             }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
index de5a4a2..5ae5ada 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPage.kt
@@ -19,6 +19,7 @@
 import android.content.Context
 import android.content.pm.ApplicationInfo
 import android.os.Bundle
+import androidx.annotation.VisibleForTesting
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.State
@@ -38,23 +39,15 @@
 import com.android.settingslib.spa.widget.preference.PreferenceModel
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
 import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
 import com.android.settingslib.spaprivileged.model.app.PackageManagers
 import com.android.settingslib.spaprivileged.model.app.toRoute
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
 import kotlinx.coroutines.Dispatchers
 
-private const val ENTRY_NAME = "AllowControl"
-private const val PERMISSION = "permission"
-private const val PACKAGE_NAME = "rt_packageName"
-private const val USER_ID = "rt_userId"
-private const val PAGE_NAME = "TogglePermissionAppInfoPage"
-private val PAGE_PARAMETER = listOf(
-    navArgument(PERMISSION) { type = NavType.StringType },
-    navArgument(PACKAGE_NAME) { type = NavType.StringType },
-    navArgument(USER_ID) { type = NavType.IntType },
-)
-
 internal class TogglePermissionAppInfoPageProvider(
     private val appListTemplate: TogglePermissionAppListTemplate,
 ) : SettingsPageProvider {
@@ -64,11 +57,7 @@
 
     override fun buildEntry(arguments: Bundle?): List<SettingsEntry> {
         val owner = SettingsPage.create(name, parameter = parameter, arguments = arguments)
-        val entryList = mutableListOf<SettingsEntry>()
-        entryList.add(
-            SettingsEntryBuilder.create(ENTRY_NAME, owner).setIsAllowSearch(false).build()
-        )
-        return entryList
+        return listOf(SettingsEntryBuilder.create("AllowControl", owner).build())
     }
 
     @Composable
@@ -76,11 +65,22 @@
         val permissionType = arguments?.getString(PERMISSION)!!
         val packageName = arguments.getString(PACKAGE_NAME)!!
         val userId = arguments.getInt(USER_ID)
-        val listModel = appListTemplate.rememberModel(permissionType)
-        TogglePermissionAppInfoPage(listModel, packageName, userId)
+        appListTemplate.rememberModel(permissionType)
+            .TogglePermissionAppInfoPage(packageName, userId)
     }
 
     companion object {
+        private const val PAGE_NAME = "TogglePermissionAppInfoPage"
+        private const val PERMISSION = "permission"
+        private const val PACKAGE_NAME = "rt_packageName"
+        private const val USER_ID = "rt_userId"
+
+        private val PAGE_PARAMETER = listOf(
+            navArgument(PERMISSION) { type = NavType.StringType },
+            navArgument(PACKAGE_NAME) { type = NavType.StringType },
+            navArgument(USER_ID) { type = NavType.IntType },
+        )
+
         @Composable
         fun navigator(permissionType: String, app: ApplicationInfo) =
             navigator(route = "$PAGE_NAME/$permissionType/${app.toRoute()}")
@@ -116,43 +116,36 @@
     }
 }
 
+@VisibleForTesting
 @Composable
-private fun TogglePermissionAppInfoPage(
-    listModel: TogglePermissionAppListModel<out AppRecord>,
+internal fun TogglePermissionAppListModel<out AppRecord>.TogglePermissionAppInfoPage(
     packageName: String,
     userId: Int,
+    packageManagers: IPackageManagers = PackageManagers,
+    restrictionsProviderFactory: RestrictionsProviderFactory = ::RestrictionsProviderImpl,
 ) {
     AppInfoPage(
-        title = stringResource(listModel.pageTitleResId),
+        title = stringResource(pageTitleResId),
         packageName = packageName,
         userId = userId,
-        footerText = stringResource(listModel.footerResId),
+        footerText = stringResource(footerResId),
+        packageManagers = packageManagers,
     ) {
-        val model = createSwitchModel(listModel, packageName, userId) ?: return@AppInfoPage
-        LaunchedEffect(model, Dispatchers.Default) {
-            model.initState()
-        }
-        RestrictedSwitchPreference(model, Restrictions(userId, listModel.switchRestrictionKeys))
+        val model = createSwitchModel(applicationInfo)
+        val restrictions = Restrictions(userId, switchRestrictionKeys)
+        RestrictedSwitchPreference(model, restrictions, restrictionsProviderFactory)
     }
 }
 
 @Composable
-private fun <T : AppRecord> createSwitchModel(
-    listModel: TogglePermissionAppListModel<T>,
-    packageName: String,
-    userId: Int,
-): TogglePermissionSwitchModel<T>? {
-    val record = remember {
-        PackageManagers.getApplicationInfoAsUser(packageName, userId)?.let { app ->
-            listModel.transformItem(app)
-        }
-    } ?: return null
-
+private fun <T : AppRecord> TogglePermissionAppListModel<T>.createSwitchModel(
+    app: ApplicationInfo,
+): TogglePermissionSwitchModel<T> {
     val context = LocalContext.current
-    val isAllowed = listModel.isAllowed(record)
-    return remember {
-        TogglePermissionSwitchModel(context, listModel, record, isAllowed)
-    }
+    val record = remember(app) { transformItem(app) }
+    val isAllowed = isAllowed(record)
+    return remember(record) { TogglePermissionSwitchModel(context, this, record, isAllowed) }
+        .also { model -> LaunchedEffect(model, Dispatchers.IO) { model.initState() } }
 }
 
 private class TogglePermissionSwitchModel<T : AppRecord>(
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
index ec7d75e..00eb607 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPage.kt
@@ -22,7 +22,6 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
@@ -43,7 +42,7 @@
 import com.android.settingslib.spaprivileged.model.app.AppRecord
 import com.android.settingslib.spaprivileged.model.app.userId
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
-import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 import com.android.settingslib.spaprivileged.template.preference.RestrictedSwitchPreference
 import kotlinx.coroutines.flow.Flow
 
@@ -71,7 +70,6 @@
             entryList.add(
                 SettingsEntryBuilder.createLinkFrom("${ENTRY_NAME}_$category", appListPage)
                     .setLink(toPage = appInfoPage)
-                    .setIsAllowSearch(false)
                     .build()
             )
         }
@@ -93,12 +91,11 @@
         AppListPage(
             title = stringResource(listModel.pageTitleResId),
             listModel = internalListModel,
-        ) { itemModel ->
+        ) {
             AppListItem(
-                itemModel = itemModel,
                 onClick = TogglePermissionAppInfoPageProvider.navigator(
                     permissionType = permissionType,
-                    app = itemModel.record.app,
+                    app = record.app,
                 ),
             )
         }
@@ -121,7 +118,7 @@
                 parameter = PAGE_PARAMETER,
                 arguments = bundleOf(PERMISSION to permissionType)
             )
-            return SettingsEntryBuilder.createInject(owner = appListPage).setIsAllowSearch(false)
+            return SettingsEntryBuilder.createInject(owner = appListPage)
                 .setUiLayoutFn {
                     val listModel = rememberContext(listModelSupplier)
                     Preference(
@@ -146,9 +143,7 @@
         listModel.filter(userIdFlow, recordListFlow)
 
     @Composable
-    override fun getSummary(option: Int, record: T): State<String> {
-        return getSummary(record)
-    }
+    override fun getSummary(option: Int, record: T) = getSummary(record)
 
     @Composable
     fun getSummary(record: T): State<String> {
@@ -157,27 +152,27 @@
                 userId = record.app.userId,
                 keys = listModel.switchRestrictionKeys,
             )
-            RestrictionsProvider(context, restrictions)
+            RestrictionsProviderImpl(context, restrictions)
         }
-        val restrictedMode = restrictionsProvider.restrictedMode.observeAsState()
+        val restrictedMode = restrictionsProvider.restrictedModeState()
         val allowed = listModel.isAllowed(record)
         return remember {
             derivedStateOf {
                 RestrictedSwitchPreference.getSummary(
                     context = context,
                     restrictedMode = restrictedMode.value,
-                    noRestrictedSummary = getNoRestrictedSummary(allowed),
+                    summaryIfNoRestricted = getSummaryIfNoRestricted(allowed),
                     checked = allowed,
                 ).value
             }
         }
     }
 
-    private fun getNoRestrictedSummary(allowed: State<Boolean?>) = derivedStateOf {
+    private fun getSummaryIfNoRestricted(allowed: State<Boolean?>) = derivedStateOf {
         when (allowed.value) {
             true -> context.getString(R.string.app_permission_summary_allowed)
             false -> context.getString(R.string.app_permission_summary_not_allowed)
-            else -> context.getString(R.string.summary_placeholder)
+            null -> context.getString(R.string.summary_placeholder)
         }
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
index 31fd3ad..b08b6df 100644
--- a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreference.kt
@@ -22,12 +22,13 @@
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.State
 import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.livedata.observeAsState
 import androidx.compose.runtime.remember
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.semantics.Role
-import com.android.settingslib.RestrictedLockUtils
+import androidx.compose.ui.semantics.semantics
+import androidx.compose.ui.semantics.toggleableState
+import androidx.compose.ui.state.ToggleableState
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.widget.preference.SwitchPreference
 import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
@@ -37,33 +38,40 @@
 import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
 import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
 import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
-import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderFactory
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
 
 @Composable
-fun RestrictedSwitchPreference(model: SwitchPreferenceModel, restrictions: Restrictions) {
+fun RestrictedSwitchPreference(
+    model: SwitchPreferenceModel,
+    restrictions: Restrictions,
+    restrictionsProviderFactory: RestrictionsProviderFactory = ::RestrictionsProviderImpl,
+) {
     if (restrictions.keys.isEmpty()) {
         SwitchPreference(model)
         return
     }
     val context = LocalContext.current
-    val restrictionsProvider = remember { RestrictionsProvider(context, restrictions) }
-    val restrictedMode = restrictionsProvider.restrictedMode.observeAsState().value ?: return
+    val restrictionsProvider = remember(restrictions) {
+        restrictionsProviderFactory(context, restrictions)
+    }
+    val restrictedMode = restrictionsProvider.restrictedModeState().value
     val restrictedSwitchModel = remember(restrictedMode) {
         RestrictedSwitchPreferenceModel(context, model, restrictedMode)
     }
-    Box(remember { restrictedSwitchModel.getModifier() }) {
+    restrictedSwitchModel.RestrictionWrapper {
         SwitchPreference(restrictedSwitchModel)
     }
 }
 
-object RestrictedSwitchPreference {
+internal object RestrictedSwitchPreference {
     fun getSummary(
         context: Context,
         restrictedMode: RestrictedMode?,
-        noRestrictedSummary: State<String>,
+        summaryIfNoRestricted: State<String>,
         checked: State<Boolean?>,
     ): State<String> = when (restrictedMode) {
-        is NoRestricted -> noRestrictedSummary
+        is NoRestricted -> summaryIfNoRestricted
         is BaseUserRestricted -> stateOf(context.getString(R.string.disabled))
         is BlockedByAdmin -> derivedStateOf { restrictedMode.getSummary(checked.value) }
         null -> stateOf(context.getString(R.string.summary_placeholder))
@@ -71,43 +79,64 @@
 }
 
 private class RestrictedSwitchPreferenceModel(
-    private val context: Context,
+    context: Context,
     model: SwitchPreferenceModel,
-    private val restrictedMode: RestrictedMode,
+    private val restrictedMode: RestrictedMode?,
 ) : SwitchPreferenceModel {
     override val title = model.title
 
     override val summary = RestrictedSwitchPreference.getSummary(
         context = context,
         restrictedMode = restrictedMode,
-        noRestrictedSummary = model.summary,
+        summaryIfNoRestricted = model.summary,
         checked = model.checked,
     )
 
     override val checked = when (restrictedMode) {
+        null -> stateOf(null)
         is NoRestricted -> model.checked
         is BaseUserRestricted -> stateOf(false)
         is BlockedByAdmin -> model.checked
     }
 
     override val changeable = when (restrictedMode) {
+        null -> stateOf(false)
         is NoRestricted -> model.changeable
         is BaseUserRestricted -> stateOf(false)
         is BlockedByAdmin -> stateOf(false)
     }
 
     override val onCheckedChange = when (restrictedMode) {
+        null -> null
         is NoRestricted -> model.onCheckedChange
-        is BaseUserRestricted -> null
+        // Need to pass a non null onCheckedChange to enable semantics ToggleableState, although
+        // since changeable is false this will not be called.
+        is BaseUserRestricted -> model.onCheckedChange
+        // Pass null since semantics ToggleableState is provided in RestrictionWrapper.
         is BlockedByAdmin -> null
     }
 
-    fun getModifier(): Modifier = when (restrictedMode) {
-        is BlockedByAdmin -> Modifier.clickable(role = Role.Switch) {
-            RestrictedLockUtils.sendShowAdminSupportDetailsIntent(
-                context, restrictedMode.enforcedAdmin
-            )
+    @Composable
+    fun RestrictionWrapper(content: @Composable () -> Unit) {
+        if (restrictedMode !is BlockedByAdmin) {
+            content()
+            return
         }
-        else -> Modifier
+        Box(
+            Modifier
+                .clickable(
+                    role = Role.Switch,
+                    onClick = { restrictedMode.sendShowAdminSupportDetailsIntent() },
+                )
+                .semantics {
+                    this.toggleableState = ToggleableState(checked.value)
+                },
+        ) { content() }
+    }
+
+    private fun ToggleableState(value: Boolean?) = when (value) {
+        true -> ToggleableState.On
+        false -> ToggleableState.Off
+        null -> ToggleableState.Indeterminate
     }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt
new file mode 100644
index 0000000..8c1421a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItem.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.scaffold
+
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.remember
+import androidx.compose.ui.platform.LocalContext
+import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
+import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProviderImpl
+
+@Composable
+fun MoreOptionsScope.RestrictedMenuItem(
+    text: String,
+    restrictions: Restrictions,
+    onClick: () -> Unit,
+) {
+    RestrictedMenuItemImpl(text, restrictions, onClick, ::RestrictionsProviderImpl)
+}
+
+@Composable
+internal fun MoreOptionsScope.RestrictedMenuItemImpl(
+    text: String,
+    restrictions: Restrictions,
+    onClick: () -> Unit,
+    restrictionsProviderFactory: (Context, Restrictions) -> RestrictionsProvider,
+) {
+    val context = LocalContext.current
+    val restrictionsProvider = remember(restrictions) {
+        restrictionsProviderFactory(context, restrictions)
+    }
+    val restrictedMode = restrictionsProvider.restrictedModeState().value
+    MenuItem(text = text, enabled = restrictedMode !is BaseUserRestricted) {
+        when (restrictedMode) {
+            is BlockedByAdmin -> restrictedMode.sendShowAdminSupportDetailsIntent()
+            else -> onClick()
+        }
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml b/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml
index c4f490e..8d384e8 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml
+++ b/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml
@@ -15,7 +15,7 @@
 -->
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.settingslib.spaprivileged.tests">
+    package="com.android.settingslib.spaprivileged.test">
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -24,5 +24,5 @@
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
         android:label="Tests for SpaPrivilegedLib"
-        android:targetPackage="com.android.settingslib.spaprivileged.tests" />
+        android:targetPackage="com.android.settingslib.spaprivileged.test" />
 </manifest>
diff --git a/packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml b/packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml
new file mode 100644
index 0000000..bdc0ba8
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <!-- Test Permission title. [DO NOT TRANSLATE] -->
+    <string name="test_permission_title" translatable="false">Test Permission</string>
+
+    <!-- Test Permission switch title. [DO NOT TRANSLATE] -->
+    <string name="test_permission_switch_title" translatable="false">Allow Test Permission</string>
+
+    <!-- Test Permission footer. [DO NOT TRANSLATE] -->
+    <string name="test_permission_footer" translatable="false">Test Permission is for testing.</string>
+
+    <!-- Test App Op Permission title. [DO NOT TRANSLATE] -->
+    <string name="test_app_op_permission_title" translatable="false">Test App Op Permission</string>
+
+    <!-- Test App Op Permission switch title. [DO NOT TRANSLATE] -->
+    <string name="test_app_op_permission_switch_title" translatable="false">Allow Test App Op Permission</string>
+
+    <!-- Test App Op Permission footer. [DO NOT TRANSLATE] -->
+    <string name="test_app_op_permission_footer" translatable="false">Test App Op Permission is for testing.</string>
+</resources>
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
index bc6925b..c4f2df2 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
@@ -40,9 +40,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class AppListRepositoryTest {
-
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @Mock
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
index b570815..b9c875b 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
@@ -21,7 +21,7 @@
 import androidx.compose.runtime.Composable
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spa.framework.compose.stateOf
-import com.android.settingslib.spa.framework.util.asyncMapItem
+import com.android.settingslib.spa.framework.util.mapItem
 import com.android.settingslib.spa.testutils.waitUntil
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -39,8 +39,7 @@
 @OptIn(ExperimentalCoroutinesApi::class)
 @RunWith(AndroidJUnit4::class)
 class AppListViewModelTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @Mock
@@ -117,16 +116,7 @@
     var onFirstLoadedCalled = false
 
     override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
-        appListFlow.asyncMapItem { TestAppRecord(it) }
-
-    @Composable
-    override fun getSummary(option: Int, record: TestAppRecord) = null
-
-    override fun filter(
-        userIdFlow: Flow<Int>,
-        option: Int,
-        recordListFlow: Flow<List<TestAppRecord>>,
-    ) = recordListFlow
+        appListFlow.mapItem(::TestAppRecord)
 
     override suspend fun onFirstLoaded(recordList: List<TestAppRecord>) {
         onFirstLoadedCalled = true
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
index 4207490..4002655 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
@@ -40,8 +40,7 @@
 
 @RunWith(AndroidJUnit4::class)
 class PackageManagerExtTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @Mock
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
index 8ca79509..bb56c10 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
@@ -36,7 +36,7 @@
     @get:Rule
     val composeTestRule = createComposeRule()
 
-    private var context: Context = ApplicationProvider.getApplicationContext()
+    private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Test
     fun appInfoLabel_isDisplayed() {
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
new file mode 100644
index 0000000..f2267f6
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.content.Context
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.State
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.R
+import com.android.settingslib.spaprivileged.tests.testutils.TestAppListModel
+import com.android.settingslib.spaprivileged.tests.testutils.TestAppRecord
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AppListPageTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Test
+    fun title_isDisplayed() {
+        setContent()
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed()
+    }
+
+    @Test
+    fun appListState_hasCorrectInitialState() {
+        val inputState by setContent()
+
+        val state = inputState!!.state
+        assertThat(state.showSystem.value).isFalse()
+        assertThat(state.option.value).isEqualTo(0)
+        assertThat(state.searchQuery.value).isEqualTo("")
+    }
+
+    @Test
+    fun canShowSystem() {
+        val inputState by setContent()
+
+        composeTestRule.onNodeWithContentDescription(
+            context.getString(R.string.abc_action_menu_overflow_description)
+        ).performClick()
+        composeTestRule.onNodeWithText(context.getString(R.string.menu_show_system)).performClick()
+
+        val state = inputState!!.state
+        assertThat(state.showSystem.value).isTrue()
+    }
+
+    @Test
+    fun afterShowSystem_displayHideSystem() {
+        setContent()
+        composeTestRule.onNodeWithContentDescription(
+            context.getString(R.string.abc_action_menu_overflow_description)
+        ).performClick()
+        composeTestRule.onNodeWithText(context.getString(R.string.menu_show_system)).performClick()
+
+        composeTestRule.onNodeWithContentDescription(
+            context.getString(R.string.abc_action_menu_overflow_description)
+        ).performClick()
+
+        composeTestRule.onNodeWithText(context.getString(R.string.menu_hide_system))
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun whenHasOptions_firstOptionDisplayed() {
+        val inputState by setContent(options = listOf(OPTION_0, OPTION_1))
+
+        composeTestRule.onNodeWithText(OPTION_0).assertIsDisplayed()
+        composeTestRule.onNodeWithText(OPTION_1).assertDoesNotExist()
+        val state = inputState!!.state
+        assertThat(state.option.value).isEqualTo(0)
+    }
+
+    @Test
+    fun whenHasOptions_couldSwitchOption() {
+        val inputState by setContent(options = listOf(OPTION_0, OPTION_1))
+
+        composeTestRule.onNodeWithText(OPTION_0).performClick()
+        composeTestRule.onNodeWithText(OPTION_1).performClick()
+
+        composeTestRule.onNodeWithText(OPTION_1).assertIsDisplayed()
+        composeTestRule.onNodeWithText(OPTION_0).assertDoesNotExist()
+        val state = inputState!!.state
+        assertThat(state.option.value).isEqualTo(1)
+    }
+
+    private fun setContent(
+        options: List<String> = emptyList(),
+        header: @Composable () -> Unit = {},
+    ): State<AppListInput<TestAppRecord>?> {
+        val appListState = mutableStateOf<AppListInput<TestAppRecord>?>(null)
+        composeTestRule.setContent {
+            AppListPage(
+                title = TITLE,
+                listModel = TestAppListModel(options),
+                header = header,
+                appItem = { AppListItem {} },
+                appList = { appListState.value = this },
+            )
+        }
+        return appListState
+    }
+
+    private companion object {
+        const val TITLE = "Title"
+        const val OPTION_0 = "Option 1"
+        const val OPTION_1 = "Option 2"
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
new file mode 100644
index 0000000..abdcd3b
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.content.pm.ApplicationInfo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.isToggleable
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class AppListSwitchItemTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @Test
+    fun appLabel_displayed() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(null),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNodeWithText(LABEL).assertIsDisplayed()
+    }
+
+    @Test
+    fun summary_displayed() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(null),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNodeWithText(SUMMARY).assertIsDisplayed()
+    }
+
+    @Test
+    fun title_onClick() {
+        var titleClicked = false
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = { titleClicked = true },
+                checked = stateOf(false),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNodeWithText(LABEL).performClick()
+
+        assertThat(titleClicked).isTrue()
+    }
+
+    @Test
+    fun switch_checkIsNull() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(null),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).assertDoesNotExist()
+    }
+
+    @Test
+    fun switch_checked() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(true),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsOn()
+    }
+
+    @Test
+    fun switch_notChecked() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(false),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsOff()
+    }
+
+    @Test
+    fun switch_changeable() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(false),
+                changeable = stateOf(true),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsEnabled()
+    }
+
+    @Test
+    fun switch_notChangeable() {
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(false),
+                changeable = stateOf(false),
+                onCheckedChange = {},
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).assertIsNotEnabled()
+    }
+
+    @Test
+    fun switch_onClick() {
+        var switchClicked = false
+        composeTestRule.setContent {
+            ITEM_MODEL.AppListSwitchItem(
+                onClick = {},
+                checked = stateOf(false),
+                changeable = stateOf(true),
+                onCheckedChange = { switchClicked = true },
+            )
+        }
+
+        composeTestRule.onNode(isToggleable()).performClick()
+
+        assertThat(switchClicked).isTrue()
+    }
+
+    private companion object {
+        const val PACKAGE_NAME = "package.name"
+        const val LABEL = "Label"
+        const val SUMMARY = "Summary"
+        val APP = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+        }
+        val ITEM_MODEL = AppListItemModel(
+            record = object : AppRecord {
+                override val app = APP
+            },
+            label = LABEL,
+            summary = stateOf(SUMMARY),
+        )
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
index 9f20c78..2677669 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
@@ -29,14 +29,12 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import com.android.settingslib.spa.framework.compose.stateOf
 import com.android.settingslib.spa.framework.compose.toState
-import com.android.settingslib.spa.framework.util.asyncMapItem
 import com.android.settingslib.spaprivileged.R
 import com.android.settingslib.spaprivileged.model.app.AppEntry
 import com.android.settingslib.spaprivileged.model.app.AppListConfig
 import com.android.settingslib.spaprivileged.model.app.AppListData
-import com.android.settingslib.spaprivileged.model.app.AppListModel
-import com.android.settingslib.spaprivileged.model.app.AppRecord
-import kotlinx.coroutines.flow.Flow
+import com.android.settingslib.spaprivileged.tests.testutils.TestAppListModel
+import com.android.settingslib.spaprivileged.tests.testutils.TestAppRecord
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -46,7 +44,7 @@
     @get:Rule
     val composeTestRule = createComposeRule()
 
-    private var context: Context = ApplicationProvider.getApplicationContext()
+    private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Test
     fun whenNoApps() {
@@ -92,21 +90,19 @@
         enableGrouping: Boolean = false,
     ) {
         composeTestRule.setContent {
-            AppList(
+            val appListInput = AppListInput(
                 config = AppListConfig(userId = USER_ID, showInstantApps = false),
-                listModel = TestAppListModel(enableGrouping),
+                listModel = TestAppListModel(enableGrouping = enableGrouping),
                 state = AppListState(
                     showSystem = false.toState(),
                     option = 0.toState(),
                     searchQuery = "".toState(),
                 ),
                 header = header,
-                appItem = { AppListItem(it) {} },
+                appItem = { AppListItem {} },
                 bottomPadding = 0.dp,
-                appListDataSupplier = {
-                    stateOf(AppListData(appEntries, option = 0))
-                }
             )
+            appListInput.AppListImpl { stateOf(AppListData(appEntries, option = 0)) }
         }
     }
 
@@ -137,25 +133,3 @@
         )
     }
 }
-
-private data class TestAppRecord(
-    override val app: ApplicationInfo,
-    val group: String? = null,
-) : AppRecord
-
-private class TestAppListModel(val enableGrouping: Boolean) : AppListModel<TestAppRecord> {
-    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
-        appListFlow.asyncMapItem { TestAppRecord(it) }
-
-    @Composable
-    override fun getSummary(option: Int, record: TestAppRecord) = null
-
-    override fun filter(
-        userIdFlow: Flow<Int>,
-        option: Int,
-        recordListFlow: Flow<List<TestAppRecord>>,
-    ) = recordListFlow
-
-    override fun getGroupTitle(option: Int, record: TestAppRecord) =
-        if (enableGrouping) record.group else null
-}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
new file mode 100644
index 0000000..f1d9abe
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.app.AppOpsManager
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.State
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.lifecycle.liveData
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
+import com.android.settingslib.spaprivileged.model.app.IAppOpsController
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.test.R
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
+class AppOpPermissionAppListTest {
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var packageManagers: IPackageManagers
+
+    private lateinit var listModel: TestAppOpPermissionAppListModel
+
+    @Before
+    fun setUp() = runTest {
+        whenever(packageManagers.getAppOpPermissionPackages(USER_ID, PERMISSION))
+            .thenReturn(emptySet())
+        listModel = TestAppOpPermissionAppListModel()
+    }
+
+    @Test
+    fun transformItem_recordHasCorrectApp() {
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.app).isSameInstanceAs(APP)
+    }
+
+    @Test
+    fun transformItem_hasRequestPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PERMISSION)).thenReturn(true)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestPermission).isTrue()
+    }
+
+    @Test
+    fun transformItem_notRequestPermission() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PERMISSION)).thenReturn(false)
+        }
+
+        val record = listModel.transformItem(APP)
+
+        assertThat(record.hasRequestPermission).isFalse()
+    }
+
+    @Test
+    fun filter() = runTest {
+        with(packageManagers) {
+            whenever(APP.hasRequestPermission(PERMISSION)).thenReturn(false)
+        }
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = false,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val recordListFlow = listModel.filter(flowOf(USER_ID), flowOf(listOf(record)))
+
+        val recordList = recordListFlow.firstWithTimeoutOrNull()!!
+        assertThat(recordList).isEmpty()
+    }
+
+    @Test
+    fun isAllowed_allowed() {
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ALLOWED),
+        )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isTrue()
+    }
+
+    @Test
+    fun isAllowed_defaultAndHasGrantPermission() {
+        with(packageManagers) {
+            whenever(APP.hasGrantPermission(PERMISSION)).thenReturn(true)
+        }
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isTrue()
+    }
+
+    @Test
+    fun isAllowed_defaultAndNotGrantPermission() {
+        with(packageManagers) {
+            whenever(APP.hasGrantPermission(PERMISSION)).thenReturn(false)
+        }
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isFalse()
+    }
+
+    @Test
+    fun isAllowed_notAllowed() {
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_ERRORED),
+        )
+
+        val isAllowed = getIsAllowed(record)
+
+        assertThat(isAllowed).isFalse()
+    }
+
+    @Test
+    fun isChangeable_notRequestPermission() {
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = false,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isFalse()
+    }
+
+    @Test
+    fun isChangeable_notChangeablePackages() {
+        val record = AppOpPermissionRecord(
+            app = NOT_CHANGEABLE_APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isFalse()
+    }
+
+    @Test
+    fun isChangeable_hasRequestPermissionAndChangeable() {
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT),
+        )
+
+        val isChangeable = listModel.isChangeable(record)
+
+        assertThat(isChangeable).isTrue()
+    }
+
+    @Test
+    fun setAllowed() {
+        val appOpsController = FakeAppOpsController(fakeMode = AppOpsManager.MODE_DEFAULT)
+        val record = AppOpPermissionRecord(
+            app = APP,
+            hasRequestPermission = true,
+            appOpsController = appOpsController,
+        )
+
+        listModel.setAllowed(record = record, newAllowed = true)
+
+        assertThat(appOpsController.setAllowedCalledWith).isTrue()
+    }
+
+    private fun getIsAllowed(record: AppOpPermissionRecord): Boolean? {
+        lateinit var isAllowedState: State<Boolean?>
+        composeTestRule.setContent {
+            isAllowedState = listModel.isAllowed(record)
+        }
+        return isAllowedState.value
+    }
+
+    private inner class TestAppOpPermissionAppListModel :
+        AppOpPermissionListModel(context, packageManagers) {
+        override val pageTitleResId = R.string.test_app_op_permission_title
+        override val switchTitleResId = R.string.test_app_op_permission_switch_title
+        override val footerResId = R.string.test_app_op_permission_footer
+        override val appOp = AppOpsManager.OP_MANAGE_MEDIA
+        override val permission = PERMISSION
+    }
+
+    private companion object {
+        const val USER_ID = 0
+        const val PACKAGE_NAME = "package.name"
+        const val PERMISSION = "PERMISSION"
+        val APP = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+        }
+        val NOT_CHANGEABLE_APP = ApplicationInfo().apply {
+            packageName = "android"
+        }
+    }
+}
+
+private class FakeAppOpsController(private val fakeMode: Int) : IAppOpsController {
+    var setAllowedCalledWith: Boolean? = null
+
+    override val mode = liveData { emit(fakeMode) }
+
+    override fun setAllowed(allowed: Boolean) {
+        setAllowedCalledWith = allowed
+    }
+
+    override fun getMode() = fakeMode
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
index b3638c2..066e28a 100644
--- a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
@@ -41,15 +41,14 @@
 
 @RunWith(AndroidJUnit4::class)
 class AppStorageSizeTest {
-    @JvmField
-    @Rule
+    @get:Rule
     val mockito: MockitoRule = MockitoJUnit.rule()
 
     @get:Rule
     val composeTestRule = createComposeRule()
 
     @Spy
-    private var context: Context = ApplicationProvider.getApplicationContext()
+    private val context: Context = ApplicationProvider.getApplicationContext()
 
     @Mock
     private lateinit var storageStatsManager: StorageStatsManager
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
new file mode 100644
index 0000000..ecad08a
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.content.Context
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageInfo
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.assertIsOff
+import androidx.compose.ui.test.assertIsOn
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.model.app.IPackageManagers
+import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
+import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListModel
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.Mockito.`when` as whenever
+
+@RunWith(AndroidJUnit4::class)
+class TogglePermissionAppInfoPageTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    @get:Rule
+    val mockito: MockitoRule = MockitoJUnit.rule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Mock
+    private lateinit var packageManagers: IPackageManagers
+
+    private val fakeRestrictionsProvider = FakeRestrictionsProvider()
+
+    private val appListTemplate =
+        TogglePermissionAppListTemplate(listOf(TestTogglePermissionAppListProvider))
+
+    private val appInfoPageProvider = TogglePermissionAppInfoPageProvider(appListTemplate)
+
+    @Before
+    fun setUp() {
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+        whenever(packageManagers.getPackageInfoAsUser(PACKAGE_NAME, USER_ID))
+            .thenReturn(PACKAGE_INFO)
+    }
+
+    @Test
+    fun buildEntry() {
+        val entryList = appInfoPageProvider.buildEntry(null)
+
+        assertThat(entryList).hasSize(1)
+        assertThat(entryList[0].displayName).isEqualTo("AllowControl")
+    }
+
+    @Test
+    fun title_isDisplayed() {
+        val listModel = TestTogglePermissionAppListModel()
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.pageTitleResId))
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun whenAllowed_switchIsOn() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = true)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsOn()
+    }
+
+    @Test
+    fun whenNotAllowed_switchIsOff() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = false)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsOff()
+    }
+
+    @Test
+    fun whenNotChangeable_switchNotEnabled() {
+        val listModel = TestTogglePermissionAppListModel(isAllowed = false, isChangeable = false)
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.switchTitleResId))
+            .assertIsDisplayed()
+            .assertIsNotEnabled()
+    }
+
+    @Test
+    fun footer_isDisplayed() {
+        val listModel = TestTogglePermissionAppListModel()
+
+        setTogglePermissionAppInfoPage(listModel)
+
+        composeTestRule.onNodeWithText(context.getString(listModel.footerResId))
+            .assertIsDisplayed()
+    }
+
+    private fun setTogglePermissionAppInfoPage(listModel: TestTogglePermissionAppListModel) {
+        composeTestRule.setContent {
+            listModel.TogglePermissionAppInfoPage(
+                packageName = PACKAGE_NAME,
+                userId = USER_ID,
+                packageManagers = packageManagers,
+                restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
+            )
+        }
+    }
+
+    private companion object {
+        const val USER_ID = 0
+        const val PACKAGE_NAME = "package.name"
+        val APP = ApplicationInfo().apply {
+            packageName = PACKAGE_NAME
+        }
+        val PACKAGE_INFO = PackageInfo().apply {
+            packageName = PACKAGE_NAME
+            applicationInfo = APP
+        }
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
new file mode 100644
index 0000000..355dfb6
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.content.Context
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.test.R
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListModel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TogglePermissionAppListPageTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Test
+    fun appListInjectEntry_titleDisplayed() {
+        val entry = TogglePermissionAppListPageProvider.buildInjectEntry(PERMISSION_TYPE) {
+            TestTogglePermissionAppListModel()
+        }.build()
+
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalContext provides context) {
+                entry.UiLayout()
+            }
+        }
+
+        composeTestRule.onNodeWithText(context.getString(R.string.test_permission_title))
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun appListRoute() {
+        val route = TogglePermissionAppListPageProvider.getRoute(PERMISSION_TYPE)
+
+        assertThat(route).isEqualTo("TogglePermissionAppList/test.PERMISSION")
+    }
+
+    private companion object {
+        const val PERMISSION_TYPE = "test.PERMISSION"
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
new file mode 100644
index 0000000..1818f2d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.app
+
+import android.content.Context
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spaprivileged.test.R
+import com.android.settingslib.spaprivileged.tests.testutils.TestTogglePermissionAppListProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class TogglePermissionAppListTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val context: Context = ApplicationProvider.getApplicationContext()
+
+    @Test
+    fun appListInjectEntry_titleDisplayed() {
+        val entry = TestTogglePermissionAppListProvider.buildAppListInjectEntry().build()
+        composeTestRule.setContent {
+            CompositionLocalProvider(LocalContext provides context) {
+                entry.UiLayout()
+            }
+        }
+
+        composeTestRule.onNodeWithText(context.getString(R.string.test_permission_title))
+            .assertIsDisplayed()
+    }
+
+    @Test
+    fun appListRoute() {
+        val route = TestTogglePermissionAppListProvider.getAppListRoute()
+
+        assertThat(route).isEqualTo("TogglePermissionAppList/test.PERMISSION")
+    }
+
+    @Test
+    fun togglePermissionAppListTemplate_createPageProviders() {
+        val togglePermissionAppListTemplate =
+            TogglePermissionAppListTemplate(listOf(TestTogglePermissionAppListProvider))
+
+        val createPageProviders = togglePermissionAppListTemplate.createPageProviders()
+
+        assertThat(createPageProviders).hasSize(2)
+        assertThat(createPageProviders.any { it is TogglePermissionAppListPageProvider }).isTrue()
+        assertThat(createPageProviders.any { it is TogglePermissionAppInfoPageProvider }).isTrue()
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
new file mode 100644
index 0000000..a13c483
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.preference
+
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.isOff
+import androidx.compose.ui.test.isOn
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.widget.preference.SwitchPreferenceModel
+import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.tests.testutils.FakeBlockedByAdmin
+import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RestrictedSwitchPreferenceTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val fakeBlockedByAdmin = FakeBlockedByAdmin()
+
+    private val fakeRestrictionsProvider = FakeRestrictionsProvider()
+
+    private val switchPreferenceModel = object : SwitchPreferenceModel {
+        override val title = TITLE
+        override val checked = mutableStateOf(true)
+        override val onCheckedChange: (Boolean) -> Unit = { checked.value = it }
+    }
+
+    @Test
+    fun whenRestrictionsKeysIsEmpty_enabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsEnabled()
+        composeTestRule.onNode(isOn()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenRestrictionsKeysIsEmpty_toggleable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        composeTestRule.onNode(isOff()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenNoRestricted_enabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsEnabled()
+        composeTestRule.onNode(isOn()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenNoRestricted_toggleable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        composeTestRule.onNode(isOff()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenBaseUserRestricted_disabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsNotEnabled()
+        composeTestRule.onNode(isOff()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenBaseUserRestricted_notToggleable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        composeTestRule.onNode(isOff()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenBlockedByAdmin_disabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TITLE).assertIsDisplayed().assertIsEnabled()
+        composeTestRule.onNodeWithText(FakeBlockedByAdmin.SUMMARY).assertIsDisplayed()
+        composeTestRule.onNode(isOn()).assertIsDisplayed()
+    }
+
+    @Test
+    fun whenBlockedByAdmin_click() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        assertThat(fakeBlockedByAdmin.sendShowAdminSupportDetailsIntentIsCalled).isTrue()
+    }
+
+    private fun setContent(restrictions: Restrictions) {
+        composeTestRule.setContent {
+            RestrictedSwitchPreference(switchPreferenceModel, restrictions) { _, _ ->
+                fakeRestrictionsProvider
+            }
+        }
+    }
+
+    private companion object {
+        const val TITLE = "Title"
+        const val USER_ID = 0
+        const val RESTRICTION_KEY = "restriction_key"
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
new file mode 100644
index 0000000..983284c
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.template.scaffold
+
+import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsEnabled
+import androidx.compose.ui.test.assertIsNotEnabled
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onNodeWithText
+import androidx.compose.ui.test.onRoot
+import androidx.compose.ui.test.performClick
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.settingslib.spa.widget.scaffold.MoreOptionsScope
+import com.android.settingslib.spaprivileged.model.enterprise.BaseUserRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.NoRestricted
+import com.android.settingslib.spaprivileged.model.enterprise.Restrictions
+import com.android.settingslib.spaprivileged.tests.testutils.FakeBlockedByAdmin
+import com.android.settingslib.spaprivileged.tests.testutils.FakeRestrictionsProvider
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RestrictedMenuItemTest {
+    @get:Rule
+    val composeTestRule = createComposeRule()
+
+    private val fakeBlockedByAdmin = FakeBlockedByAdmin()
+
+    private val fakeRestrictionsProvider = FakeRestrictionsProvider()
+
+    private var menuItemOnClickIsCalled = false
+
+    @Test
+    fun whenRestrictionsKeysIsEmpty_enabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
+    }
+
+    @Test
+    fun whenRestrictionsKeysIsEmpty_clickable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = emptyList())
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        assertThat(menuItemOnClickIsCalled).isTrue()
+    }
+
+    @Test
+    fun whenNoRestricted_enabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
+    }
+
+    @Test
+    fun whenNoRestricted_clickable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = NoRestricted
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        assertThat(menuItemOnClickIsCalled).isTrue()
+    }
+
+    @Test
+    fun whenBaseUserRestricted_disabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsNotEnabled()
+    }
+
+    @Test
+    fun whenBaseUserRestricted_notClickable() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = BaseUserRestricted
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        assertThat(menuItemOnClickIsCalled).isFalse()
+    }
+
+    @Test
+    fun whenBlockedByAdmin_disabled() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
+
+        setContent(restrictions)
+
+        composeTestRule.onNodeWithText(TEXT).assertIsDisplayed().assertIsEnabled()
+    }
+
+    @Test
+    fun whenBlockedByAdmin_onClick_showAdminSupportDetails() {
+        val restrictions = Restrictions(userId = USER_ID, keys = listOf(RESTRICTION_KEY))
+        fakeRestrictionsProvider.restrictedMode = fakeBlockedByAdmin
+
+        setContent(restrictions)
+        composeTestRule.onRoot().performClick()
+
+        assertThat(fakeBlockedByAdmin.sendShowAdminSupportDetailsIntentIsCalled).isTrue()
+        assertThat(menuItemOnClickIsCalled).isFalse()
+    }
+
+    private fun setContent(restrictions: Restrictions) {
+        val fakeMoreOptionsScope = object : MoreOptionsScope {
+            override fun dismiss() {}
+        }
+        composeTestRule.setContent {
+            fakeMoreOptionsScope.RestrictedMenuItemImpl(
+                text = TEXT,
+                restrictions = restrictions,
+                onClick = { menuItemOnClickIsCalled = true },
+                restrictionsProviderFactory = { _, _ -> fakeRestrictionsProvider },
+            )
+        }
+    }
+
+    private companion object {
+        const val TEXT = "Text"
+        const val USER_ID = 0
+        const val RESTRICTION_KEY = "restriction_key"
+    }
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
new file mode 100644
index 0000000..93fa17d
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.tests.testutils
+
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spaprivileged.model.enterprise.BlockedByAdmin
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictedMode
+import com.android.settingslib.spaprivileged.model.enterprise.RestrictionsProvider
+
+class FakeBlockedByAdmin : BlockedByAdmin {
+    var sendShowAdminSupportDetailsIntentIsCalled = false
+
+    override fun getSummary(checked: Boolean?) = SUMMARY
+
+    override fun sendShowAdminSupportDetailsIntent() {
+        sendShowAdminSupportDetailsIntentIsCalled = true
+    }
+
+    companion object {
+        const val SUMMARY = "Blocked by admin"
+    }
+}
+
+class FakeRestrictionsProvider : RestrictionsProvider {
+    var restrictedMode: RestrictedMode? = null
+
+    @Composable
+    override fun restrictedModeState() = stateOf(restrictedMode)
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
new file mode 100644
index 0000000..ada4016
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.tests.testutils
+
+import android.content.pm.ApplicationInfo
+import com.android.settingslib.spa.framework.util.mapItem
+import com.android.settingslib.spaprivileged.model.app.AppListModel
+import com.android.settingslib.spaprivileged.model.app.AppRecord
+import kotlinx.coroutines.flow.Flow
+
+data class TestAppRecord(
+    override val app: ApplicationInfo,
+    val group: String? = null,
+) : AppRecord
+
+class TestAppListModel(
+    private val options: List<String> = emptyList(),
+    private val enableGrouping: Boolean = false,
+) : AppListModel<TestAppRecord> {
+    override fun getSpinnerOptions() = options
+
+    override fun transform(userIdFlow: Flow<Int>, appListFlow: Flow<List<ApplicationInfo>>) =
+        appListFlow.mapItem(::TestAppRecord)
+
+    override fun getGroupTitle(option: Int, record: TestAppRecord) =
+        if (enableGrouping) record.group else null
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
new file mode 100644
index 0000000..b13fbb3
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.tests.testutils
+
+import android.content.pm.ApplicationInfo
+import androidx.compose.runtime.Composable
+import com.android.settingslib.spa.framework.compose.stateOf
+import com.android.settingslib.spaprivileged.test.R
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListModel
+import kotlinx.coroutines.flow.Flow
+
+class TestTogglePermissionAppListModel(
+    private val isAllowed: Boolean? = null,
+    private val isChangeable: Boolean = false,
+) : TogglePermissionAppListModel<TestAppRecord> {
+    override val pageTitleResId = R.string.test_permission_title
+    override val switchTitleResId = R.string.test_permission_switch_title
+    override val footerResId = R.string.test_permission_footer
+
+    override fun transformItem(app: ApplicationInfo) = TestAppRecord(app = app)
+
+    override fun filter(userIdFlow: Flow<Int>, recordListFlow: Flow<List<TestAppRecord>>) =
+        recordListFlow
+
+    @Composable
+    override fun isAllowed(record: TestAppRecord) = stateOf(isAllowed)
+
+    override fun isChangeable(record: TestAppRecord) = isChangeable
+
+    override fun setAllowed(record: TestAppRecord, newAllowed: Boolean) {}
+}
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
new file mode 100644
index 0000000..354bbf5
--- /dev/null
+++ b/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.spaprivileged.tests.testutils
+
+import android.content.Context
+import com.android.settingslib.spaprivileged.template.app.TogglePermissionAppListProvider
+
+object TestTogglePermissionAppListProvider : TogglePermissionAppListProvider {
+    override val permissionType = "test.PERMISSION"
+    override fun createModel(context: Context) = TestTogglePermissionAppListModel()
+}
diff --git a/packages/SettingsLib/TwoTargetPreference/Android.bp b/packages/SettingsLib/TwoTargetPreference/Android.bp
index 3baef4b..e9c6aed 100644
--- a/packages/SettingsLib/TwoTargetPreference/Android.bp
+++ b/packages/SettingsLib/TwoTargetPreference/Android.bp
@@ -23,5 +23,6 @@
     apex_available: [
         "//apex_available:platform",
         "com.android.permission",
+        "com.android.healthconnect",
     ],
 }
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index a39a2b9..0234330 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> oor tot vol"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> oor tot vol"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Laaiproses is onderbreek"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laai"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laai tans vinnig"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index d953678..29b188c 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"እስኪሞላ ድረስ <xliff:g id="TIME">%1$s</xliff:g> ይቀራል"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - እስኪሞላ ድረስ <xliff:g id="TIME">%2$s</xliff:g> ይቀራል"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ኃይል መሙላት ባለበት ቆሟል"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ያልታወቀ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ኃይል በመሙላት ላይ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ኃይል በፍጥነት በመሙላት ላይ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 3b00d26..28a3f18 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"يتبقّى <xliff:g id="TIME">%1$s</xliff:g> حتى اكتمال شحن البطارية."</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - يتبقّى <xliff:g id="TIME">%2$s</xliff:g> حتى اكتمال شحن البطارية."</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - تم إيقاف الشحن مؤقتًا"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"غير معروف"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"جارٍ الشحن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"جارٍ الشحن سريعًا"</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index 0acd7ee6..fc54e04 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="TIME">%1$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"সম্পূৰ্ণ হ’বলৈ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> বাকী আছে"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - চাৰ্জিং পজ কৰা হৈছে"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজ্ঞাত"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চাৰ্জ কৰি থকা হৈছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্ৰুততাৰে চাৰ্জ হৈছে"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 33efb4fd..e2e294f 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tam şarj edilənədək <xliff:g id="TIME">%1$s</xliff:g> qalıb"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - tam şarj edilənədək <xliff:g id="TIME">%2$s</xliff:g> qalıb"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Şarj durdurulub"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Naməlum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Enerji doldurma"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Sürətlə doldurulur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 108a136..479c9ca 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do kraja punjenja"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do kraja punjenja"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Punjenje je zaustavljeno"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Puni se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo se puni"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index 5a70202..b45996c 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Да поўнай зарадкі засталося <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – да поўнай зарадкі засталося: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Зарадка прыпынена"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невядома"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарадка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хуткая зарадка"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 7e97dd3..ecb5208 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Оставащо време до пълно зареждане: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Оставащо време до пълно зареждане: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: Зареждането е на пауза"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарежда се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Зарежда се бързо"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 023be24..fda27ed 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>-এ ব্যাটারি পুরো চার্জ হয়ে যাবে"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - চার্জিং পজ করা হয়েছে"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"অজানা"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"চার্জ হচ্ছে"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"দ্রুত চার্জ হচ্ছে"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index 3cb4190..cae96e9 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do potpune napunjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do potpune napunjenosti"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Punjenje je pauzirano"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index efa29ee..51a4a02 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> per completar la càrrega"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> per completar la càrrega"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: la càrrega s\'ha posat en pausa"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconegut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"S\'està carregant"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregant ràpidament"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 3736f93..a50e527 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabití"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabití"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Nabíjení je pozastaveno"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznámé"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíjí se"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rychlé nabíjení"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 849604d..95e0130 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fuldt opladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – fuldt opladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladningen er sat på pause"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukendt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Oplader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Oplader hurtigt"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index d736d59..12fce37 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Voll in <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – voll in <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Ladevorgang angehalten"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unbekannt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Wird aufgeladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Schnelles Aufladen"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index e76b933..f54d5d2 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Απομένουν <xliff:g id="TIME">%1$s</xliff:g> για πλήρη φόρτιση"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Απομένουν <xliff:g id="TIME">%2$s</xliff:g> για πλήρη φόρτιση"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Η φόρτιση τέθηκε σε παύση"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Άγνωστο"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Φόρτιση"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ταχεία φόρτιση"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index 09bc065..208dbfa 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index 4714a0b..aac80ab 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -468,6 +468,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
+    <string name="power_charging_future_paused" msgid="6829683663982987290">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging to <xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index 09bc065..208dbfa 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index 09bc065..208dbfa 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> left until full"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> left until full"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Charging is paused"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Unknown"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charging"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charging rapidly"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index f82a757..bfd7e83 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -468,6 +468,7 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‏‎‎‎‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎<xliff:g id="TIME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ left until full‎‏‎‎‏‎"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‎‎‎‎‎‏‎‏‏‏‏‏‎‎‏‏‏‎‏‎‎‏‏‏‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - ‎‏‎‎‏‏‎<xliff:g id="TIME">%2$s</xliff:g>‎‏‎‎‏‏‏‎ left until full‎‏‎‎‏‎"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‏‎‎‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‏‎‏‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging is paused‎‏‎‎‏‎"</string>
+    <string name="power_charging_future_paused" msgid="6829683663982987290">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‎‏‏‏‏‏‏‎‏‎‎‏‎‎‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‎‎‏‎‎‎‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎<xliff:g id="LEVEL">%1$s</xliff:g>‎‏‎‎‏‏‏‎ - Charging to ‎‏‎‎‏‏‎<xliff:g id="DOCK_DEFENDER_THRESHOLD">%2$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="battery_info_status_unknown" msgid="268625384868401114">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‎‏‎‎‎‎‏‎‏‎‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎Unknown‎‏‎‎‏‎"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‏‎‏‎‏‏‏‎‏‏‏‎‎‏‎‎‎‏‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‎‎‎‏‏‎‎‏‏‎‏‏‎‎‏‏‎‏‎Charging‎‏‎‎‏‎"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‏‏‎‏‏‎‎‏‏‏‏‎‎‏‏‏‏‏‎‎‎‏‎‎‎‎‏‏‏‎‏‏‏‏‏‏‎‏‎‎‎‏‎‎‏‎‏‏‎‏‏‎‎‎‎‏‎‏‎Charging rapidly‎‏‎‎‏‎"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 1a4e307..c11d6eb0 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -232,7 +232,7 @@
     <string name="adb_wireless_list_empty_off" msgid="1713707973837255490">"Para ver y usar los dispositivos disponibles, activa la depuración inalámbrica"</string>
     <string name="adb_pair_method_qrcode_title" msgid="6982904096137468634">"Vincular dispositivo mediante código QR"</string>
     <string name="adb_pair_method_qrcode_summary" msgid="7130694277228970888">"Vincular dispositivos nuevos mediante escáner de código QR"</string>
-    <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincular dispositivo con código de sincronización"</string>
+    <string name="adb_pair_method_code_title" msgid="1122590300445142904">"Vincular dispositivo con un código de vinculación"</string>
     <string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Vincular dispositivos nuevos mediante código de seis dígitos"</string>
     <string name="adb_paired_devices_title" msgid="5268997341526217362">"Dispositivos vinculados"</string>
     <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Conectado actualmente"</string>
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> para completar"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Se pausó la carga"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rápidamente"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index fdf99e0..1ef351a 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> hasta la carga completa"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> hasta la carga completa"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Carga en pausa"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconocido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carga rápida"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index bcd395c..e156011 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Täislaadimiseks kulub <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – täislaadimiseks kulub <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – laadimine on peatatud"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tundmatu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laadimine"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Kiirlaadimine"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index cd1e7d1..e5f399c 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Kargatze-prozesua etenda dago"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ezezaguna"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kargatzen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Bizkor kargatzen"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index d40f692..ccacfde 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> تا شارژ کامل باقی مانده است"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - شارژ موقتاً متوقف شده است"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ناشناس"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"در حال شارژ شدن"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"درحال شارژ شدن سریع"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 0d6036a..101dc67 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kunnes täynnä"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kunnes täynnä"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Lataus on keskeytetty"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tuntematon"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ladataan"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Nopea lataus"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index f276236..ff58a51 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> jusqu\'à la recharge complète"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la recharge complète)"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - La recharge est interrompue"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Charge en cours…"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Recharge rapide"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 7c4afa7..f9725f6 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Chargée à 100 %% dans <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - chargée à 100 %% dans <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – La recharge est en pause"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Batterie en charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Charge rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 95d5e21..3ceb99c 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> para completar a carga"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> (<xliff:g id="TIME">%2$s</xliff:g> para completar a carga)"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: a carga está en pausa"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Descoñecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Cargando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Cargando rapidamente"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index e8acbd5..1821546 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%1$s</xliff:g> બાકી છે"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - પૂર્ણ ચાર્જ થવામાં <xliff:g id="TIME">%2$s</xliff:g> બાકી છે"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ચાર્જિંગ થોભાવવામાં આવ્યું છે"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"અજાણ્યું"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ચાર્જ થઈ રહ્યું છે"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ઝડપથી ચાર્જ થાય છે"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index b1ef50a..4b899bb 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> में बैटरी पूरी चार्ज हो जाएगी"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्जिंग को रोका गया है"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हो रही है"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"तेज़ चार्ज हो रही है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 06166f6..46c8b90 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do napunjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do napunjenosti"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – punjenje je pauzirano"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nepoznato"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Punjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Brzo punjenje"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index af5a114..d74490f 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> a teljes töltöttségig"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> a teljes töltöttségig"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – A töltés szünetel"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ismeretlen"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Töltés"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Gyorstöltés"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 61c3e7e..c26f94f 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> մինչև լրիվ լիցքավորումը"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Լիցքավորումը դադարեցված է"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Անհայտ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Լիցքավորում"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Արագ լիցքավորում"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index d7f5857..203485f 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sampai penuh"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sampai penuh"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengisian daya dijeda"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengisi daya"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengisi daya cepat"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 4862904..9185877 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> fram að fullri hleðslu"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> fram að fullri hleðslu"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Hlé var gert á hleðslu"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Óþekkt"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Í hleðslu"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hröð hleðsla"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9e5a224..0cd9e1e 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> alla ricarica completa"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> alla ricarica completa"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ricarica in pausa"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Sconosciuta"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"In carica"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ricarica veloce"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index c6afad9..6293105 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – הזמן הנותר לטעינה מלאה: <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – הטעינה הושהתה"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"לא ידוע"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"בטעינה"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"הסוללה נטענת מהר"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 43fe178..9a9d6ea 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"完了まであと <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 完了まであと <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充電は一時停止中"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"急速充電中"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index c498b61..2fa2d80 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — სრულ დატენვამდე დარჩენილია <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - დატენვა ᲨეᲩერებულია"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"უცნობი"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"იტენება"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"სწრაფად იტენება"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 314683b..a332004 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Толық зарядталғанға дейін <xliff:g id="TIME">%1$s</xliff:g> қалды."</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – толық зарядталғанға дейін <xliff:g id="TIME">%2$s</xliff:g> қалды."</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – зарядтау кідіртілді."</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгісіз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Зарядталуда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Жылдам зарядталуда"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 00668fe..2d78295 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - នៅសល់ <xliff:g id="TIME">%2$s</xliff:g> ទៀតទើបពេញ"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ការសាកថ្មត្រូវបានផ្អាក"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"មិន​ស្គាល់"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"កំពុងសាក​ថ្ម"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"កំពុងសាកថ្មយ៉ាងឆាប់រហ័ស"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index ebf742b..5db4b16 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> - ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ಸಮಯದಲ್ಲಿ ಪೂರ್ತಿ ಚಾರ್ಜ್ ಆಗುತ್ತದೆ"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ಚಾರ್ಜಿಂಗ್ ಅನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ಅಪರಿಚಿತ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ವೇಗದ ಚಾರ್ಜಿಂಗ್"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 21c8091..30ab26c 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> 후 충전 완료"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> 후 충전 완료"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 충전 일시중지됨"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"알 수 없음"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"충전 중"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"고속 충전 중"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 076f317a..baacfd7 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> кийин толук кубатталат"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> кийин толук кубатталат"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Кубаттоо тындырылды"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Белгисиз"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Кубатталууда"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ыкчам кубатталууда"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 9ebe67a..36755f7 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ຍັງເຫຼືອອີກ <xliff:g id="TIME">%1$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"ຍັງເຫຼືອອີກ <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> ຈຶ່ງຈະສາກເຕັມ"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ການສາກໄຟຖືກຢຸດໄວ້ຊົ່ວຄາວ"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ກຳລັງສາກໄຟ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ກຳລັງສາກໄຟດ່ວນ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index fcea778..50652ea 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Liko <xliff:g id="TIME">%1$s</xliff:g>, kol bus visiškai įkrauta"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – liko <xliff:g id="TIME">%2$s</xliff:g>, kol bus visiškai įkrauta"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – įkrovimas pristabdytas"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nežinomas"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Kraunasi..."</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Greitai įkraunama"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index c280737..c199fea 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> līdz pilnai uzlādei"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> — <xliff:g id="TIME">%2$s</xliff:g> līdz pilnai uzlādei"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> — uzlāde ir pārtraukta"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nezināms"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Uzlāde"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Notiek ātrā uzlāde"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index f849900..957f68b 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полна батерија"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> до полна батерија"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Полнењето е паузирано"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Се полни"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо полнење"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index cc15e03..1cc92ca 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"പൂർണ്ണമാകാൻ <xliff:g id="TIME">%1$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - പൂർണ്ണമാകാൻ <xliff:g id="TIME">%2$s</xliff:g> ശേഷിക്കുന്നു"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ചാർജിംഗ് താൽക്കാലികമായി നിർത്തി"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"അജ്ഞാതം"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ചാർജ് ചെയ്യുന്നു"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"അതിവേഗ ചാർജിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 3701a30..a107c70 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Дүүрэх хүртэл <xliff:g id="TIME">%1$s</xliff:g> үлдсэн"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - дүүрэх хүртэл <xliff:g id="TIME">%2$s</xliff:g> үлдсэн"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Цэнэглэхийг түр зогсоосон"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Тодорхойгүй"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Цэнэглэж байна"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Хурдан цэнэглэж байна"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 3fffc1a..d5c83a8 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%1$s</xliff:g> शिल्लक आहेत"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूर्ण चार्ज होण्यासाठी <xliff:g id="TIME">%2$s</xliff:g> शिल्लक आहे"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज करणे थांबवले आहे"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज होत आहे"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"वेगाने चार्ज होत आहे"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index 79553c0..ae8be8e 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> lagi sebelum penuh"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> lagi sebelum penuh"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Pengecasan dijeda"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Tidak diketahui"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Mengecas"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mengecas dgn cepat"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index fc38626..f16cdca 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"အားပြည့်ရန် <xliff:g id="TIME">%1$s</xliff:g> လိုသည်"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"အားပြည့်ရန် <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> လိုသည်"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - အားသွင်းခြင်းကို ခဏရပ်ထားသည်"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"မသိ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"အားသွင်းနေပါသည်"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"အမြန် အားသွင်းနေသည်"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 59a2517..f7a10a6 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Fulladet om <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Fulladet om <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ladingen er satt på pause"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Ukjent"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Lader"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Lader raskt"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 777c897..a966f15 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"पूरा चार्ज हुन <xliff:g id="TIME">%1$s</xliff:g> लाग्ने छ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - पूरा चार्ज हुन <xliff:g id="TIME">%2$s</xliff:g> लाग्ने छ"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - चार्ज गर्ने प्रक्रिया रोकिएको छ"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"अज्ञात"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"चार्ज हुँदै छ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"द्रुत गतिमा चार्ज गरिँदै छ"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index d30a21f..c5406ee 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Vol over <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - vol over <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Opladen is onderbroken"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Onbekend"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Opladen"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Snel opladen"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 0120768..37cc25e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%1$s</xliff:g> ବାକି ଅଛି"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ପୂର୍ଣ୍ଣ ହେବାକୁ ଆଉ <xliff:g id="TIME">%2$s</xliff:g> ବାକି ଅଛି"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ଚାର୍ଜିଂକୁ ବିରତ କରାଯାଇଛି"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ଅଜ୍ଞାତ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ଚାର୍ଜ ହେଉଛି"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 1481767..767cbc5 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%1$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਬੈਟਰੀ ਪੂਰੀ ਚਾਰਜ ਹੋਣ ਵਿੱਚ <xliff:g id="TIME">%2$s</xliff:g> ਬਾਕੀ"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ਚਾਰਜਿੰਗ ਨੂੰ ਰੋਕਿਆ ਗਿਆ ਹੈ"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ਅਗਿਆਤ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 83f8e49..48bc82e 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do pełnego naładowania"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do pełnego naładowania"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – ładowanie zostało wstrzymane"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Nieznane"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Ładowanie"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Szybkie ładowanie"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index d9a7c69..68a1c49 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: o carregamento está pausado"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c24589c..87bab50 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até à carga máxima"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> até à carga máxima"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – O carregamento está pausado"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"A carregar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregamento rápido"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index d9a7c69..68a1c49 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g>: <xliff:g id="TIME">%2$s</xliff:g> até a conclusão"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: o carregamento está pausado"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Desconhecido"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Carregando"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Carregando rápido"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 04c58ae..f81ef4c 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> până la finalizare"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> până la finalizare"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Încărcarea este întreruptă"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Necunoscut"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Se încarcă"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Se încarcă rapid"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 704d848..4dcee13 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до полной зарядки"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до полной зарядки"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: зарядка приостановлена"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Неизвестно"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Идет зарядка"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Быстрая зарядка"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index d67060e..17c59ea 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"සම්පූර්ණ වීමට <xliff:g id="TIME">%1$s</xliff:g>ක් ඉතිරියි"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - සම්පූර්ණ වීමට <xliff:g id="TIME">%2$s</xliff:g>ක් ඉතිරියි"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ආරෝපණය විරාම කර ඇත"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"නොදනී"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ආරෝපණය වෙමින්"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"ශීඝ්‍ර ආරෝපණය"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 1982893..d9ce6cf 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> do úplného nabitia"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> do úplného nabitia"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Nabíjanie je pozastavené"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznáme"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nabíja sa"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Rýchle nabíjanie"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 262ecfd..8f9b059 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Še <xliff:g id="TIME">%1$s</xliff:g> do napolnjenosti"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – še <xliff:g id="TIME">%2$s</xliff:g> do napolnjenosti"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Polnjenje je začasno zaustavljeno"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Neznano"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Polnjenje"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hitro polnjenje"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index d0f1f7c..d467eea 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> derisa të mbushet"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> derisa të mbushet"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Karikimi është vendosur në pauzë"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"I panjohur"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Po karikohet"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Karikim i shpejtë"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index b102d3a..9cc43d9 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до краја пуњења"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до краја пуњења"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Пуњење је заустављено"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Непознато"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Пуни се"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Брзо се пуни"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 17a06c2..89deafa 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> kvar tills fulladdat"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> kvar tills fulladdat"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Laddningen har pausats"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Okänd"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Laddar"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Laddas snabbt"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 72a3751..1fa5edd 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Zimesalia <xliff:g id="TIME">%1$s</xliff:g> ijae chaji"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> zimesalia ijae chaji"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Imesitisha kuchaji"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Haijulikani"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Inachaji"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Inachaji kwa kasi"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 8714958..1b7b643 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"முழுவதும் சார்ஜாக <xliff:g id="TIME">%1$s</xliff:g> ஆகும்"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - முழுவதும் சார்ஜாக <xliff:g id="TIME">%2$s</xliff:g> ஆகும்"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - சார்ஜ் ஏறுவது இடைநிறுத்தப்பட்டுள்ளது"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"அறியப்படாத"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"சார்ஜ் ஆகிறது"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"வேகமாக சார்ஜாகிறது"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 5e00b1d..27e9dbd 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>లో పూర్తిగా ఛార్జ్ అవుతుంది"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - ఛార్జింగ్ పాజ్ చేయబడింది"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"తెలియదు"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"ఛార్జ్ అవుతోంది"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"వేగవంతమైన ఛార్జింగ్"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index f386e5d..6b9c077 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"อีก <xliff:g id="TIME">%1$s</xliff:g>จึงจะเต็ม"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - อีก <xliff:g id="TIME">%2$s</xliff:g> จึงจะเต็ม"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - การชาร์จหยุดชั่วคราว"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"ไม่ทราบ"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"กำลังชาร์จ"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"กำลังชาร์จอย่างเร็ว"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index db27382..fddc1d0 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> na lang bago mapuno"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> na lang bago mapuno"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Naka-pause ang pag-charge"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Hindi Kilala"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Nagcha-charge"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Mabilis na charge"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 8f4bae4..31dcedb8 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Tamamen şarj olmasına <xliff:g id="TIME">%1$s</xliff:g> kaldı"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - Tamamen şarj olmasına <xliff:g id="TIME">%2$s</xliff:g> kaldı"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g>: Şarj işlemi duraklatıldı"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Bilinmiyor"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Şarj oluyor"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Hızlı şarj oluyor"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index a0c68c1..2fdc227 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> до повного заряду"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Заряджання призупинено"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Невідомо"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Заряджається"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Швидке заряджання"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index d0a1204..82dbdb3 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"مکمل چارج ہونے میں <xliff:g id="TIME">%1$s</xliff:g> باقی ہے"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"مکمل چارج ہونے میں <xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> باقی ہے"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - چارجنگ موقوف ہے"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"نامعلوم"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"چارج ہو رہا ہے"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"تیزی سے چارج ہو رہا ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index efb5eb9..ab997b6 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"Toʻlishiga <xliff:g id="TIME">%1$s</xliff:g> qoldi"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – Toʻlishiga <xliff:g id="TIME">%2$s</xliff:g> qoldi"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Quvvatlash pauza qilindi"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Noma’lum"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Quvvat olmoqda"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Tezkor quvvat olmoqda"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index f7f4c0e..44c820a5 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -268,7 +268,7 @@
     <string name="mock_location_app_set" msgid="4706722469342913843">"Ứng dụng vị trí mô phỏng: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="6829757985772659599">"Mạng"</string>
     <string name="wifi_display_certification" msgid="1805579519992520381">"Chứng nhận hiển thị không dây"</string>
-    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Bật ghi nhật ký chi tiết Wi‑Fi"</string>
+    <string name="wifi_verbose_logging" msgid="1785910450009679371">"Bật tính năng ghi nhật ký chi tiết Wi‑Fi"</string>
     <string name="wifi_scan_throttling" msgid="2985624788509913617">"Hạn chế quét tìm Wi-Fi"</string>
     <string name="wifi_non_persistent_mac_randomization" msgid="7482769677894247316">"Tạo địa chỉ MAC ngẫu nhiên, không cố định mỗi khi kết nối Wi-Fi"</string>
     <string name="mobile_data_always_on" msgid="8275958101875563572">"Dữ liệu di động luôn hoạt động"</string>
@@ -280,7 +280,7 @@
     <string name="bluetooth_select_avrcp_version_dialog_title" msgid="7846922290083709633">"Chọn phiên bản Bluetooth AVRCP"</string>
     <string name="bluetooth_select_map_version_string" msgid="526308145174175327">"Phiên bản Bluetooth MAP"</string>
     <string name="bluetooth_select_map_version_dialog_title" msgid="7085934373987428460">"Chọn phiên bản Bluetooth MAP"</string>
-    <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Codec âm thanh Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_type" msgid="952001408455456494">"Bộ mã hoá và giải mã âm thanh qua Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="7510542404227225545">"Kích hoạt chế độ chọn codec\nâm thanh Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="1638623076480928191">"Tốc độ lấy mẫu âm thanh Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="5876305103137067798">"Kích hoạt chế độ chọn codec\nâm thanh Bluetooth: Tần số lấy mẫu"</string>
@@ -374,7 +374,7 @@
     <string name="window_blurs" msgid="6831008984828425106">"Cho phép làm mờ cửa sổ"</string>
     <string name="force_msaa" msgid="4081288296137775550">"Bắt buộc 4x MSAA"</string>
     <string name="force_msaa_summary" msgid="9070437493586769500">"Bật 4x MSAA trong ứng dụng OpenGL ES 2.0"</string>
-    <string name="show_non_rect_clip" msgid="7499758654867881817">"Gỡ lỗi hoạt động của clip không phải là hình chữ nhật"</string>
+    <string name="show_non_rect_clip" msgid="7499758654867881817">"Gỡ lỗi hoạt động của đoạn không phải hình chữ nhật"</string>
     <string name="track_frame_time" msgid="522674651937771106">"Kết xuất HWUI cấu hình"</string>
     <string name="enable_gpu_debug_layers" msgid="4986675516188740397">"Bật lớp gỡ lỗi GPU"</string>
     <string name="enable_gpu_debug_layers_summary" msgid="4921521407377170481">"Cho phép tải lớp gỡ lỗi GPU cho ứng dụng gỡ lỗi"</string>
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> nữa là pin đầy"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g> nữa là pin đầy"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> – Đã tạm dừng sạc"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Không xác định"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Đang sạc"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Đang sạc nhanh"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index f536bb9..eae1c39 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"还需<xliff:g id="TIME">%1$s</xliff:g>充满"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - 还需<xliff:g id="TIME">%2$s</xliff:g>充满"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 充电已暂停"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"正在充电"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"正在快速充电"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 357302b..4371bb3 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充滿電"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充滿電"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"未知"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 4ae28304..d76a4a4 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g>後充飽"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>後充飽"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - 已暫停充電"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"不明"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"充電中"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"快速充電中"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index c113dc8..4dc7651 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -468,6 +468,8 @@
     <string name="power_remaining_charging_duration_only" msgid="8085099012811384899">"<xliff:g id="TIME">%1$s</xliff:g> okusele kuze kugcwale"</string>
     <string name="power_charging_duration" msgid="6127154952524919719">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> okusele kuze kugcwale"</string>
     <string name="power_charging_limited" msgid="6971664137170239141">"<xliff:g id="LEVEL">%1$s</xliff:g> - Ukushaja kumisiwe okwesikhashana"</string>
+    <!-- no translation found for power_charging_future_paused (6829683663982987290) -->
+    <skip />
     <string name="battery_info_status_unknown" msgid="268625384868401114">"Akwaziwa"</string>
     <string name="battery_info_status_charging" msgid="4279958015430387405">"Iyashaja"</string>
     <string name="battery_info_status_charging_fast" msgid="8027559755902954885">"Ishaja ngokushesha"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 2e0155b..b693996 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -1104,7 +1104,9 @@
     <!-- [CHAR_LIMIT=40] Label for battery level chart when charging with duration -->
     <string name="power_charging_duration"><xliff:g id="level">%1$s</xliff:g> - <xliff:g id="time">%2$s</xliff:g> left until full</string>
     <!-- [CHAR_LIMIT=80] Label for battery level chart when charge been limited -->
-    <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging is paused</string>
+    <string name="power_charging_limited"><xliff:g id="level">%1$s</xliff:g> - Charging paused</string>
+    <!-- [CHAR_LIMIT=80] Label for battery charging future pause -->
+    <string name="power_charging_future_paused"><xliff:g id="level">%1$s</xliff:g> - Charging to <xliff:g id="dock_defender_threshold">%2$s</xliff:g></string>
 
     <!-- Battery Info screen. Value for a status item.  Used for diagnostic info screens, precise translation isn't needed -->
     <string name="battery_info_status_unknown">Unknown</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 65c94ce..ca5f57d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1598,6 +1598,11 @@
          */
         public boolean isHomeApp;
 
+        /**
+         * Whether or not it's a cloned app .
+         */
+        public boolean isCloned;
+
         public String getNormalizedLabel() {
             if (normalizedLabel != null) {
                 return normalizedLabel;
@@ -1637,7 +1642,12 @@
                 ThreadUtils.postOnBackgroundThread(
                         () -> this.ensureLabelDescriptionLocked(context));
             }
-            this.showInPersonalTab = shouldShowInPersonalTab(context, info.uid);
+            UserManager um = UserManager.get(context);
+            this.showInPersonalTab = shouldShowInPersonalTab(um, info.uid);
+            UserInfo userInfo = um.getUserInfo(UserHandle.getUserId(info.uid));
+            if (userInfo != null) {
+                this.isCloned = userInfo.isCloneProfile();
+            }
         }
 
         /**
@@ -1645,8 +1655,7 @@
          * {@link UserProperties#SHOW_IN_SETTINGS_WITH_PARENT} set.
          */
         @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
-        boolean shouldShowInPersonalTab(Context context, int uid) {
-            UserManager userManager = UserManager.get(context);
+        boolean shouldShowInPersonalTab(UserManager userManager, int uid) {
             int userId = UserHandle.getUserId(uid);
 
             // Regardless of apk version, if the app belongs to the current user then return true.
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index 5c796af..a36cbc0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -115,12 +115,24 @@
         }
 
         List<LocalBluetoothProfile> profiles = cachedDevice.getProfiles();
+        int resId = 0;
         for (LocalBluetoothProfile profile : profiles) {
-            int resId = profile.getDrawableResource(btClass);
-            if (resId != 0) {
-                return new Pair<>(getBluetoothDrawable(context, resId), null);
+            int profileResId = profile.getDrawableResource(btClass);
+            if (profileResId != 0) {
+                // The device should show hearing aid icon if it contains any hearing aid related
+                // profiles
+                if (profile instanceof HearingAidProfile || profile instanceof HapClientProfile) {
+                    return new Pair<>(getBluetoothDrawable(context, profileResId), null);
+                }
+                if (resId == 0) {
+                    resId = profileResId;
+                }
             }
         }
+        if (resId != 0) {
+            return new Pair<>(getBluetoothDrawable(context, resId), null);
+        }
+
         if (btClass != null) {
             if (doesClassMatch(btClass, BluetoothClass.PROFILE_HEADSET)) {
                 return new Pair<>(
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 9583a59..61c7fb9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -77,9 +77,7 @@
     private final LocalBluetoothProfileManager mProfileManager;
     private final Object mProfileLock = new Object();
     BluetoothDevice mDevice;
-    private int mDeviceSide;
-    private int mDeviceMode;
-    private long mHiSyncId;
+    private HearingAidInfo mHearingAidInfo;
     private int mGroupId;
 
     // Need this since there is no method for getting RSSI
@@ -160,7 +158,6 @@
         mProfileManager = profileManager;
         mDevice = device;
         fillData();
-        mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
         mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
         initDrawableCache();
         mUnpairing = false;
@@ -339,32 +336,34 @@
         connectDevice();
     }
 
-    public int getDeviceSide() {
-        return mDeviceSide;
+    public HearingAidInfo getHearingAidInfo() {
+        return mHearingAidInfo;
     }
 
-    public void setDeviceSide(int side) {
-        mDeviceSide = side;
+    public void setHearingAidInfo(HearingAidInfo hearingAidInfo) {
+        mHearingAidInfo = hearingAidInfo;
+    }
+
+    /**
+     * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device
+     */
+    public boolean isHearingAidDevice() {
+        return mHearingAidInfo != null;
+    }
+
+    public int getDeviceSide() {
+        return mHearingAidInfo != null
+                ? mHearingAidInfo.getSide() : HearingAidInfo.DeviceSide.SIDE_INVALID;
     }
 
     public int getDeviceMode() {
-        return mDeviceMode;
-    }
-
-    public void setDeviceMode(int mode) {
-        mDeviceMode = mode;
+        return mHearingAidInfo != null
+                ? mHearingAidInfo.getMode() : HearingAidInfo.DeviceMode.MODE_INVALID;
     }
 
     public long getHiSyncId() {
-        return mHiSyncId;
-    }
-
-    public void setHiSyncId(long id) {
-        mHiSyncId = id;
-    }
-
-    public boolean isHearingAidDevice() {
-        return mHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID;
+        return mHearingAidInfo != null
+                ? mHearingAidInfo.getHiSyncId() : BluetoothHearingAid.HI_SYNC_ID_INVALID;
     }
 
     /**
@@ -784,8 +783,6 @@
         ParcelUuid[] localUuids = new ParcelUuid[uuidsList.size()];
         uuidsList.toArray(localUuids);
 
-        if (localUuids == null) return false;
-
         /*
          * Now we know if the device supports PBAP, update permissions...
          */
@@ -1167,15 +1164,24 @@
 
                 // Try to show left/right information if can not get it from battery for hearing
                 // aids specifically.
-                if (mIsActiveDeviceHearingAid
+                boolean isActiveAshaHearingAid = mIsActiveDeviceHearingAid;
+                boolean isActiveLeAudioHearingAid = mIsActiveDeviceLeAudio
+                        && isConnectedHapClientDevice();
+                if ((isActiveAshaHearingAid || isActiveLeAudioHearingAid)
                         && stringRes == R.string.bluetooth_active_no_battery_level) {
+                    final Set<CachedBluetoothDevice> memberDevices = getMemberDevice();
                     final CachedBluetoothDevice subDevice = getSubDevice();
-                    if (subDevice != null && subDevice.isConnected()) {
+                    if (memberDevices.stream().anyMatch(m -> m.isConnected())) {
+                        stringRes = R.string.bluetooth_hearing_aid_left_and_right_active;
+                    } else if (subDevice != null && subDevice.isConnected()) {
                         stringRes = R.string.bluetooth_hearing_aid_left_and_right_active;
                     } else {
-                        if (mDeviceSide == HearingAidProfile.DeviceSide.SIDE_LEFT) {
+                        int deviceSide = getDeviceSide();
+                        if (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT_AND_RIGHT) {
+                            stringRes = R.string.bluetooth_hearing_aid_left_and_right_active;
+                        } else if (deviceSide == HearingAidInfo.DeviceSide.SIDE_LEFT) {
                             stringRes = R.string.bluetooth_hearing_aid_left_active;
-                        } else if (mDeviceSide == HearingAidProfile.DeviceSide.SIDE_RIGHT) {
+                        } else if (deviceSide == HearingAidInfo.DeviceSide.SIDE_RIGHT) {
                             stringRes = R.string.bluetooth_hearing_aid_right_active;
                         } else {
                             stringRes = R.string.bluetooth_active_no_battery_level;
@@ -1371,15 +1377,41 @@
     }
 
     /**
-     * @return {@code true} if {@code cachedBluetoothDevice} is Hearing Aid device
+     * @return {@code true} if {@code cachedBluetoothDevice} is ASHA hearing aid device
      */
-    public boolean isConnectedHearingAidDevice() {
+    public boolean isConnectedAshaHearingAidDevice() {
         HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
         return hearingAidProfile != null && hearingAidProfile.getConnectionStatus(mDevice) ==
                 BluetoothProfile.STATE_CONNECTED;
     }
 
     /**
+     * @return {@code true} if {@code cachedBluetoothDevice} is HAP device
+     */
+    public boolean isConnectedHapClientDevice() {
+        HapClientProfile hapClientProfile = mProfileManager.getHapClientProfile();
+        return hapClientProfile != null && hapClientProfile.getConnectionStatus(mDevice)
+                == BluetoothProfile.STATE_CONNECTED;
+    }
+
+    /**
+     * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio hearing aid device
+     */
+    public boolean isConnectedLeAudioHearingAidDevice() {
+        return isConnectedHapClientDevice() && isConnectedLeAudioDevice();
+    }
+
+    /**
+     * @return {@code true} if {@code cachedBluetoothDevice} is hearing aid device
+     *
+     * The device may be an ASHA hearing aid that supports {@link HearingAidProfile} or a LeAudio
+     * hearing aid that supports {@link HapClientProfile} and {@link LeAudioProfile}.
+     */
+    public boolean isConnectedHearingAidDevice() {
+        return isConnectedAshaHearingAidDevice() || isConnectedLeAudioHearingAidDevice();
+    }
+
+    /**
      * @return {@code true} if {@code cachedBluetoothDevice} is LeAudio device
      */
     public boolean isConnectedLeAudioDevice() {
@@ -1407,17 +1439,17 @@
         BluetoothDevice tmpDevice = mDevice;
         final short tmpRssi = mRssi;
         final boolean tmpJustDiscovered = mJustDiscovered;
-        final int tmpDeviceSide = mDeviceSide;
+        final HearingAidInfo tmpHearingAidInfo = mHearingAidInfo;
         // Set main device from sub device
         mDevice = mSubDevice.mDevice;
         mRssi = mSubDevice.mRssi;
         mJustDiscovered = mSubDevice.mJustDiscovered;
-        mDeviceSide = mSubDevice.mDeviceSide;
+        mHearingAidInfo = mSubDevice.mHearingAidInfo;
         // Set sub device from backup
         mSubDevice.mDevice = tmpDevice;
         mSubDevice.mRssi = tmpRssi;
         mSubDevice.mJustDiscovered = tmpJustDiscovered;
-        mSubDevice.mDeviceSide = tmpDeviceSide;
+        mSubDevice.mHearingAidInfo = tmpHearingAidInfo;
         fetchActiveDevices();
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
index cf4e1ee..ebfec0a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidDeviceManager.java
@@ -27,7 +27,7 @@
 import java.util.Set;
 
 /**
- * HearingAidDeviceManager manages the set of remote HearingAid Bluetooth devices.
+ * HearingAidDeviceManager manages the set of remote HearingAid(ASHA) Bluetooth devices.
  */
 public class HearingAidDeviceManager {
     private static final String TAG = "HearingAidDeviceManager";
@@ -44,12 +44,12 @@
     void initHearingAidDeviceIfNeeded(CachedBluetoothDevice newDevice) {
         long hiSyncId = getHiSyncId(newDevice.getDevice());
         if (isValidHiSyncId(hiSyncId)) {
-            // Once hiSyncId is valid, assign hiSyncId
-            newDevice.setHiSyncId(hiSyncId);
-            final int side = getDeviceSide(newDevice.getDevice());
-            final int mode = getDeviceMode(newDevice.getDevice());
-            newDevice.setDeviceSide(side);
-            newDevice.setDeviceMode(mode);
+            // Once hiSyncId is valid, assign hearing aid info
+            final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                    .setAshaDeviceSide(getDeviceSide(newDevice.getDevice()))
+                    .setAshaDeviceMode(getDeviceMode(newDevice.getDevice()))
+                    .setHiSyncId(hiSyncId);
+            newDevice.setHearingAidInfo(infoBuilder.build());
         }
     }
 
@@ -123,12 +123,14 @@
                 final long newHiSyncId = getHiSyncId(cachedDevice.getDevice());
                 // Do nothing if there is no HiSyncId on Bluetooth device
                 if (isValidHiSyncId(newHiSyncId)) {
-                    cachedDevice.setHiSyncId(newHiSyncId);
+                    // Once hiSyncId is valid, assign hearing aid info
+                    final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                            .setAshaDeviceSide(getDeviceSide(cachedDevice.getDevice()))
+                            .setAshaDeviceMode(getDeviceMode(cachedDevice.getDevice()))
+                            .setHiSyncId(newHiSyncId);
+                    cachedDevice.setHearingAidInfo(infoBuilder.build());
+
                     newSyncIdSet.add(newHiSyncId);
-                    final int side = getDeviceSide(cachedDevice.getDevice());
-                    final int mode = getDeviceMode(cachedDevice.getDevice());
-                    cachedDevice.setDeviceSide(side);
-                    cachedDevice.setDeviceMode(mode);
                 }
             }
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java
new file mode 100644
index 0000000..ef08c92
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidInfo.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.annotation.IntDef;
+import android.bluetooth.BluetoothHearingAid;
+import android.bluetooth.BluetoothLeAudio;
+import android.util.SparseIntArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
+
+/** Hearing aids information and constants that shared within hearing aids related profiles */
+public class HearingAidInfo {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DeviceSide.SIDE_INVALID,
+            DeviceSide.SIDE_LEFT,
+            DeviceSide.SIDE_RIGHT,
+            DeviceSide.SIDE_LEFT_AND_RIGHT,
+    })
+
+    /** Side definition for hearing aids. */
+    public @interface DeviceSide {
+        int SIDE_INVALID = -1;
+        int SIDE_LEFT = 0;
+        int SIDE_RIGHT = 1;
+        int SIDE_LEFT_AND_RIGHT = 2;
+    }
+
+    @Retention(java.lang.annotation.RetentionPolicy.SOURCE)
+    @IntDef({
+            DeviceMode.MODE_INVALID,
+            DeviceMode.MODE_MONAURAL,
+            DeviceMode.MODE_BINAURAL,
+            DeviceMode.MODE_BANDED,
+    })
+
+    /** Mode definition for hearing aids. */
+    public @interface DeviceMode {
+        int MODE_INVALID = -1;
+        int MODE_MONAURAL = 0;
+        int MODE_BINAURAL = 1;
+        int MODE_BANDED = 2;
+    }
+
+    private final int mSide;
+    private final int mMode;
+    private final long mHiSyncId;
+
+    private HearingAidInfo(int side, int mode, long hiSyncId) {
+        mSide = side;
+        mMode = mode;
+        mHiSyncId = hiSyncId;
+    }
+
+    @DeviceSide
+    public int getSide() {
+        return mSide;
+    }
+
+    @DeviceMode
+    public int getMode() {
+        return mMode;
+    }
+
+    public long getHiSyncId() {
+        return mHiSyncId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof HearingAidInfo)) {
+            return false;
+        }
+        HearingAidInfo that = (HearingAidInfo) o;
+        return mSide == that.mSide && mMode == that.mMode && mHiSyncId == that.mHiSyncId;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mSide, mMode, mHiSyncId);
+    }
+
+    @Override
+    public String toString() {
+        return "HearingAidInfo{"
+                + "mSide=" + mSide
+                + ", mMode=" + mMode
+                + ", mHiSyncId=" + mHiSyncId
+                + '}';
+    }
+
+    @DeviceSide
+    private static int convertAshaDeviceSideToInternalSide(int ashaDeviceSide) {
+        return ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.get(
+                ashaDeviceSide, DeviceSide.SIDE_INVALID);
+    }
+
+    @DeviceMode
+    private static int convertAshaDeviceModeToInternalMode(int ashaDeviceMode) {
+        return ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.get(
+                ashaDeviceMode, DeviceMode.MODE_INVALID);
+    }
+
+    @DeviceSide
+    private static int convertLeAudioLocationToInternalSide(int leAudioLocation) {
+        boolean isLeft = (leAudioLocation & LE_AUDIO_LOCATION_LEFT) != 0;
+        boolean isRight = (leAudioLocation & LE_AUDIO_LOCATION_RIGHT) != 0;
+        if (isLeft && isRight) {
+            return DeviceSide.SIDE_LEFT_AND_RIGHT;
+        } else if (isLeft) {
+            return DeviceSide.SIDE_LEFT;
+        } else if (isRight) {
+            return DeviceSide.SIDE_RIGHT;
+        }
+        return DeviceSide.SIDE_INVALID;
+    }
+
+    @DeviceMode
+    private static int convertHapDeviceTypeToInternalMode(int hapDeviceType) {
+        return HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.get(hapDeviceType, DeviceMode.MODE_INVALID);
+    }
+
+    /** Builder class for constructing {@link HearingAidInfo} objects. */
+    public static final class Builder {
+        private int mSide = DeviceSide.SIDE_INVALID;
+        private int mMode = DeviceMode.MODE_INVALID;
+        private long mHiSyncId = BluetoothHearingAid.HI_SYNC_ID_INVALID;
+
+        /**
+         * Configure the hearing device mode.
+         * @param ashaDeviceMode one of the hearing aid device modes defined in HearingAidProfile
+         * {@link HearingAidProfile.DeviceMode}
+         */
+        public Builder setAshaDeviceMode(int ashaDeviceMode) {
+            mMode = convertAshaDeviceModeToInternalMode(ashaDeviceMode);
+            return this;
+        }
+
+        /**
+         * Configure the hearing device mode.
+         * @param hapDeviceType one of the hearing aid device types defined in HapClientProfile
+         * {@link HapClientProfile.HearingAidType}
+         */
+        public Builder setHapDeviceType(int hapDeviceType) {
+            mMode = convertHapDeviceTypeToInternalMode(hapDeviceType);
+            return this;
+        }
+
+        /**
+         * Configure the hearing device side.
+         * @param ashaDeviceSide one of the hearing aid device sides defined in HearingAidProfile
+         * {@link HearingAidProfile.DeviceSide}
+         */
+        public Builder setAshaDeviceSide(int ashaDeviceSide) {
+            mSide = convertAshaDeviceSideToInternalSide(ashaDeviceSide);
+            return this;
+        }
+
+        /**
+         * Configure the hearing device side.
+         * @param leAudioLocation one of the audio location defined in BluetoothLeAudio
+         * {@link BluetoothLeAudio.AudioLocation}
+         */
+        public Builder setLeAudioLocation(int leAudioLocation) {
+            mSide = convertLeAudioLocationToInternalSide(leAudioLocation);
+            return this;
+        }
+
+        /**
+         * Configure the hearing aid hiSyncId.
+         * @param hiSyncId the ASHA hearing aid id
+         */
+        public Builder setHiSyncId(long hiSyncId) {
+            mHiSyncId = hiSyncId;
+            return this;
+        }
+
+        /** Build the configured {@link HearingAidInfo} */
+        public HearingAidInfo build() {
+            return new HearingAidInfo(mSide, mMode, mHiSyncId);
+        }
+    }
+
+    private static final int LE_AUDIO_LOCATION_LEFT =
+            BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BACK_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_OF_CENTER
+                    | BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_LEFT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_LEFT_WIDE
+                    | BluetoothLeAudio.AUDIO_LOCATION_LEFT_SURROUND;
+
+    private static final int LE_AUDIO_LOCATION_RIGHT =
+            BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BACK_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_OF_CENTER
+                    | BluetoothLeAudio.AUDIO_LOCATION_SIDE_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_BACK_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_TOP_SIDE_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_BOTTOM_FRONT_RIGHT
+                    | BluetoothLeAudio.AUDIO_LOCATION_FRONT_RIGHT_WIDE
+                    | BluetoothLeAudio.AUDIO_LOCATION_RIGHT_SURROUND;
+
+    private static final SparseIntArray ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING;
+    private static final SparseIntArray ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING;
+    private static final SparseIntArray HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING;
+
+    static {
+        ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING = new SparseIntArray();
+        ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put(
+                HearingAidProfile.DeviceSide.SIDE_INVALID, DeviceSide.SIDE_INVALID);
+        ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put(
+                HearingAidProfile.DeviceSide.SIDE_LEFT, DeviceSide.SIDE_LEFT);
+        ASHA_DEVICE_SIDE_TO_INTERNAL_SIDE_MAPPING.put(
+                HearingAidProfile.DeviceSide.SIDE_RIGHT, DeviceSide.SIDE_RIGHT);
+
+        ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING = new SparseIntArray();
+        ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put(
+                HearingAidProfile.DeviceMode.MODE_INVALID, DeviceMode.MODE_INVALID);
+        ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put(
+                HearingAidProfile.DeviceMode.MODE_MONAURAL, DeviceMode.MODE_MONAURAL);
+        ASHA_DEVICE_MODE_TO_INTERNAL_MODE_MAPPING.put(
+                HearingAidProfile.DeviceMode.MODE_BINAURAL, DeviceMode.MODE_BINAURAL);
+
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING = new SparseIntArray();
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put(
+                HapClientProfile.HearingAidType.TYPE_INVALID, DeviceMode.MODE_INVALID);
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put(
+                HapClientProfile.HearingAidType.TYPE_BINAURAL, DeviceMode.MODE_BINAURAL);
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put(
+                HapClientProfile.HearingAidType.TYPE_MONAURAL, DeviceMode.MODE_MONAURAL);
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put(
+                HapClientProfile.HearingAidType.TYPE_BANDED, DeviceMode.MODE_BANDED);
+        HAP_DEVICE_TYPE_TO_INTERNAL_MODE_MAPPING.put(
+                HapClientProfile.HearingAidType.TYPE_RFU, DeviceMode.MODE_INVALID);
+
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
index fb861da..a3c2e70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -21,6 +21,7 @@
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHapClient;
 import android.bluetooth.BluetoothHeadset;
 import android.bluetooth.BluetoothHeadsetClient;
 import android.bluetooth.BluetoothHearingAid;
@@ -103,6 +104,7 @@
     private PbapClientProfile mPbapClientProfile;
     private PbapServerProfile mPbapProfile;
     private HearingAidProfile mHearingAidProfile;
+    private HapClientProfile mHapClientProfile;
     private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile;
     private LeAudioProfile mLeAudioProfile;
     private LocalBluetoothLeBroadcast mLeAudioBroadcast;
@@ -189,6 +191,12 @@
             addProfile(mHearingAidProfile, HearingAidProfile.NAME,
                     BluetoothHearingAid.ACTION_CONNECTION_STATE_CHANGED);
         }
+        if (mHapClientProfile == null && supportedList.contains(BluetoothProfile.HAP_CLIENT)) {
+            if (DEBUG) Log.d(TAG, "Adding local HAP_CLIENT profile");
+            mHapClientProfile = new HapClientProfile(mContext, mDeviceManager, this);
+            addProfile(mHapClientProfile, HapClientProfile.NAME,
+                    BluetoothHapClient.ACTION_HAP_CONNECTION_STATE_CHANGED);
+        }
         if (mHidProfile == null && supportedList.contains(BluetoothProfile.HID_HOST)) {
             if (DEBUG) Log.d(TAG, "Adding local HID_HOST profile");
             mHidProfile = new HidProfile(mContext, mDeviceManager, this);
@@ -337,25 +345,44 @@
                 Log.i(TAG, "Failed to connect " + mProfile + " device");
             }
 
-            if (getHearingAidProfile() != null &&
-                mProfile instanceof HearingAidProfile &&
-                (newState == BluetoothProfile.STATE_CONNECTED)) {
-                final int side = getHearingAidProfile().getDeviceSide(cachedDevice.getDevice());
-                final int mode = getHearingAidProfile().getDeviceMode(cachedDevice.getDevice());
-                cachedDevice.setDeviceSide(side);
-                cachedDevice.setDeviceMode(mode);
+            if (getHearingAidProfile() != null
+                    && mProfile instanceof HearingAidProfile
+                    && (newState == BluetoothProfile.STATE_CONNECTED)) {
 
                 // Check if the HiSyncID has being initialized
                 if (cachedDevice.getHiSyncId() == BluetoothHearingAid.HI_SYNC_ID_INVALID) {
                     long newHiSyncId = getHearingAidProfile().getHiSyncId(cachedDevice.getDevice());
                     if (newHiSyncId != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
-                        cachedDevice.setHiSyncId(newHiSyncId);
+                        final BluetoothDevice device = cachedDevice.getDevice();
+                        final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                                .setAshaDeviceSide(getHearingAidProfile().getDeviceSide(device))
+                                .setAshaDeviceMode(getHearingAidProfile().getDeviceMode(device))
+                                .setHiSyncId(newHiSyncId);
+                        cachedDevice.setHearingAidInfo(infoBuilder.build());
                     }
                 }
-
                 HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
             }
 
+            final boolean isHapClientProfile = getHapClientProfile() != null
+                    && mProfile instanceof HapClientProfile;
+            final boolean isLeAudioProfile = getLeAudioProfile() != null
+                    && mProfile instanceof LeAudioProfile;
+            final boolean isHapClientOrLeAudioProfile = isHapClientProfile || isLeAudioProfile;
+            if (isHapClientOrLeAudioProfile && newState == BluetoothProfile.STATE_CONNECTED) {
+
+                // Checks if both profiles are connected to the device. Hearing aid info need
+                // to be retrieved from these profiles separately.
+                if (cachedDevice.isConnectedLeAudioHearingAidDevice()) {
+                    final BluetoothDevice device = cachedDevice.getDevice();
+                    final HearingAidInfo.Builder infoBuilder = new HearingAidInfo.Builder()
+                            .setLeAudioLocation(getLeAudioProfile().getAudioLocation(device))
+                            .setHapDeviceType(getHapClientProfile().getHearingAidType(device));
+                    cachedDevice.setHearingAidInfo(infoBuilder.build());
+                    HearingAidStatsLogUtils.logHearingAidInfo(cachedDevice);
+                }
+            }
+
             if (getCsipSetCoordinatorProfile() != null
                     && mProfile instanceof CsipSetCoordinatorProfile
                     && newState == BluetoothProfile.STATE_CONNECTED) {
@@ -524,6 +551,10 @@
         return mHearingAidProfile;
     }
 
+    public HapClientProfile getHapClientProfile() {
+        return mHapClientProfile;
+    }
+
     public LeAudioProfile getLeAudioProfile() {
         return mLeAudioProfile;
     }
@@ -675,6 +706,11 @@
             removedProfiles.remove(mHearingAidProfile);
         }
 
+        if (mHapClientProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.HAS)) {
+            profiles.add(mHapClientProfile);
+            removedProfiles.remove(mHapClientProfile);
+        }
+
         if (mSapProfile != null && ArrayUtils.contains(uuids, BluetoothUuid.SAP)) {
             profiles.add(mSapProfile);
             removedProfiles.remove(mSapProfile);
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
index 132a631..8b68a09 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatteryStatus.java
@@ -66,7 +66,7 @@
     public BatteryStatus(Intent batteryChangedIntent) {
         status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
         plugged = batteryChangedIntent.getIntExtra(EXTRA_PLUGGED, 0);
-        level = batteryChangedIntent.getIntExtra(EXTRA_LEVEL, 0);
+        level = getBatteryLevel(batteryChangedIntent);
         health = batteryChangedIntent.getIntExtra(EXTRA_HEALTH, BATTERY_HEALTH_UNKNOWN);
         present = batteryChangedIntent.getBooleanExtra(EXTRA_PRESENT, true);
 
@@ -188,7 +188,7 @@
      */
     public static boolean isCharged(Intent batteryChangedIntent) {
         int status = batteryChangedIntent.getIntExtra(EXTRA_STATUS, BATTERY_STATUS_UNKNOWN);
-        int level = batteryChangedIntent.getIntExtra(EXTRA_LEVEL, 0);
+        int level = getBatteryLevel(batteryChangedIntent);
         return isCharged(status, level);
     }
 
@@ -204,4 +204,13 @@
     public static boolean isCharged(int status, int level) {
         return status == BATTERY_STATUS_FULL || level >= 100;
     }
+
+    /** Gets the battery level from the intent. */
+    public static int getBatteryLevel(Intent batteryChangedIntent) {
+        final int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
+        final int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 0);
+        return scale == 0
+                ? -1 /*invalid battery level*/
+                : Math.round((level / (float) scale) * 100f);
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
index df6929e..b3a52b9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
@@ -16,6 +16,7 @@
 package com.android.settingslib.media;
 
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHearingAid;
 import android.media.MediaRoute2Info;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -32,7 +33,9 @@
      */
     public static String getId(CachedBluetoothDevice cachedDevice) {
         if (cachedDevice.isHearingAidDevice()) {
-            return Long.toString(cachedDevice.getHiSyncId());
+            if (cachedDevice.getHiSyncId() != BluetoothHearingAid.HI_SYNC_ID_INVALID) {
+                return Long.toString(cachedDevice.getHiSyncId());
+            }
         }
         return cachedDevice.getAddress();
     }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index 336cdd3..291f6a3 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -317,7 +317,9 @@
 
     @Test
     public void getBatteryStatus_statusIsFull_returnFullString() {
-        final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100);
+        final Intent intent = new Intent()
+                .putExtra(BatteryManager.EXTRA_LEVEL, 100)
+                .putExtra(BatteryManager.EXTRA_SCALE, 100);
         final Resources resources = mContext.getResources();
 
         assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ false)).isEqualTo(
@@ -326,7 +328,9 @@
 
     @Test
     public void getBatteryStatus_statusIsFullAndUseCompactStatus_returnFullyChargedString() {
-        final Intent intent = new Intent().putExtra(BatteryManager.EXTRA_LEVEL, 100);
+        final Intent intent = new Intent()
+                .putExtra(BatteryManager.EXTRA_LEVEL, 100)
+                .putExtra(BatteryManager.EXTRA_SCALE, 100);
         final Resources resources = mContext.getResources();
 
         assertThat(Utils.getBatteryStatus(mContext, intent, /* compactStatus= */ true)).isEqualTo(
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
index 39875f7..96e64ea 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java
@@ -755,28 +755,30 @@
 
     @Test
     public void shouldShowInPersonalTab_forCurrentUser_returnsTrue() {
+        UserManager um = RuntimeEnvironment.application.getSystemService(UserManager.class);
         ApplicationInfo appInfo = createApplicationInfo(PKG_1);
         AppEntry primaryUserApp = createAppEntry(appInfo, 1);
 
-        assertThat(primaryUserApp.shouldShowInPersonalTab(mContext, appInfo.uid)).isTrue();
+        assertThat(primaryUserApp.shouldShowInPersonalTab(um, appInfo.uid)).isTrue();
     }
 
     @Test
     public void shouldShowInPersonalTab_userProfilePreU_returnsFalse() {
+        UserManager um = RuntimeEnvironment.application.getSystemService(UserManager.class);
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT",
                 Build.VERSION_CODES.TIRAMISU);
         // Create an app (and subsequent AppEntry) in a non-primary user profile.
         ApplicationInfo appInfo1 = createApplicationInfo(PKG_1, PROFILE_UID_1);
         AppEntry nonPrimaryUserApp = createAppEntry(appInfo1, 1);
 
-        assertThat(nonPrimaryUserApp.shouldShowInPersonalTab(mContext, appInfo1.uid)).isFalse();
+        assertThat(nonPrimaryUserApp.shouldShowInPersonalTab(um, appInfo1.uid)).isFalse();
     }
 
     @Test
     public void shouldShowInPersonalTab_currentUserIsParent_returnsAsPerUserPropertyOfProfile1() {
         // Mark system user as parent for both profile users.
-        ShadowUserManager shadowUserManager = Shadow
-                .extract(RuntimeEnvironment.application.getSystemService(UserManager.class));
+        UserManager um = RuntimeEnvironment.application.getSystemService(UserManager.class);
+        ShadowUserManager shadowUserManager = Shadow.extract(um);
         shadowUserManager.addProfile(USER_SYSTEM, PROFILE_USERID,
                 CLONE_USER, 0);
         shadowUserManager.addProfile(USER_SYSTEM, PROFILE_USERID2,
@@ -796,7 +798,7 @@
         AppEntry nonPrimaryUserApp1 = createAppEntry(appInfo1, 1);
         AppEntry nonPrimaryUserApp2 = createAppEntry(appInfo2, 2);
 
-        assertThat(nonPrimaryUserApp1.shouldShowInPersonalTab(mContext, appInfo1.uid)).isTrue();
-        assertThat(nonPrimaryUserApp2.shouldShowInPersonalTab(mContext, appInfo2.uid)).isFalse();
+        assertThat(nonPrimaryUserApp1.shouldShowInPersonalTab(um, appInfo1.uid)).isTrue();
+        assertThat(nonPrimaryUserApp2.shouldShowInPersonalTab(um, appInfo2.uid)).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 61802a8..f06623d 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
@@ -327,8 +327,10 @@
         when(mDevice1.getBondState()).thenReturn(BluetoothDevice.BOND_BONDED);
         CachedBluetoothDevice cachedDevice1 = mCachedDeviceManager.addDevice(mDevice1);
         CachedBluetoothDevice cachedDevice2 = mCachedDeviceManager.addDevice(mDevice2);
-        cachedDevice1.setHiSyncId(HISYNCID1);
-        cachedDevice2.setHiSyncId(HISYNCID1);
+        cachedDevice1.setHearingAidInfo(
+                new HearingAidInfo.Builder().setHiSyncId(HISYNCID1).build());
+        cachedDevice2.setHearingAidInfo(
+                new HearingAidInfo.Builder().setHiSyncId(HISYNCID1).build());
         cachedDevice1.setSubDevice(cachedDevice2);
 
         // Call onDeviceUnpaired for the one in mCachedDevices.
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 79e9938..65671a2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -29,6 +29,7 @@
 
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothLeAudio;
 import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
@@ -74,6 +75,10 @@
     @Mock
     private HearingAidProfile mHearingAidProfile;
     @Mock
+    private HapClientProfile mHapClientProfile;
+    @Mock
+    private LeAudioProfile mLeAudioProfile;
+    @Mock
     private BluetoothDevice mDevice;
     @Mock
     private BluetoothDevice mSubDevice;
@@ -354,7 +359,7 @@
         assertThat(mCachedDevice.getConnectionSummary()).isNull();
 
         // Set device as Active for Hearing Aid and test connection state summary
-        mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
+        mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only");
 
@@ -399,7 +404,7 @@
         //   1. Profile:       {HEARING_AID, Connected, Active, Right ear}
         //   2. Audio Manager: In Call
         updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
-        mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo());
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
 
@@ -413,9 +418,9 @@
         // Arrange:
         //   1. Profile:       {HEARING_AID, Connected, Active, Both ear}
         //   2. Audio Manager: In Call
-        mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        mCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo());
         updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
-        mSubCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
+        mSubCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
         updateSubDeviceProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.setSubDevice(mSubCachedDevice);
         mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.HEARING_AID);
@@ -443,6 +448,26 @@
     }
 
     @Test
+    public void getConnectionSummary_testActiveDeviceLeAudioHearingAid() {
+        // Test without battery level
+        // Set HAP Client and LE Audio profile to be connected and test connection state summary
+        when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+        updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Set device as Active for LE Audio and test connection state summary
+        mCachedDevice.setHearingAidInfo(getLeftLeAudioHearingAidInfo());
+        mCachedDevice.onActiveDeviceChanged(true, BluetoothProfile.LE_AUDIO);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo("Active, left only");
+
+        // Set LE Audio profile to be disconnected and test connection state summary
+        mCachedDevice.onActiveDeviceChanged(false, BluetoothProfile.LE_AUDIO);
+        mCachedDevice.onProfileStateChanged(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
     public void getConnectionSummary_testMultipleProfilesActiveDevice() {
         // Test without battery level
         // Set A2DP and HFP profiles to be connected and test connection state summary
@@ -859,21 +884,21 @@
     }
 
     @Test
-    public void isConnectedHearingAidDevice_connected_returnTrue() {
+    public void isConnectedAshaHearingAidDevice_connected_returnTrue() {
         when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
         when(mHearingAidProfile.getConnectionStatus(mDevice)).
                 thenReturn(BluetoothProfile.STATE_CONNECTED);
 
-        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue();
+        assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isTrue();
     }
 
     @Test
-    public void isConnectedHearingAidDevice_disconnected_returnFalse() {
+    public void isConnectedAshaHearingAidDevice_disconnected_returnFalse() {
         when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
         when(mHearingAidProfile.getConnectionStatus(mDevice)).
                 thenReturn(BluetoothProfile.STATE_DISCONNECTED);
 
-        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
+        assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse();
     }
 
     @Test
@@ -891,10 +916,10 @@
     }
 
     @Test
-    public void isConnectedHearingAidDevice_profileIsNull_returnFalse() {
+    public void isConnectedAshaHearingAidDevice_profileIsNull_returnFalse() {
         when(mProfileManager.getHearingAidProfile()).thenReturn(null);
 
-        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
+        assertThat(mCachedDevice.isConnectedAshaHearingAidDevice()).isFalse();
     }
 
     @Test
@@ -965,10 +990,10 @@
 
         mCachedDevice.mRssi = RSSI_1;
         mCachedDevice.mJustDiscovered = JUSTDISCOVERED_1;
-        mCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
+        mCachedDevice.setHearingAidInfo(getLeftAshaHearingAidInfo());
         mSubCachedDevice.mRssi = RSSI_2;
         mSubCachedDevice.mJustDiscovered = JUSTDISCOVERED_2;
-        mSubCachedDevice.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        mSubCachedDevice.setHearingAidInfo(getRightAshaHearingAidInfo());
         mCachedDevice.setSubDevice(mSubCachedDevice);
 
         mCachedDevice.switchSubDeviceContent();
@@ -976,22 +1001,20 @@
         assertThat(mCachedDevice.mRssi).isEqualTo(RSSI_2);
         assertThat(mCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_2);
         assertThat(mCachedDevice.mDevice).isEqualTo(mSubDevice);
-        assertThat(mCachedDevice.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+        assertThat(mCachedDevice.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_RIGHT);
         assertThat(mSubCachedDevice.mRssi).isEqualTo(RSSI_1);
         assertThat(mSubCachedDevice.mJustDiscovered).isEqualTo(JUSTDISCOVERED_1);
         assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
-        assertThat(mSubCachedDevice.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+        assertThat(mSubCachedDevice.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_LEFT);
     }
 
     @Test
     public void getConnectionSummary_profileConnectedFail_showErrorMessage() {
-        final A2dpProfile profle = mock(A2dpProfile.class);
-        mCachedDevice.onProfileStateChanged(profle, BluetoothProfile.STATE_CONNECTED);
+        final A2dpProfile profile = mock(A2dpProfile.class);
+        mCachedDevice.onProfileStateChanged(profile, BluetoothProfile.STATE_CONNECTED);
         mCachedDevice.setProfileConnectedStatus(BluetoothProfile.A2DP, true);
 
-        when(profle.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED);
+        when(profile.getConnectionStatus(mDevice)).thenReturn(BluetoothProfile.STATE_CONNECTED);
 
         assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(
                 mContext.getString(R.string.profile_connect_timeout_subtext));
@@ -1069,4 +1092,55 @@
         assertThat(mSubCachedDevice.mDevice).isEqualTo(mDevice);
         assertThat(mCachedDevice.getMemberDevice().contains(mSubCachedDevice)).isTrue();
     }
+
+    @Test
+    public void isConnectedHearingAidDevice_isConnectedAshaHearingAidDevice_returnTrue() {
+        when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_CONNECTED);
+
+        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue();
+    }
+
+    @Test
+    public void isConnectedHearingAidDevice_isConnectedLeAudioHearingAidDevice_returnTrue() {
+        when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+
+        updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_CONNECTED);
+        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_CONNECTED);
+
+        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isTrue();
+    }
+
+    @Test
+    public void isConnectedHearingAidDevice_isNotAnyConnectedHearingAidDevice_returnFalse() {
+        when(mProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile);
+        when(mProfileManager.getHapClientProfile()).thenReturn(mHapClientProfile);
+        when(mProfileManager.getLeAudioProfile()).thenReturn(mLeAudioProfile);
+
+        updateProfileStatus(mHearingAidProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mHapClientProfile, BluetoothProfile.STATE_DISCONNECTED);
+        updateProfileStatus(mLeAudioProfile, BluetoothProfile.STATE_DISCONNECTED);
+
+        assertThat(mCachedDevice.isConnectedHearingAidDevice()).isFalse();
+    }
+
+    private HearingAidInfo getLeftAshaHearingAidInfo() {
+        return new HearingAidInfo.Builder()
+                .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT)
+                .build();
+    }
+
+    private HearingAidInfo getRightAshaHearingAidInfo() {
+        return new HearingAidInfo.Builder()
+                .setAshaDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT)
+                .build();
+    }
+
+    private HearingAidInfo getLeftLeAudioHearingAidInfo() {
+        return new HearingAidInfo.Builder()
+                .setLeAudioLocation(BluetoothLeAudio.AUDIO_LOCATION_SIDE_LEFT)
+                .build();
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 611b0a4..470d8e0 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -17,6 +17,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
@@ -106,7 +107,7 @@
      * deviceSide, deviceMode.
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfos() {
+    public void initHearingAidDeviceIfNeeded_validHiSyncId_setHearingAidInfo() {
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(HISYNCID1);
         when(mHearingAidProfile.getDeviceMode(mDevice1)).thenReturn(
                 HearingAidProfile.DeviceMode.MODE_BINAURAL);
@@ -118,21 +119,22 @@
 
         assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
         assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
     }
 
     /**
      * Test initHearingAidDeviceIfNeeded, an invalid HiSyncId will not be assigned
      */
     @Test
-    public void initHearingAidDeviceIfNeeded_invalidHiSyncId_notToSetHiSyncId() {
+    public void initHearingAidDeviceIfNeeded_invalidHiSyncId_notToSetHearingAidInfo() {
         when(mHearingAidProfile.getHiSyncId(mDevice1)).thenReturn(
                 BluetoothHearingAid.HI_SYNC_ID_INVALID);
+
         mHearingAidDeviceManager.initHearingAidDeviceIfNeeded(mCachedDevice1);
 
-        verify(mCachedDevice1, never()).setHiSyncId(anyLong());
+        verify(mCachedDevice1, never()).setHearingAidInfo(any(HearingAidInfo.class));
     }
 
     /**
@@ -140,9 +142,10 @@
      */
     @Test
     public void setSubDeviceIfNeeded_sameHiSyncId_setSubDevice() {
-        mCachedDevice1.setHiSyncId(HISYNCID1);
-        mCachedDevice2.setHiSyncId(HISYNCID1);
+        mCachedDevice1.setHearingAidInfo(getLeftAshaHearingAidInfo(HISYNCID1));
+        mCachedDevice2.setHearingAidInfo(getRightAshaHearingAidInfo(HISYNCID1));
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
         mHearingAidDeviceManager.setSubDeviceIfNeeded(mCachedDevice2);
 
         assertThat(mCachedDevice1.getSubDevice()).isEqualTo(mCachedDevice2);
@@ -153,9 +156,10 @@
      */
     @Test
     public void setSubDeviceIfNeeded_differentHiSyncId_notSetSubDevice() {
-        mCachedDevice1.setHiSyncId(HISYNCID1);
-        mCachedDevice2.setHiSyncId(HISYNCID2);
+        mCachedDevice1.setHearingAidInfo(getLeftAshaHearingAidInfo(HISYNCID1));
+        mCachedDevice2.setHearingAidInfo(getRightAshaHearingAidInfo(HISYNCID2));
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
+
         mHearingAidDeviceManager.setSubDeviceIfNeeded(mCachedDevice2);
 
         assertThat(mCachedDevice1.getSubDevice()).isNull();
@@ -276,9 +280,9 @@
 
         assertThat(mCachedDevice1.getHiSyncId()).isEqualTo(HISYNCID1);
         assertThat(mCachedDevice1.getDeviceMode()).isEqualTo(
-                HearingAidProfile.DeviceMode.MODE_BINAURAL);
+                HearingAidInfo.DeviceMode.MODE_BINAURAL);
         assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
+                HearingAidInfo.DeviceSide.SIDE_RIGHT);
         verify(mHearingAidDeviceManager).onHiSyncIdChanged(HISYNCID1);
     }
 
@@ -389,11 +393,9 @@
     @Test
     public void onProfileConnectionStateChanged_disconnected_mainDevice_subDeviceConnected_switch()
     {
-        when(mCachedDevice1.getHiSyncId()).thenReturn(HISYNCID1);
-        mCachedDevice1.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_LEFT);
-        when(mCachedDevice2.getHiSyncId()).thenReturn(HISYNCID1);
+        mCachedDevice1.setHearingAidInfo(getLeftAshaHearingAidInfo(HISYNCID1));
+        mCachedDevice2.setHearingAidInfo(getRightAshaHearingAidInfo(HISYNCID1));
         when(mCachedDevice2.isConnected()).thenReturn(true);
-        mCachedDevice2.setDeviceSide(HearingAidProfile.DeviceSide.SIDE_RIGHT);
         mCachedDeviceManager.mCachedDevices.add(mCachedDevice1);
         mCachedDevice1.setSubDevice(mCachedDevice2);
 
@@ -404,10 +406,8 @@
 
         assertThat(mCachedDevice1.mDevice).isEqualTo(mDevice2);
         assertThat(mCachedDevice2.mDevice).isEqualTo(mDevice1);
-        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_RIGHT);
-        assertThat(mCachedDevice2.getDeviceSide()).isEqualTo(
-                HearingAidProfile.DeviceSide.SIDE_LEFT);
+        assertThat(mCachedDevice1.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_RIGHT);
+        assertThat(mCachedDevice2.getDeviceSide()).isEqualTo(HearingAidInfo.DeviceSide.SIDE_LEFT);
         verify(mCachedDevice1).refresh();
     }
 
@@ -455,4 +455,18 @@
         assertThat(mHearingAidDeviceManager.findMainDevice(mCachedDevice2)).
                 isEqualTo(mCachedDevice1);
     }
+
+    private HearingAidInfo getLeftAshaHearingAidInfo(long hiSyncId) {
+        return new HearingAidInfo.Builder()
+                .setAshaDeviceSide(HearingAidInfo.DeviceSide.SIDE_LEFT)
+                .setHiSyncId(hiSyncId)
+                .build();
+    }
+
+    private HearingAidInfo getRightAshaHearingAidInfo(long hiSyncId) {
+        return new HearingAidInfo.Builder()
+                .setAshaDeviceSide(HearingAidInfo.DeviceSide.SIDE_RIGHT)
+                .setHiSyncId(hiSyncId)
+                .build();
+    }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 98af15a..267c196 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -53,6 +53,7 @@
         Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
         Settings.Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN,
         Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
+        Settings.Secure.CONTRAST_LEVEL,
         Settings.Secure.ACCESSIBILITY_CAPTIONING_PRESET,
         Settings.Secure.ACCESSIBILITY_CAPTIONING_ENABLED,
         Settings.Secure.ACCESSIBILITY_CAPTIONING_LOCALE,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
index cf7c7c5..46876b4 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/GlobalSettingsValidators.java
@@ -336,6 +336,7 @@
         VALIDATORS.put(Global.Wearable.COOLDOWN_MODE_ON, BOOLEAN_VALIDATOR);
         VALIDATORS.put(
                 Global.Wearable.GESTURE_TOUCH_AND_HOLD_WATCH_FACE_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Global.Wearable.RSB_WAKE_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.CHARGING_SOUNDS_ENABLED, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Global.Wearable.BEDTIME_MODE, BOOLEAN_VALIDATOR);
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index 80af69c..def9c19 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -86,6 +86,7 @@
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_SHORTCUT_ON_LOCK_SCREEN, BOOLEAN_VALIDATOR);
         VALIDATORS.put(Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, BOOLEAN_VALIDATOR);
+        VALIDATORS.put(Secure.CONTRAST_LEVEL, new InclusiveFloatRangeValidator(-1f, 1f));
         VALIDATORS.put(
                 Secure.ACCESSIBILITY_CAPTIONING_PRESET,
                 new DiscreteValueValidator(new String[] {"-1", "0", "1", "2", "3", "4"}));
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 4e2bce2..17078c4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1762,6 +1762,9 @@
                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
                 SecureSettingsProto.Accessibility.HIGH_TEXT_CONTRAST_ENABLED);
         dumpSetting(s, p,
+                Settings.Secure.CONTRAST_LEVEL,
+                SecureSettingsProto.Accessibility.CONTRAST_LEVEL);
+        dumpSetting(s, p,
                 Settings.Secure.FONT_WEIGHT_ADJUSTMENT,
                 SecureSettingsProto.FONT_WEIGHT_ADJUSTMENT);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 24c1435..153f0b4 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -659,7 +659,8 @@
                     Settings.Global.Wearable.SCREEN_UNLOCK_SOUND_ENABLED,
                     Settings.Global.Wearable.BEDTIME_MODE,
                     Settings.Global.Wearable.BEDTIME_HARD_MODE,
-                    Settings.Global.Wearable.EARLY_UPDATES_STATUS);
+                    Settings.Global.Wearable.EARLY_UPDATES_STATUS,
+                    Settings.Global.Wearable.RSB_WAKE_ENABLED);
 
     private static final Set<String> BACKUP_DENY_LIST_SECURE_SETTINGS =
              newHashSet(
@@ -771,6 +772,7 @@
                  Settings.Secure.SLEEP_TIMEOUT,
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
                  Settings.Secure.SPELL_CHECKER_ENABLED,  // Intentionally removed in Q
+                 Settings.Secure.STYLUS_BUTTONS_DISABLED,
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
                  Settings.Secure.KNOWN_TRUST_AGENTS_INITIALIZED,
                  Settings.Secure.TV_APP_USES_NON_SYSTEM_INPUTS,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 01c0809..d3ba5e6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -754,6 +754,9 @@
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED" />
 
     <!-- Permission required for CTS test - CtsAppFgsTestCases -->
+    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_FILE_MANAGEMENT" />
+
+    <!-- Permission required for CTS test - CtsAppFgsTestCases -->
     <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
 
     <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
@@ -771,6 +774,80 @@
     <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
     <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
 
+    <!-- Permissions required for CTS test - CtsAppFgsTestCases -->
+    <uses-permission android:name="android.permission.health.READ_ACTIVE_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.READ_BASAL_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.READ_BASAL_METABOLIC_RATE" />
+    <uses-permission android:name="android.permission.health.READ_BLOOD_GLUCOSE" />
+    <uses-permission android:name="android.permission.health.READ_BLOOD_PRESSURE" />
+    <uses-permission android:name="android.permission.health.READ_BODY_FAT" />
+    <uses-permission android:name="android.permission.health.READ_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.READ_BODY_WATER_MASS" />
+    <uses-permission android:name="android.permission.health.READ_BONE_MASS" />
+    <uses-permission android:name="android.permission.health.READ_CERVICAL_MUCUS" />
+    <uses-permission android:name="android.permission.health.READ_DISTANCE" />
+    <uses-permission android:name="android.permission.health.READ_ELEVATION_GAINED" />
+    <uses-permission android:name="android.permission.health.READ_EXERCISE" />
+    <uses-permission android:name="android.permission.health.READ_FLOORS_CLIMBED" />
+    <uses-permission android:name="android.permission.health.READ_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.READ_HEART_RATE_VARIABILITY" />
+    <uses-permission android:name="android.permission.health.READ_HEIGHT" />
+    <uses-permission android:name="android.permission.health.READ_HIP_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.READ_HYDRATION" />
+    <uses-permission android:name="android.permission.health.READ_LEAN_BODY_MASS" />
+    <uses-permission android:name="android.permission.health.READ_MENSTRUATION" />
+    <uses-permission android:name="android.permission.health.READ_NUTRITION" />
+    <uses-permission android:name="android.permission.health.READ_OVULATION_TEST" />
+    <uses-permission android:name="android.permission.health.READ_OXYGEN_SATURATION" />
+    <uses-permission android:name="android.permission.health.READ_POWER" />
+    <uses-permission android:name="android.permission.health.READ_RESPIRATORY_RATE" />
+    <uses-permission android:name="android.permission.health.READ_RESTING_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.READ_SEXUAL_ACTIVITY" />
+    <uses-permission android:name="android.permission.health.READ_SLEEP" />
+    <uses-permission android:name="android.permission.health.READ_SPEED" />
+    <uses-permission android:name="android.permission.health.READ_STEPS" />
+    <uses-permission android:name="android.permission.health.READ_TOTAL_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.READ_VO2_MAX" />
+    <uses-permission android:name="android.permission.health.READ_WAIST_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.READ_WEIGHT" />
+    <uses-permission android:name="android.permission.health.READ_WHEELCHAIR_PUSHES" />
+    <uses-permission android:name="android.permission.health.WRITE_ACTIVE_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.WRITE_BASAL_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BASAL_METABOLIC_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_BLOOD_GLUCOSE" />
+    <uses-permission android:name="android.permission.health.WRITE_BLOOD_PRESSURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_FAT" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_TEMPERATURE" />
+    <uses-permission android:name="android.permission.health.WRITE_BODY_WATER_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_BONE_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_CERVICAL_MUCUS" />
+    <uses-permission android:name="android.permission.health.WRITE_DISTANCE" />
+    <uses-permission android:name="android.permission.health.WRITE_ELEVATION_GAINED" />
+    <uses-permission android:name="android.permission.health.WRITE_EXERCISE" />
+    <uses-permission android:name="android.permission.health.WRITE_FLOORS_CLIMBED" />
+    <uses-permission android:name="android.permission.health.WRITE_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_HEART_RATE_VARIABILITY" />
+    <uses-permission android:name="android.permission.health.WRITE_HEIGHT" />
+    <uses-permission android:name="android.permission.health.WRITE_HIP_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.WRITE_HYDRATION" />
+    <uses-permission android:name="android.permission.health.WRITE_LEAN_BODY_MASS" />
+    <uses-permission android:name="android.permission.health.WRITE_MENSTRUATION" />
+    <uses-permission android:name="android.permission.health.WRITE_NUTRITION" />
+    <uses-permission android:name="android.permission.health.WRITE_OVULATION_TEST" />
+    <uses-permission android:name="android.permission.health.WRITE_OXYGEN_SATURATION" />
+    <uses-permission android:name="android.permission.health.WRITE_POWER" />
+    <uses-permission android:name="android.permission.health.WRITE_RESPIRATORY_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_RESTING_HEART_RATE" />
+    <uses-permission android:name="android.permission.health.WRITE_SEXUAL_ACTIVITY" />
+    <uses-permission android:name="android.permission.health.WRITE_SLEEP" />
+    <uses-permission android:name="android.permission.health.WRITE_SPEED" />
+    <uses-permission android:name="android.permission.health.WRITE_STEPS" />
+    <uses-permission android:name="android.permission.health.WRITE_TOTAL_CALORIES_BURNED" />
+    <uses-permission android:name="android.permission.health.WRITE_VO2_MAX" />
+    <uses-permission android:name="android.permission.health.WRITE_WAIST_CIRCUMFERENCE" />
+    <uses-permission android:name="android.permission.health.WRITE_WEIGHT" />
+    <uses-permission android:name="android.permission.health.WRITE_WHEELCHAIR_PUSHES" />
+
     <!-- Permission required for CTS test - ApplicationExemptionsTests -->
     <uses-permission android:name="android.permission.MANAGE_DEVICE_POLICY_APP_EXEMPTIONS" />
 
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index 5c70edaf..87354c7 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -170,7 +170,6 @@
 android_library {
     name: "SystemUI-tests-base",
     manifest: "tests/AndroidManifest-base.xml",
-    
     resource_dirs: [
         "tests/res",
         "res-product",
@@ -224,30 +223,21 @@
         "LowLightDreamLib",
         "motion_tool_lib",
     ],
-    libs: [
-        "android.test.runner",
-        "android.test.base",
-        "android.test.mock",
-    ],
 }
 
-// Device tests only
 android_library {
     name: "SystemUI-tests",
-    manifest: "tests/AndroidManifest.xml",
+    manifest: "tests/AndroidManifest-base.xml",
     additional_manifests: ["tests/AndroidManifest.xml"],
-    resource_dirs: [],
     srcs: [
-        // Kotlin likes all files in the same module for internal
+        "tests/src/**/*.kt",
+        "tests/src/**/*.java",
         "src/**/*.kt",
         "src/**/*.java",
         "src/**/I*.aidl",
         ":ReleaseJavaFiles",
-        "tests/src/**/*.kt",
-        "tests/src/**/*.java",
         ":SystemUI-tests-utils",
     ],
-    dont_merge_manifests: true,
     static_libs: [
         "SystemUI-tests-base",
         "androidx.test.uiautomator_uiautomator",
@@ -276,12 +266,6 @@
         "platform_app_defaults",
         "SystemUI_app_defaults",
     ],
-    srcs: [
-        "src/**/*.kt",
-        "src/**/*.java",
-        "src/**/I*.aidl",
-        ":ReleaseJavaFiles",
-    ],
     manifest: "tests/AndroidManifest-base.xml",
     static_libs: [
         "SystemUI-tests-base",
@@ -296,13 +280,6 @@
     certificate: "platform",
     privileged: true,
     resource_dirs: [],
-
-    kotlincflags: ["-Xjvm-default=enable"],
-    dxflags: ["--multi-dex"],
-    required: [
-        "privapp_whitelist_com.android.systemui",
-    ],
-    plugins: ["dagger2-compiler"],
 }
 
 android_robolectric_test {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 11237dc..7db68b0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -126,6 +126,9 @@
     <uses-permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES" />
     <uses-permission android:name="android.permission.INPUT_CONSUMER" />
 
+    <!-- DeviceStateManager -->
+    <uses-permission android:name="android.permission.CONTROL_DEVICE_STATE" />
+
     <!-- DreamManager -->
     <uses-permission android:name="android.permission.READ_DREAM_STATE" />
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
diff --git a/packages/SystemUI/animation/Android.bp b/packages/SystemUI/animation/Android.bp
index f7bcf1f..17ad55f 100644
--- a/packages/SystemUI/animation/Android.bp
+++ b/packages/SystemUI/animation/Android.bp
@@ -36,8 +36,31 @@
 
     static_libs: [
         "PluginCoreLib",
+        "androidx.core_core-animation-nodeps",
+        "androidx.core_core-ktx",
+        "androidx.annotation_annotation",
     ],
 
     manifest: "AndroidManifest.xml",
     kotlincflags: ["-Xjvm-default=all"],
 }
+
+android_test {
+    name: "SystemUIAnimationLibTests",
+
+    static_libs: [
+        "SystemUIAnimationLib",
+        "androidx.test.ext.junit",
+        "androidx.test.rules",
+        "testables",
+    ],
+    libs: [
+        "android.test.base",
+    ],
+    srcs: [
+        "**/*.java",
+        "**/*.kt",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+    test_suites: ["general-tests"],
+}
diff --git a/packages/SystemUI/animation/TEST_MAPPING b/packages/SystemUI/animation/TEST_MAPPING
new file mode 100644
index 0000000..3dc8510
--- /dev/null
+++ b/packages/SystemUI/animation/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "SystemUIAnimationLibTests"
+    }
+  ]
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
index fdfad2b..54aa351 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/DialogLaunchAnimator.kt
@@ -75,7 +75,7 @@
      */
     interface Controller {
         /** The [ViewRootImpl] of this controller. */
-        val viewRoot: ViewRootImpl
+        val viewRoot: ViewRootImpl?
 
         /**
          * The identity object of the source animated by this controller. This animator will ensure
@@ -807,15 +807,17 @@
      * inversely, removed from the overlay when the source is moved back to its original position).
      */
     private fun synchronizeNextDraw(then: () -> Unit) {
-        if (forceDisableSynchronization) {
-            // Don't synchronize when inside an automated test.
+        val controllerRootView = controller.viewRoot?.view
+        if (forceDisableSynchronization || controllerRootView == null) {
+            // Don't synchronize when inside an automated test or if the controller root view is
+            // detached.
             then()
             return
         }
 
-        ViewRootSync.synchronizeNextDraw(controller.viewRoot.view, decorView, then)
+        ViewRootSync.synchronizeNextDraw(controllerRootView, decorView, then)
         decorView.invalidate()
-        controller.viewRoot.view.invalidate()
+        controllerRootView.invalidate()
     }
 
     private fun findFirstViewGroupWithBackground(view: View): ViewGroup? {
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 8063483..9dbb920 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -27,7 +27,10 @@
 import android.view.animation.PathInterpolator;
 
 /**
- * Utility class to receive interpolators from
+ * Utility class to receive interpolators from.
+ *
+ * Make sure that changes made to this class are also reflected in {@link InterpolatorsAndroidX}.
+ * Please consider using the androidx dependencies featuring better testability altogether.
  */
 public class Interpolators {
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
new file mode 100644
index 0000000..8da87feb
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/InterpolatorsAndroidX.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.animation;
+
+import android.graphics.Path;
+import android.util.MathUtils;
+
+import androidx.core.animation.AccelerateDecelerateInterpolator;
+import androidx.core.animation.AccelerateInterpolator;
+import androidx.core.animation.BounceInterpolator;
+import androidx.core.animation.DecelerateInterpolator;
+import androidx.core.animation.Interpolator;
+import androidx.core.animation.LinearInterpolator;
+import androidx.core.animation.PathInterpolator;
+
+/**
+ * Utility class to receive interpolators from. (androidx compatible version)
+ *
+ * This is the androidx compatible version of {@link Interpolators}. Make sure that changes made to
+ * this class are also reflected in {@link Interpolators}.
+ *
+ * Using the androidx versions of {@link androidx.core.animation.ValueAnimator} or
+ * {@link androidx.core.animation.ObjectAnimator} improves animation testability. This file provides
+ * the androidx compatible versions of the interpolators defined in {@link Interpolators}.
+ * AnimatorTestRule can be used in Tests to manipulate the animation under test (e.g. artificially
+ * advancing the time).
+ */
+public class InterpolatorsAndroidX {
+
+    /*
+     * ============================================================================================
+     * Emphasized interpolators.
+     * ============================================================================================
+     */
+
+    /**
+     * The default emphasized interpolator. Used for hero / emphasized movement of content.
+     */
+    public static final Interpolator EMPHASIZED = createEmphasizedInterpolator();
+
+    /**
+     * The accelerated emphasized interpolator. Used for hero / emphasized movement of content that
+     * is disappearing e.g. when moving off screen.
+     */
+    public static final Interpolator EMPHASIZED_ACCELERATE = new PathInterpolator(
+            0.3f, 0f, 0.8f, 0.15f);
+
+    /**
+     * The decelerating emphasized interpolator. Used for hero / emphasized movement of content that
+     * is appearing e.g. when coming from off screen
+     */
+    public static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
+            0.05f, 0.7f, 0.1f, 1f);
+
+
+    /*
+     * ============================================================================================
+     * Standard interpolators.
+     * ============================================================================================
+     */
+
+    /**
+     * The standard interpolator that should be used on every normal animation
+     */
+    public static final Interpolator STANDARD = new PathInterpolator(
+            0.2f, 0f, 0f, 1f);
+
+    /**
+     * The standard accelerating interpolator that should be used on every regular movement of
+     * content that is disappearing e.g. when moving off screen.
+     */
+    public static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(
+            0.3f, 0f, 1f, 1f);
+
+    /**
+     * The standard decelerating interpolator that should be used on every regular movement of
+     * content that is appearing e.g. when coming from off screen.
+     */
+    public static final Interpolator STANDARD_DECELERATE = new PathInterpolator(
+            0f, 0f, 0f, 1f);
+
+    /*
+     * ============================================================================================
+     * Legacy
+     * ============================================================================================
+     */
+
+    /**
+     * The default legacy interpolator as defined in Material 1. Also known as FAST_OUT_SLOW_IN.
+     */
+    public static final Interpolator LEGACY = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+
+    /**
+     * The default legacy accelerating interpolator as defined in Material 1.
+     * Also known as FAST_OUT_LINEAR_IN.
+     */
+    public static final Interpolator LEGACY_ACCELERATE = new PathInterpolator(0.4f, 0f, 1f, 1f);
+
+    /**
+     * The default legacy decelerating interpolator as defined in Material 1.
+     * Also known as LINEAR_OUT_SLOW_IN.
+     */
+    public static final Interpolator LEGACY_DECELERATE = new PathInterpolator(0f, 0f, 0.2f, 1f);
+
+    /**
+     * Linear interpolator. Often used if the interpolator is for different properties who need
+     * different interpolations.
+     */
+    public static final Interpolator LINEAR = new LinearInterpolator();
+
+    /*
+    * ============================================================================================
+    * Custom interpolators
+    * ============================================================================================
+    */
+
+    public static final Interpolator FAST_OUT_SLOW_IN = LEGACY;
+    public static final Interpolator FAST_OUT_LINEAR_IN = LEGACY_ACCELERATE;
+    public static final Interpolator LINEAR_OUT_SLOW_IN = LEGACY_DECELERATE;
+
+    /**
+     * Like {@link #FAST_OUT_SLOW_IN}, but used in case the animation is played in reverse (i.e. t
+     * goes from 1 to 0 instead of 0 to 1).
+     */
+    public static final Interpolator FAST_OUT_SLOW_IN_REVERSE =
+            new PathInterpolator(0.8f, 0f, 0.6f, 1f);
+    public static final Interpolator SLOW_OUT_LINEAR_IN = new PathInterpolator(0.8f, 0f, 1f, 1f);
+    public static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+    public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+    public static final Interpolator ACCELERATE = new AccelerateInterpolator();
+    public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
+    public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
+    public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
+    public static final Interpolator ICON_OVERSHOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f);
+    public static final Interpolator ICON_OVERSHOT_LESS = new PathInterpolator(0.4f, 0f, 0.2f,
+            1.1f);
+    public static final Interpolator PANEL_CLOSE_ACCELERATED = new PathInterpolator(0.3f, 0, 0.5f,
+            1);
+    public static final Interpolator BOUNCE = new BounceInterpolator();
+    /**
+     * For state transitions on the control panel that lives in GlobalActions.
+     */
+    public static final Interpolator CONTROL_STATE = new PathInterpolator(0.4f, 0f, 0.2f,
+            1.0f);
+
+    /**
+     * Interpolator to be used when animating a move based on a click. Pair with enough duration.
+     */
+    public static final Interpolator TOUCH_RESPONSE =
+            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
+    /**
+     * Like {@link #TOUCH_RESPONSE}, but used in case the animation is played in reverse (i.e. t
+     * goes from 1 to 0 instead of 0 to 1).
+     */
+    public static final Interpolator TOUCH_RESPONSE_REVERSE =
+            new PathInterpolator(0.9f, 0f, 0.7f, 1f);
+
+    /*
+     * ============================================================================================
+     * Functions / Utilities
+     * ============================================================================================
+     */
+
+    /**
+     * Calculate the amount of overshoot using an exponential falloff function with desired
+     * properties, where the overshoot smoothly transitions at the 1.0f boundary into the
+     * overshoot, retaining its acceleration.
+     *
+     * @param progress a progress value going from 0 to 1
+     * @param overshootAmount the amount > 0 of overshoot desired. A value of 0.1 means the max
+     *                        value of the overall progress will be at 1.1.
+     * @param overshootStart the point in (0,1] where the result should reach 1
+     * @return the interpolated overshoot
+     */
+    public static float getOvershootInterpolation(float progress, float overshootAmount,
+            float overshootStart) {
+        if (overshootAmount == 0.0f || overshootStart == 0.0f) {
+            throw new IllegalArgumentException("Invalid values for overshoot");
+        }
+        float b = MathUtils.log((overshootAmount + 1) / (overshootAmount)) / overshootStart;
+        return MathUtils.max(0.0f,
+                (float) (1.0f - Math.exp(-b * progress)) * (overshootAmount + 1.0f));
+    }
+
+    /**
+     * Similar to {@link #getOvershootInterpolation(float, float, float)} but the overshoot
+     * starts immediately here, instead of first having a section of non-overshooting
+     *
+     * @param progress a progress value going from 0 to 1
+     */
+    public static float getOvershootInterpolation(float progress) {
+        return MathUtils.max(0.0f, (float) (1.0f - Math.exp(-4 * progress)));
+    }
+
+    // Create the default emphasized interpolator
+    private static PathInterpolator createEmphasizedInterpolator() {
+        Path path = new Path();
+        // Doing the same as fast_out_extra_slow_in
+        path.moveTo(0f, 0f);
+        path.cubicTo(0.05f, 0f, 0.133333f, 0.06f, 0.166666f, 0.4f);
+        path.cubicTo(0.208333f, 0.82f, 0.25f, 1f, 1f, 1f);
+        return new PathInterpolator(path);
+    }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
index f9c6841..0e2d23b 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/RemoteTransitionAdapter.kt
@@ -195,8 +195,16 @@
             val out = ArrayList<RemoteAnimationTarget>()
             for (i in info.changes.indices) {
                 val change = info.changes[i]
-                val changeIsWallpaper = change.flags and TransitionInfo.FLAG_IS_WALLPAPER != 0
-                if (wallpapers != changeIsWallpaper) continue
+                if (change.hasFlags(TransitionInfo.FLAG_IN_TASK_WITH_EMBEDDED_ACTIVITY)) {
+                    // For embedded container, when the parent Task is also in the transition, we
+                    // should only animate the parent Task.
+                    if (change.parent != null) continue
+                    // For embedded container without parent, we should only animate if it fills
+                    // the Task. Otherwise we may animate only partial of the Task.
+                    if (!change.hasFlags(TransitionInfo.FLAG_FILLS_TASK)) continue
+                }
+                // Check if it is wallpaper
+                if (wallpapers != change.hasFlags(TransitionInfo.FLAG_IS_WALLPAPER)) continue
                 out.add(createTarget(change, info.changes.size - i, info, t))
                 if (leashMap != null) {
                     leashMap[change.leash] = out[out.size - 1].leash
@@ -320,9 +328,7 @@
                                 counterWallpaper.cleanUp(finishTransaction)
                                 // Release surface references now. This is apparently to free GPU
                                 // memory while doing quick operations (eg. during CTS).
-                                for (i in info.changes.indices.reversed()) {
-                                    info.changes[i].leash.release()
-                                }
+                                info.releaseAllSurfaces()
                                 for (i in leashMap.size - 1 downTo 0) {
                                     leashMap.valueAt(i).release()
                                 }
@@ -331,6 +337,7 @@
                                         null /* wct */,
                                         finishTransaction
                                     )
+                                    finishTransaction.close()
                                 } catch (e: RemoteException) {
                                     Log.e(
                                         "ActivityOptionsCompat",
@@ -364,6 +371,9 @@
                 ) {
                     // TODO: hook up merge to recents onTaskAppeared if applicable. Until then,
                     //       ignore any incoming merges.
+                    // Clean up stuff though cuz GC takes too long for benchmark tests.
+                    t.close()
+                    info.releaseAllSurfaces()
                 }
             }
         }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
index ecee598..964ef8c 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ViewDialogLaunchAnimatorController.kt
@@ -28,7 +28,7 @@
     private val source: View,
     override val cuj: DialogCuj?,
 ) : DialogLaunchAnimator.Controller {
-    override val viewRoot: ViewRootImpl
+    override val viewRoot: ViewRootImpl?
         get() = source.viewRootImpl
 
     override val sourceIdentity: Any = source
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleController.kt
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
new file mode 100644
index 0000000..b8dc223
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.surfaceeffects.ripple
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.util.Log
+import android.view.View
+import androidx.annotation.VisibleForTesting
+
+/**
+ * A view that allows multiple ripples to play.
+ *
+ * Use [MultiRippleController] to play ripple animations.
+ */
+class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+    val ripples = ArrayList<RippleAnimation>()
+    private val listeners = ArrayList<RipplesFinishedListener>()
+    private val ripplePaint = Paint()
+    private var isWarningLogged = false
+
+    companion object {
+        private const val TAG = "MultiRippleView"
+
+        interface RipplesFinishedListener {
+            /** Triggered when all the ripples finish running. */
+            fun onRipplesFinish()
+        }
+    }
+
+    fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
+        listeners.add(listener)
+    }
+
+    override fun onDraw(canvas: Canvas?) {
+        if (canvas == null || !canvas.isHardwareAccelerated) {
+            // Drawing with the ripple shader requires hardware acceleration, so skip
+            // if it's unsupported.
+            if (!isWarningLogged) {
+                // Only log once to not spam.
+                Log.w(
+                    TAG,
+                    "Can't draw ripple shader. $canvas does not support hardware acceleration."
+                )
+                isWarningLogged = true
+            }
+            return
+        }
+
+        var shouldInvalidate = false
+
+        ripples.forEach { anim ->
+            ripplePaint.shader = anim.rippleShader
+            canvas.drawPaint(ripplePaint)
+
+            shouldInvalidate = shouldInvalidate || anim.isPlaying()
+        }
+
+        if (shouldInvalidate) {
+            invalidate()
+        } else { // Nothing is playing.
+            listeners.forEach { listener -> listener.onRipplesFinish() }
+        }
+    }
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt
new file mode 100644
index 0000000..0e3d41c
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.surfaceeffects.ripple
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import androidx.annotation.VisibleForTesting
+import androidx.core.graphics.ColorUtils
+
+/** A single ripple animation. */
+class RippleAnimation(private val config: RippleAnimationConfig) {
+    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
+    val rippleShader: RippleShader = RippleShader(config.rippleShape)
+    private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
+
+    init {
+        applyConfigToShader()
+    }
+
+    /** Updates the ripple color during the animation. */
+    fun updateColor(color: Int) {
+        config.apply { config.color = color }
+        applyConfigToShader()
+    }
+
+    @JvmOverloads
+    fun play(onAnimationEnd: Runnable? = null) {
+        if (isPlaying()) {
+            return // Ignore if ripple effect is already playing
+        }
+
+        animator.duration = config.duration
+        animator.addUpdateListener { updateListener ->
+            val now = updateListener.currentPlayTime
+            val progress = updateListener.animatedValue as Float
+            rippleShader.progress = progress
+            rippleShader.distortionStrength = if (config.shouldDistort) 1 - progress else 0f
+            rippleShader.time = now.toFloat()
+        }
+        animator.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator?) {
+                    onAnimationEnd?.run()
+                }
+            }
+        )
+        animator.start()
+    }
+
+    /** Indicates whether the animation is playing. */
+    fun isPlaying(): Boolean = animator.isRunning
+
+    private fun applyConfigToShader() {
+        rippleShader.setCenter(config.centerX, config.centerY)
+        rippleShader.setMaxSize(config.maxWidth, config.maxHeight)
+        rippleShader.rippleFill = config.shouldFillRipple
+        rippleShader.pixelDensity = config.pixelDensity
+        rippleShader.color = ColorUtils.setAlphaComponent(config.color, config.opacity)
+        rippleShader.sparkleStrength = config.sparkleStrength
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleAnimationConfig.kt
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
new file mode 100644
index 0000000..f55fb97
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.surfaceeffects.ripple
+
+import android.graphics.PointF
+import android.graphics.RuntimeShader
+import android.util.MathUtils
+import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary
+import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
+
+/**
+ * Shader class that renders an expanding ripple effect. The ripple contains three elements:
+ *
+ * 1. an expanding filled [RippleShape] that appears in the beginning and quickly fades away
+ * 2. an expanding ring that appears throughout the effect
+ * 3. an expanding ring-shaped area that reveals noise over #2.
+ *
+ * The ripple shader will be default to the circle shape if not specified.
+ *
+ * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
+ */
+class RippleShader(rippleShape: RippleShape = RippleShape.CIRCLE) :
+    RuntimeShader(buildShader(rippleShape)) {
+
+    /** Shapes that the [RippleShader] supports. */
+    enum class RippleShape {
+        CIRCLE,
+        ROUNDED_BOX,
+        ELLIPSE
+    }
+    // language=AGSL
+    companion object {
+        private const val SHADER_UNIFORMS =
+            """
+            uniform vec2 in_center;
+            uniform vec2 in_size;
+            uniform float in_progress;
+            uniform float in_cornerRadius;
+            uniform float in_thickness;
+            uniform float in_time;
+            uniform float in_distort_radial;
+            uniform float in_distort_xy;
+            uniform float in_fadeSparkle;
+            uniform float in_fadeFill;
+            uniform float in_fadeRing;
+            uniform float in_blur;
+            uniform float in_pixelDensity;
+            layout(color) uniform vec4 in_color;
+            uniform float in_sparkle_strength;
+        """
+
+        private const val SHADER_CIRCLE_MAIN =
+            """
+            vec4 main(vec2 p) {
+                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);
+                float radius = in_size.x * 0.5;
+                float sparkleRing = soften(circleRing(p_distorted-in_center, radius), in_blur);
+                float inside = soften(sdCircle(p_distorted-in_center, radius * 1.2), in_blur);
+                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
+                    * (1.-sparkleRing) * in_fadeSparkle;
+
+                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
+                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
+                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
+                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
+                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
+            }
+        """
+
+        private const val SHADER_ROUNDED_BOX_MAIN =
+            """
+            vec4 main(vec2 p) {
+                float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius,
+                    in_thickness), in_blur);
+                float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius),
+                    in_blur);
+                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
+                    * (1.-sparkleRing) * in_fadeSparkle;
+
+                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
+                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
+                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
+                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
+                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
+            }
+        """
+
+        private const val SHADER_ELLIPSE_MAIN =
+            """
+            vec4 main(vec2 p) {
+                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);
+
+                float sparkleRing = soften(ellipseRing(p_distorted-in_center, in_size), in_blur);
+                float inside = soften(sdEllipse(p_distorted-in_center, in_size * 1.2), in_blur);
+                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
+                    * (1.-sparkleRing) * in_fadeSparkle;
+
+                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
+                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
+                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
+                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
+                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
+            }
+        """
+
+        private const val CIRCLE_SHADER =
+            SHADER_UNIFORMS +
+                ShaderUtilLibrary.SHADER_LIB +
+                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
+                SdfShaderLibrary.CIRCLE_SDF +
+                SHADER_CIRCLE_MAIN
+        private const val ROUNDED_BOX_SHADER =
+            SHADER_UNIFORMS +
+                ShaderUtilLibrary.SHADER_LIB +
+                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
+                SdfShaderLibrary.ROUNDED_BOX_SDF +
+                SHADER_ROUNDED_BOX_MAIN
+        private const val ELLIPSE_SHADER =
+            SHADER_UNIFORMS +
+                ShaderUtilLibrary.SHADER_LIB +
+                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
+                SdfShaderLibrary.ELLIPSE_SDF +
+                SHADER_ELLIPSE_MAIN
+
+        private fun buildShader(rippleShape: RippleShape): String =
+            when (rippleShape) {
+                RippleShape.CIRCLE -> CIRCLE_SHADER
+                RippleShape.ROUNDED_BOX -> ROUNDED_BOX_SHADER
+                RippleShape.ELLIPSE -> ELLIPSE_SHADER
+            }
+
+        private fun subProgress(start: Float, end: Float, progress: Float): Float {
+            val min = Math.min(start, end)
+            val max = Math.max(start, end)
+            val sub = Math.min(Math.max(progress, min), max)
+            return (sub - start) / (end - start)
+        }
+    }
+
+    /** Sets the center position of the ripple. */
+    fun setCenter(x: Float, y: Float) {
+        setFloatUniform("in_center", x, y)
+    }
+
+    /** Max width of the ripple. */
+    private var maxSize: PointF = PointF()
+    fun setMaxSize(width: Float, height: Float) {
+        maxSize.x = width
+        maxSize.y = height
+    }
+
+    /** Progress of the ripple. Float value between [0, 1]. */
+    var progress: Float = 0.0f
+        set(value) {
+            field = value
+            setFloatUniform("in_progress", value)
+            val curvedProg = 1 - (1 - value) * (1 - value) * (1 - value)
+
+            setFloatUniform(
+                "in_size",
+                /* width= */ maxSize.x * curvedProg,
+                /* height= */ maxSize.y * curvedProg
+            )
+            setFloatUniform("in_thickness", maxSize.y * curvedProg * 0.5f)
+            // radius should not exceed width and height values.
+            setFloatUniform("in_cornerRadius", Math.min(maxSize.x, maxSize.y) * curvedProg)
+
+            setFloatUniform("in_blur", MathUtils.lerp(1.25f, 0.5f, value))
+
+            val fadeIn = subProgress(0f, 0.1f, value)
+            val fadeOutNoise = subProgress(0.4f, 1f, value)
+            var fadeOutRipple = 0f
+            var fadeFill = 0f
+            if (!rippleFill) {
+                fadeFill = subProgress(0f, 0.6f, value)
+                fadeOutRipple = subProgress(0.3f, 1f, value)
+            }
+            setFloatUniform("in_fadeSparkle", Math.min(fadeIn, 1 - fadeOutNoise))
+            setFloatUniform("in_fadeFill", 1 - fadeFill)
+            setFloatUniform("in_fadeRing", Math.min(fadeIn, 1 - fadeOutRipple))
+        }
+
+    /** Play time since the start of the effect. */
+    var time: Float = 0.0f
+        set(value) {
+            field = value
+            setFloatUniform("in_time", value)
+        }
+
+    /** A hex value representing the ripple color, in the format of ARGB */
+    var color: Int = 0xffffff
+        set(value) {
+            field = value
+            setColorUniform("in_color", value)
+        }
+
+    /**
+     * Noise sparkle intensity. Expected value between [0, 1]. The sparkle is white, and thus with
+     * strength 0 it's transparent, leaving the ripple fully smooth, while with strength 1 it's
+     * opaque white and looks the most grainy.
+     */
+    var sparkleStrength: Float = 0.0f
+        set(value) {
+            field = value
+            setFloatUniform("in_sparkle_strength", value)
+        }
+
+    /** Distortion strength of the ripple. Expected value between[0, 1]. */
+    var distortionStrength: Float = 0.0f
+        set(value) {
+            field = value
+            setFloatUniform("in_distort_radial", 75 * progress * value)
+            setFloatUniform("in_distort_xy", 75 * value)
+        }
+
+    var pixelDensity: Float = 1.0f
+        set(value) {
+            field = value
+            setFloatUniform("in_pixelDensity", value)
+        }
+
+    /**
+     * True if the ripple should stayed filled in as it expands to give a filled-in circle effect.
+     * False for a ring effect.
+     */
+    var rippleFill: Boolean = false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/ripple/RippleView.kt
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/SdfShaderLibrary.kt
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/shaderutil/ShaderUtilLibrary.kt
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseAnimationConfig.kt
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseController.kt
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
similarity index 100%
rename from packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
rename to packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseShader.kt
diff --git a/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
new file mode 100644
index 0000000..68712c6
--- /dev/null
+++ b/packages/SystemUI/animation/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.surfaceeffects.turbulencenoise
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.util.AttributeSet
+import android.view.View
+import androidx.annotation.VisibleForTesting
+import androidx.core.graphics.ColorUtils
+import java.util.Random
+import kotlin.math.sin
+
+/** View that renders turbulence noise effect. */
+class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+
+    companion object {
+        private const val MS_TO_SEC = 0.001f
+        private const val TWO_PI = Math.PI.toFloat() * 2f
+    }
+
+    @VisibleForTesting val turbulenceNoiseShader = TurbulenceNoiseShader()
+    private val paint = Paint().apply { this.shader = turbulenceNoiseShader }
+    private val random = Random()
+    private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
+    private var config: TurbulenceNoiseAnimationConfig? = null
+
+    val isPlaying: Boolean
+        get() = animator.isRunning
+
+    init {
+        // Only visible during the animation.
+        visibility = INVISIBLE
+    }
+
+    /** Updates the color during the animation. No-op if there's no animation playing. */
+    fun updateColor(color: Int) {
+        config?.let {
+            it.color = color
+            applyConfig(it)
+        }
+    }
+
+    override fun onDraw(canvas: Canvas?) {
+        if (canvas == null || !canvas.isHardwareAccelerated) {
+            // Drawing with the turbulence noise shader requires hardware acceleration, so skip
+            // if it's unsupported.
+            return
+        }
+
+        canvas.drawPaint(paint)
+    }
+
+    fun play(config: TurbulenceNoiseAnimationConfig) {
+        if (isPlaying) {
+            return // Ignore if the animation is playing.
+        }
+        visibility = VISIBLE
+        applyConfig(config)
+
+        // Add random offset to avoid same patterned noise.
+        val offsetX = random.nextFloat()
+        val offsetY = random.nextFloat()
+
+        animator.duration = config.duration.toLong()
+        animator.addUpdateListener { updateListener ->
+            val timeInSec = updateListener.currentPlayTime * MS_TO_SEC
+            // Remap [0,1] to [0, 2*PI]
+            val progress = TWO_PI * updateListener.animatedValue as Float
+
+            turbulenceNoiseShader.setNoiseMove(
+                offsetX + timeInSec * config.noiseMoveSpeedX,
+                offsetY + timeInSec * config.noiseMoveSpeedY,
+                timeInSec * config.noiseMoveSpeedZ
+            )
+
+            // Fade in and out the noise as the animation progress.
+            // TODO: replace it with a better curve
+            turbulenceNoiseShader.setOpacity(sin(TWO_PI - progress) * config.luminosityMultiplier)
+
+            invalidate()
+        }
+
+        animator.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    visibility = INVISIBLE
+                    config.onAnimationEnd?.run()
+                }
+            }
+        )
+        animator.start()
+    }
+
+    private fun applyConfig(config: TurbulenceNoiseAnimationConfig) {
+        this.config = config
+        with(turbulenceNoiseShader) {
+            setGridCount(config.gridCount)
+            setColor(ColorUtils.setAlphaComponent(config.color, config.opacity))
+            setBackgroundColor(config.backgroundColor)
+            setSize(config.width, config.height)
+            setPixelDensity(config.pixelDensity)
+        }
+        paint.blendMode = config.blendMode
+    }
+}
diff --git a/packages/SystemUI/animation/tests/com/android/systemui/animation/InterpolatorsAndroidXTest.kt b/packages/SystemUI/animation/tests/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
new file mode 100644
index 0000000..389eed0
--- /dev/null
+++ b/packages/SystemUI/animation/tests/com/android/systemui/animation/InterpolatorsAndroidXTest.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.animation
+
+import androidx.test.filters.SmallTest
+import java.lang.reflect.Modifier
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+class InterpolatorsAndroidXTest {
+
+    @Test
+    fun testInterpolatorsAndInterpolatorsAndroidXPublicMethodsAreEqual() {
+        assertEquals(
+            Interpolators::class.java.getPublicMethods(),
+            InterpolatorsAndroidX::class.java.getPublicMethods()
+        )
+    }
+
+    @Test
+    fun testInterpolatorsAndInterpolatorsAndroidXPublicFieldsAreEqual() {
+        assertEquals(
+            Interpolators::class.java.getPublicFields(),
+            InterpolatorsAndroidX::class.java.getPublicFields()
+        )
+    }
+
+    private fun <T> Class<T>.getPublicMethods() =
+        declaredMethods
+            .filter { Modifier.isPublic(it.modifiers) }
+            .map { it.toString().replace(name, "") }
+            .toSet()
+
+    private fun <T> Class<T>.getPublicFields() =
+        fields.filter { Modifier.isPublic(it.modifiers) }.map { it.name }.toSet()
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt b/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt
index 50c3d7e..d6db574 100644
--- a/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt
+++ b/packages/SystemUI/compose/core/src/com/android/systemui/compose/animation/ExpandableController.kt
@@ -262,7 +262,7 @@
 
     private fun dialogController(cuj: DialogCuj?): DialogLaunchAnimator.Controller {
         return object : DialogLaunchAnimator.Controller {
-            override val viewRoot: ViewRootImpl = composeViewRoot.viewRootImpl
+            override val viewRoot: ViewRootImpl? = composeViewRoot.viewRootImpl
             override val sourceIdentity: Any = this@ExpandableControllerImpl
             override val cuj: DialogCuj? = cuj
 
diff --git a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
index e611e8b..979e1a0 100644
--- a/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
+++ b/packages/SystemUI/compose/testing/src/com/android/systemui/testing/compose/ComposeScreenshotTestRule.kt
@@ -38,12 +38,18 @@
 import platform.test.screenshot.getEmulatedDevicePathConfig
 
 /** A rule for Compose screenshot diff tests. */
-class ComposeScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+class ComposeScreenshotTestRule(
+    emulationSpec: DeviceEmulationSpec,
+    assetPathRelativeToBuildRoot: String
+) : TestRule {
     private val colorsRule = MaterialYouColorsRule()
     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
     private val screenshotRule =
         ScreenshotTestRule(
-            SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+            SystemUIGoldenImagePathManager(
+                getEmulatedDevicePathConfig(emulationSpec),
+                assetPathRelativeToBuildRoot
+            )
         )
     private val composeRule = createAndroidComposeRule<ScreenshotActivity>()
     private val delegateRule =
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
index 22944b8..462b90a 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/AnimatableClockView.kt
@@ -237,6 +237,28 @@
         this.lockScreenColor = lockScreenColor
     }
 
+    fun animateColorChange() {
+        logBuffer?.log(tag, DEBUG, "animateColorChange")
+        setTextStyle(
+            weight = lockScreenWeight,
+            textSize = -1f,
+            color = null, /* using current color */
+            animate = false,
+            duration = 0,
+            delay = 0,
+            onAnimationEnd = null
+        )
+        setTextStyle(
+            weight = lockScreenWeight,
+            textSize = -1f,
+            color = lockScreenColor,
+            animate = true,
+            duration = COLOR_ANIM_DURATION,
+            delay = 0,
+            onAnimationEnd = null
+        )
+    }
+
     fun animateAppearOnLockscreen() {
         logBuffer?.log(tag, DEBUG, "animateAppearOnLockscreen")
         setTextStyle(
@@ -350,6 +372,7 @@
      *
      * By passing -1 to weight, the view preserves its current weight.
      * By passing -1 to textSize, the view preserves its current text size.
+     * By passing null to color, the view preserves its current color.
      *
      * @param weight text weight.
      * @param textSize font size.
@@ -611,6 +634,7 @@
         private const val APPEAR_ANIM_DURATION: Long = 350
         private const val CHARGE_ANIM_DURATION_PHASE_0: Long = 500
         private const val CHARGE_ANIM_DURATION_PHASE_1: Long = 1000
+        private const val COLOR_ANIM_DURATION: Long = 400
 
         // Constants for the animation
         private val MOVE_INTERPOLATOR = Interpolators.EMPHASIZED
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 8698844..c540f0f 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -20,7 +20,6 @@
 import android.icu.text.NumberFormat
 import android.util.TypedValue
 import android.view.LayoutInflater
-import android.view.View
 import android.widget.FrameLayout
 import androidx.annotation.VisibleForTesting
 import com.android.systemui.customization.R
@@ -143,7 +142,7 @@
             currentColor = color
             view.setColors(DOZE_COLOR, color)
             if (!animations.dozeState.isActive) {
-                view.animateAppearOnLockscreen()
+                view.animateColorChange()
             }
         }
     }
@@ -152,15 +151,9 @@
         view: AnimatableClockView,
     ) : DefaultClockFaceController(view) {
         override fun recomputePadding(targetRegion: Rect?) {
-            // We center the view within the targetRegion instead of within the parent
-            // view by computing the difference and adding that to the padding.
-            val parent = view.parent
-            val yDiff =
-                if (targetRegion != null && parent is View && parent.isLaidOut())
-                    targetRegion.centerY() - parent.height / 2f
-                else 0f
+            // Ignore Target Region until top padding fixed in aod
             val lp = view.getLayoutParams() as FrameLayout.LayoutParams
-            lp.topMargin = (-0.5f * view.bottom + yDiff).toInt()
+            lp.topMargin = (-0.5f * view.bottom).toInt()
             view.setLayoutParams(lp)
         }
 
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/FakeKeyguardQuickAffordanceProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/FakeKeyguardQuickAffordanceProviderClient.kt
new file mode 100644
index 0000000..cb1a5f9
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/FakeKeyguardQuickAffordanceProviderClient.kt
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.shared.quickaffordance.data.content
+
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.Drawable
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.combine
+
+class FakeKeyguardQuickAffordanceProviderClient(
+    slots: List<KeyguardQuickAffordanceProviderClient.Slot> =
+        listOf(
+            KeyguardQuickAffordanceProviderClient.Slot(
+                id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                capacity = 1,
+            ),
+            KeyguardQuickAffordanceProviderClient.Slot(
+                id = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
+                capacity = 1,
+            ),
+        ),
+    affordances: List<KeyguardQuickAffordanceProviderClient.Affordance> =
+        listOf(
+            KeyguardQuickAffordanceProviderClient.Affordance(
+                id = AFFORDANCE_1,
+                name = AFFORDANCE_1,
+                iconResourceId = 1,
+            ),
+            KeyguardQuickAffordanceProviderClient.Affordance(
+                id = AFFORDANCE_2,
+                name = AFFORDANCE_2,
+                iconResourceId = 2,
+            ),
+            KeyguardQuickAffordanceProviderClient.Affordance(
+                id = AFFORDANCE_3,
+                name = AFFORDANCE_3,
+                iconResourceId = 3,
+            ),
+        ),
+    flags: List<KeyguardQuickAffordanceProviderClient.Flag> =
+        listOf(
+            KeyguardQuickAffordanceProviderClient.Flag(
+                name = KeyguardQuickAffordanceProviderContract.FlagsTable.FLAG_NAME_FEATURE_ENABLED,
+                value = true,
+            )
+        ),
+) : KeyguardQuickAffordanceProviderClient {
+
+    private val slots = MutableStateFlow(slots)
+    private val affordances = MutableStateFlow(affordances)
+    private val flags = MutableStateFlow(flags)
+
+    private val selections = MutableStateFlow<Map<String, List<String>>>(emptyMap())
+
+    override suspend fun insertSelection(slotId: String, affordanceId: String) {
+        val slotCapacity =
+            querySlots().find { it.id == slotId }?.capacity
+                ?: error("Slot with ID \"$slotId\" not found!")
+        val affordances = selections.value.getOrDefault(slotId, mutableListOf()).toMutableList()
+        while (affordances.size + 1 > slotCapacity) {
+            affordances.removeAt(0)
+        }
+        affordances.remove(affordanceId)
+        affordances.add(affordanceId)
+        selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances }
+    }
+
+    override suspend fun querySlots(): List<KeyguardQuickAffordanceProviderClient.Slot> {
+        return slots.value
+    }
+
+    override suspend fun queryFlags(): List<KeyguardQuickAffordanceProviderClient.Flag> {
+        return flags.value
+    }
+
+    override fun observeSlots(): Flow<List<KeyguardQuickAffordanceProviderClient.Slot>> {
+        return slots.asStateFlow()
+    }
+
+    override fun observeFlags(): Flow<List<KeyguardQuickAffordanceProviderClient.Flag>> {
+        return flags.asStateFlow()
+    }
+
+    override suspend fun queryAffordances():
+        List<KeyguardQuickAffordanceProviderClient.Affordance> {
+        return affordances.value
+    }
+
+    override fun observeAffordances():
+        Flow<List<KeyguardQuickAffordanceProviderClient.Affordance>> {
+        return affordances.asStateFlow()
+    }
+
+    override suspend fun querySelections(): List<KeyguardQuickAffordanceProviderClient.Selection> {
+        return toSelectionList(selections.value, affordances.value)
+    }
+
+    override fun observeSelections(): Flow<List<KeyguardQuickAffordanceProviderClient.Selection>> {
+        return combine(selections, affordances) { selections, affordances ->
+            toSelectionList(selections, affordances)
+        }
+    }
+
+    override suspend fun deleteSelection(slotId: String, affordanceId: String) {
+        val affordances = selections.value.getOrDefault(slotId, mutableListOf()).toMutableList()
+        affordances.remove(affordanceId)
+
+        selections.value = selections.value.toMutableMap().apply { this[slotId] = affordances }
+    }
+
+    override suspend fun deleteAllSelections(slotId: String) {
+        selections.value = selections.value.toMutableMap().apply { this[slotId] = emptyList() }
+    }
+
+    override suspend fun getAffordanceIcon(iconResourceId: Int, tintColor: Int): Drawable {
+        return when (iconResourceId) {
+            1 -> ICON_1
+            2 -> ICON_2
+            3 -> ICON_3
+            else -> BitmapDrawable()
+        }
+    }
+
+    fun setFlag(
+        name: String,
+        value: Boolean,
+    ) {
+        flags.value =
+            flags.value.toMutableList().apply {
+                removeIf { it.name == name }
+                add(KeyguardQuickAffordanceProviderClient.Flag(name = name, value = value))
+            }
+    }
+
+    fun setSlotCapacity(slotId: String, capacity: Int) {
+        slots.value =
+            slots.value.toMutableList().apply {
+                val index = indexOfFirst { it.id == slotId }
+                check(index != -1) { "Slot with ID \"$slotId\" doesn't exist!" }
+                set(
+                    index,
+                    KeyguardQuickAffordanceProviderClient.Slot(id = slotId, capacity = capacity)
+                )
+            }
+    }
+
+    fun addAffordance(affordance: KeyguardQuickAffordanceProviderClient.Affordance): Int {
+        affordances.value = affordances.value + listOf(affordance)
+        return affordances.value.size - 1
+    }
+
+    private fun toSelectionList(
+        selections: Map<String, List<String>>,
+        affordances: List<KeyguardQuickAffordanceProviderClient.Affordance>,
+    ): List<KeyguardQuickAffordanceProviderClient.Selection> {
+        return selections
+            .map { (slotId, affordanceIds) ->
+                affordanceIds.map { affordanceId ->
+                    val affordanceName =
+                        affordances.find { it.id == affordanceId }?.name
+                            ?: error("No affordance with ID of \"$affordanceId\"!")
+                    KeyguardQuickAffordanceProviderClient.Selection(
+                        slotId = slotId,
+                        affordanceId = affordanceId,
+                        affordanceName = affordanceName,
+                    )
+                }
+            }
+            .flatten()
+    }
+
+    companion object {
+        const val AFFORDANCE_1 = "affordance_1"
+        const val AFFORDANCE_2 = "affordance_2"
+        const val AFFORDANCE_3 = "affordance_3"
+        val ICON_1 = BitmapDrawable()
+        val ICON_2 = BitmapDrawable()
+        val ICON_3 = BitmapDrawable()
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderClient.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderClient.kt
new file mode 100644
index 0000000..3213b2e
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderClient.kt
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.shared.quickaffordance.data.content
+
+import android.annotation.SuppressLint
+import android.content.ContentValues
+import android.content.Context
+import android.database.ContentObserver
+import android.graphics.Color
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import androidx.annotation.DrawableRes
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+/** Client for using a content provider implementing the [Contract]. */
+interface KeyguardQuickAffordanceProviderClient {
+
+    /**
+     * Selects an affordance with the given ID for a slot on the lock screen with the given ID.
+     *
+     * Note that the maximum number of selected affordances on this slot is automatically enforced.
+     * Selecting a slot that is already full (e.g. already has a number of selected affordances at
+     * its maximum capacity) will automatically remove the oldest selected affordance before adding
+     * the one passed in this call. Additionally, selecting an affordance that's already one of the
+     * selected affordances on the slot will move the selected affordance to the newest location in
+     * the slot.
+     */
+    suspend fun insertSelection(
+        slotId: String,
+        affordanceId: String,
+    )
+
+    /** Returns all available slots supported by the device. */
+    suspend fun querySlots(): List<Slot>
+
+    /** Returns the list of flags. */
+    suspend fun queryFlags(): List<Flag>
+
+    /**
+     * Returns [Flow] for observing the collection of slots.
+     *
+     * @see [querySlots]
+     */
+    fun observeSlots(): Flow<List<Slot>>
+
+    /**
+     * Returns [Flow] for observing the collection of flags.
+     *
+     * @see [queryFlags]
+     */
+    fun observeFlags(): Flow<List<Flag>>
+
+    /**
+     * Returns all available affordances supported by the device, regardless of current slot
+     * placement.
+     */
+    suspend fun queryAffordances(): List<Affordance>
+
+    /**
+     * Returns [Flow] for observing the collection of affordances.
+     *
+     * @see [queryAffordances]
+     */
+    fun observeAffordances(): Flow<List<Affordance>>
+
+    /** Returns the current slot-affordance selections. */
+    suspend fun querySelections(): List<Selection>
+
+    /**
+     * Returns [Flow] for observing the collection of selections.
+     *
+     * @see [querySelections]
+     */
+    fun observeSelections(): Flow<List<Selection>>
+
+    /** Unselects an affordance with the given ID from the slot with the given ID. */
+    suspend fun deleteSelection(
+        slotId: String,
+        affordanceId: String,
+    )
+
+    /** Unselects all affordances from the slot with the given ID. */
+    suspend fun deleteAllSelections(
+        slotId: String,
+    )
+
+    /** Returns a [Drawable] with the given ID, loaded from the system UI package. */
+    suspend fun getAffordanceIcon(
+        @DrawableRes iconResourceId: Int,
+        tintColor: Int = Color.WHITE,
+    ): Drawable
+
+    /** Models a slot. A position that quick affordances can be positioned in. */
+    data class Slot(
+        /** Unique ID of the slot. */
+        val id: String,
+        /**
+         * The maximum number of quick affordances that are allowed to be positioned in this slot.
+         */
+        val capacity: Int,
+    )
+
+    /**
+     * Models a quick affordance. An action that can be selected by the user to appear in one or
+     * more slots on the lock screen.
+     */
+    data class Affordance(
+        /** Unique ID of the quick affordance. */
+        val id: String,
+        /** User-facing label for this affordance. */
+        val name: String,
+        /**
+         * Resource ID for the user-facing icon for this affordance. This resource is hosted by the
+         * System UI process so it must be used with
+         * `PackageManager.getResourcesForApplication(String)`.
+         */
+        val iconResourceId: Int,
+        /**
+         * Whether the affordance is enabled. Disabled affordances should be shown on the picker but
+         * should be rendered as "disabled". When tapped, the enablement properties should be used
+         * to populate UI that would explain to the user what to do in order to re-enable this
+         * affordance.
+         */
+        val isEnabled: Boolean = true,
+        /**
+         * If the affordance is disabled, this is a set of instruction messages to be shown to the
+         * user when the disabled affordance is selected. The instructions should help the user
+         * figure out what to do in order to re-neable this affordance.
+         */
+        val enablementInstructions: List<String>? = null,
+        /**
+         * If the affordance is disabled, this is a label for a button shown together with the set
+         * of instruction messages when the disabled affordance is selected. The button should help
+         * send the user to a flow that would help them achieve the instructions and re-enable this
+         * affordance.
+         *
+         * If `null`, the button should not be shown.
+         */
+        val enablementActionText: String? = null,
+        /**
+         * If the affordance is disabled, this is a "component name" of the format
+         * `packageName/action` to be used as an `Intent` for `startActivity` when the action button
+         * (shown together with the set of instruction messages when the disabled affordance is
+         * selected) is clicked by the user. The button should help send the user to a flow that
+         * would help them achieve the instructions and re-enable this affordance.
+         *
+         * If `null`, the button should not be shown.
+         */
+        val enablementActionComponentName: String? = null,
+    )
+
+    /** Models a selection of a quick affordance on a slot. */
+    data class Selection(
+        /** The unique ID of the slot. */
+        val slotId: String,
+        /** The unique ID of the quick affordance. */
+        val affordanceId: String,
+        /** The user-visible label for the quick affordance. */
+        val affordanceName: String,
+    )
+
+    /** Models a System UI flag. */
+    data class Flag(
+        /** The name of the flag. */
+        val name: String,
+        /** The value of the flag. */
+        val value: Boolean,
+    )
+}
+
+class KeyguardQuickAffordanceProviderClientImpl(
+    private val context: Context,
+    private val backgroundDispatcher: CoroutineDispatcher,
+) : KeyguardQuickAffordanceProviderClient {
+
+    override suspend fun insertSelection(
+        slotId: String,
+        affordanceId: String,
+    ) {
+        withContext(backgroundDispatcher) {
+            context.contentResolver.insert(
+                Contract.SelectionTable.URI,
+                ContentValues().apply {
+                    put(Contract.SelectionTable.Columns.SLOT_ID, slotId)
+                    put(Contract.SelectionTable.Columns.AFFORDANCE_ID, affordanceId)
+                }
+            )
+        }
+    }
+
+    override suspend fun querySlots(): List<KeyguardQuickAffordanceProviderClient.Slot> {
+        return withContext(backgroundDispatcher) {
+            context.contentResolver
+                .query(
+                    Contract.SlotTable.URI,
+                    null,
+                    null,
+                    null,
+                    null,
+                )
+                ?.use { cursor ->
+                    buildList {
+                        val idColumnIndex = cursor.getColumnIndex(Contract.SlotTable.Columns.ID)
+                        val capacityColumnIndex =
+                            cursor.getColumnIndex(Contract.SlotTable.Columns.CAPACITY)
+                        if (idColumnIndex == -1 || capacityColumnIndex == -1) {
+                            return@buildList
+                        }
+
+                        while (cursor.moveToNext()) {
+                            add(
+                                KeyguardQuickAffordanceProviderClient.Slot(
+                                    id = cursor.getString(idColumnIndex),
+                                    capacity = cursor.getInt(capacityColumnIndex),
+                                )
+                            )
+                        }
+                    }
+                }
+        }
+            ?: emptyList()
+    }
+
+    override suspend fun queryFlags(): List<KeyguardQuickAffordanceProviderClient.Flag> {
+        return withContext(backgroundDispatcher) {
+            context.contentResolver
+                .query(
+                    Contract.FlagsTable.URI,
+                    null,
+                    null,
+                    null,
+                    null,
+                )
+                ?.use { cursor ->
+                    buildList {
+                        val nameColumnIndex =
+                            cursor.getColumnIndex(Contract.FlagsTable.Columns.NAME)
+                        val valueColumnIndex =
+                            cursor.getColumnIndex(Contract.FlagsTable.Columns.VALUE)
+                        if (nameColumnIndex == -1 || valueColumnIndex == -1) {
+                            return@buildList
+                        }
+
+                        while (cursor.moveToNext()) {
+                            add(
+                                KeyguardQuickAffordanceProviderClient.Flag(
+                                    name = cursor.getString(nameColumnIndex),
+                                    value = cursor.getInt(valueColumnIndex) == 1,
+                                )
+                            )
+                        }
+                    }
+                }
+        }
+            ?: emptyList()
+    }
+
+    override fun observeSlots(): Flow<List<KeyguardQuickAffordanceProviderClient.Slot>> {
+        return observeUri(Contract.SlotTable.URI).map { querySlots() }
+    }
+
+    override fun observeFlags(): Flow<List<KeyguardQuickAffordanceProviderClient.Flag>> {
+        return observeUri(Contract.FlagsTable.URI).map { queryFlags() }
+    }
+
+    override suspend fun queryAffordances():
+        List<KeyguardQuickAffordanceProviderClient.Affordance> {
+        return withContext(backgroundDispatcher) {
+            context.contentResolver
+                .query(
+                    Contract.AffordanceTable.URI,
+                    null,
+                    null,
+                    null,
+                    null,
+                )
+                ?.use { cursor ->
+                    buildList {
+                        val idColumnIndex =
+                            cursor.getColumnIndex(Contract.AffordanceTable.Columns.ID)
+                        val nameColumnIndex =
+                            cursor.getColumnIndex(Contract.AffordanceTable.Columns.NAME)
+                        val iconColumnIndex =
+                            cursor.getColumnIndex(Contract.AffordanceTable.Columns.ICON)
+                        val isEnabledColumnIndex =
+                            cursor.getColumnIndex(Contract.AffordanceTable.Columns.IS_ENABLED)
+                        val enablementInstructionsColumnIndex =
+                            cursor.getColumnIndex(
+                                Contract.AffordanceTable.Columns.ENABLEMENT_INSTRUCTIONS
+                            )
+                        val enablementActionTextColumnIndex =
+                            cursor.getColumnIndex(
+                                Contract.AffordanceTable.Columns.ENABLEMENT_ACTION_TEXT
+                            )
+                        val enablementComponentNameColumnIndex =
+                            cursor.getColumnIndex(
+                                Contract.AffordanceTable.Columns.ENABLEMENT_COMPONENT_NAME
+                            )
+                        if (
+                            idColumnIndex == -1 ||
+                                nameColumnIndex == -1 ||
+                                iconColumnIndex == -1 ||
+                                isEnabledColumnIndex == -1 ||
+                                enablementInstructionsColumnIndex == -1 ||
+                                enablementActionTextColumnIndex == -1 ||
+                                enablementComponentNameColumnIndex == -1
+                        ) {
+                            return@buildList
+                        }
+
+                        while (cursor.moveToNext()) {
+                            add(
+                                KeyguardQuickAffordanceProviderClient.Affordance(
+                                    id = cursor.getString(idColumnIndex),
+                                    name = cursor.getString(nameColumnIndex),
+                                    iconResourceId = cursor.getInt(iconColumnIndex),
+                                    isEnabled = cursor.getInt(isEnabledColumnIndex) == 1,
+                                    enablementInstructions =
+                                        cursor
+                                            .getString(enablementInstructionsColumnIndex)
+                                            ?.split(
+                                                Contract.AffordanceTable
+                                                    .ENABLEMENT_INSTRUCTIONS_DELIMITER
+                                            ),
+                                    enablementActionText =
+                                        cursor.getString(enablementActionTextColumnIndex),
+                                    enablementActionComponentName =
+                                        cursor.getString(enablementComponentNameColumnIndex),
+                                )
+                            )
+                        }
+                    }
+                }
+        }
+            ?: emptyList()
+    }
+
+    override fun observeAffordances():
+        Flow<List<KeyguardQuickAffordanceProviderClient.Affordance>> {
+        return observeUri(Contract.AffordanceTable.URI).map { queryAffordances() }
+    }
+
+    override suspend fun querySelections(): List<KeyguardQuickAffordanceProviderClient.Selection> {
+        return withContext(backgroundDispatcher) {
+            context.contentResolver
+                .query(
+                    Contract.SelectionTable.URI,
+                    null,
+                    null,
+                    null,
+                    null,
+                )
+                ?.use { cursor ->
+                    buildList {
+                        val slotIdColumnIndex =
+                            cursor.getColumnIndex(Contract.SelectionTable.Columns.SLOT_ID)
+                        val affordanceIdColumnIndex =
+                            cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_ID)
+                        val affordanceNameColumnIndex =
+                            cursor.getColumnIndex(Contract.SelectionTable.Columns.AFFORDANCE_NAME)
+                        if (
+                            slotIdColumnIndex == -1 ||
+                                affordanceIdColumnIndex == -1 ||
+                                affordanceNameColumnIndex == -1
+                        ) {
+                            return@buildList
+                        }
+
+                        while (cursor.moveToNext()) {
+                            add(
+                                KeyguardQuickAffordanceProviderClient.Selection(
+                                    slotId = cursor.getString(slotIdColumnIndex),
+                                    affordanceId = cursor.getString(affordanceIdColumnIndex),
+                                    affordanceName = cursor.getString(affordanceNameColumnIndex),
+                                )
+                            )
+                        }
+                    }
+                }
+        }
+            ?: emptyList()
+    }
+
+    override fun observeSelections(): Flow<List<KeyguardQuickAffordanceProviderClient.Selection>> {
+        return observeUri(Contract.SelectionTable.URI).map { querySelections() }
+    }
+
+    override suspend fun deleteSelection(
+        slotId: String,
+        affordanceId: String,
+    ) {
+        withContext(backgroundDispatcher) {
+            context.contentResolver.delete(
+                Contract.SelectionTable.URI,
+                "${Contract.SelectionTable.Columns.SLOT_ID} = ? AND" +
+                    " ${Contract.SelectionTable.Columns.AFFORDANCE_ID} = ?",
+                arrayOf(
+                    slotId,
+                    affordanceId,
+                ),
+            )
+        }
+    }
+
+    override suspend fun deleteAllSelections(
+        slotId: String,
+    ) {
+        withContext(backgroundDispatcher) {
+            context.contentResolver.delete(
+                Contract.SelectionTable.URI,
+                Contract.SelectionTable.Columns.SLOT_ID,
+                arrayOf(
+                    slotId,
+                ),
+            )
+        }
+    }
+
+    @SuppressLint("UseCompatLoadingForDrawables")
+    override suspend fun getAffordanceIcon(
+        @DrawableRes iconResourceId: Int,
+        tintColor: Int,
+    ): Drawable {
+        return withContext(backgroundDispatcher) {
+            context.packageManager
+                .getResourcesForApplication(SYSTEM_UI_PACKAGE_NAME)
+                .getDrawable(iconResourceId, context.theme)
+                .apply { setTint(tintColor) }
+        }
+    }
+
+    private fun observeUri(
+        uri: Uri,
+    ): Flow<Unit> {
+        return callbackFlow {
+                val observer =
+                    object : ContentObserver(null) {
+                        override fun onChange(selfChange: Boolean) {
+                            trySend(Unit)
+                        }
+                    }
+
+                context.contentResolver.registerContentObserver(
+                    uri,
+                    /* notifyForDescendants= */ true,
+                    observer,
+                )
+
+                awaitClose { context.contentResolver.unregisterContentObserver(observer) }
+            }
+            .onStart { emit(Unit) }
+    }
+
+    companion object {
+        private const val SYSTEM_UI_PACKAGE_NAME = "com.android.systemui"
+    }
+}
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderContract.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderContract.kt
new file mode 100644
index 0000000..17be74b
--- /dev/null
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/data/content/KeyguardQuickAffordanceProviderContract.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.shared.quickaffordance.data.content
+
+import android.content.ContentResolver
+import android.net.Uri
+
+/** Contract definitions for querying content about keyguard quick affordances. */
+object KeyguardQuickAffordanceProviderContract {
+
+    const val AUTHORITY = "com.android.systemui.keyguard.quickaffordance"
+    const val PERMISSION = "android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES"
+
+    private val BASE_URI: Uri =
+        Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build()
+
+    /**
+     * Table for slots.
+     *
+     * Slots are positions where affordances can be placed on the lock screen. Affordances that are
+     * placed on slots are said to be "selected". The system supports the idea of multiple
+     * affordances per slot, though the implementation may limit the number of affordances on each
+     * slot.
+     *
+     * Supported operations:
+     * - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result set
+     * will contain rows with the [SlotTable.Columns] columns.
+     */
+    object SlotTable {
+        const val TABLE_NAME = "slots"
+        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
+
+        object Columns {
+            /** String. Unique ID for this slot. */
+            const val ID = "id"
+            /** Integer. The maximum number of affordances that can be placed in the slot. */
+            const val CAPACITY = "capacity"
+        }
+    }
+
+    /**
+     * Table for affordances.
+     *
+     * Affordances are actions/buttons that the user can execute. They are placed on slots on the
+     * lock screen.
+     *
+     * Supported operations:
+     * - Query - to know about all the affordances that are available on the device, regardless of
+     * which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result set will
+     * contain rows, each with the columns specified in [AffordanceTable.Columns].
+     */
+    object AffordanceTable {
+        const val TABLE_NAME = "affordances"
+        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
+        const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
+        const val COMPONENT_NAME_SEPARATOR = "/"
+
+        object Columns {
+            /** String. Unique ID for this affordance. */
+            const val ID = "id"
+            /** String. User-visible name for this affordance. */
+            const val NAME = "name"
+            /**
+             * Integer. Resource ID for the drawable to load for this affordance. This is a resource
+             * ID from the system UI package.
+             */
+            const val ICON = "icon"
+            /** Integer. `1` if the affordance is enabled or `0` if it disabled. */
+            const val IS_ENABLED = "is_enabled"
+            /**
+             * String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be shown
+             * to the user if the affordance is disabled and the user selects the affordance. The
+             * first one is a title while the rest are the steps needed to re-enable the affordance.
+             */
+            const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
+            /**
+             * String. Optional label for a button that, when clicked, opens a destination activity
+             * where the user can re-enable the disabled affordance.
+             */
+            const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
+            /**
+             * String. Optional package name and activity action string, delimited by
+             * [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that opens a
+             * destination where the user can re-enable the disabled affordance.
+             */
+            const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
+        }
+    }
+
+    /**
+     * Table for selections.
+     *
+     * Selections are pairs of slot and affordance IDs.
+     *
+     * Supported operations:
+     * - Insert - to insert an affordance and place it in a slot, insert values for the columns into
+     * the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system.
+     * Selecting a new affordance for a slot that is already full will automatically remove the
+     * oldest affordance from the slot.
+     * - Query - to know which affordances are set on which slots, query the [SelectionTable.URI]
+     * [Uri]. The result set will contain rows, each of which with the columns from
+     * [SelectionTable.Columns].
+     * - Delete - to unselect an affordance, removing it from a slot, delete from the
+     * [SelectionTable.URI] [Uri], passing in values for each column.
+     */
+    object SelectionTable {
+        const val TABLE_NAME = "selections"
+        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
+
+        object Columns {
+            /** String. Unique ID for the slot. */
+            const val SLOT_ID = "slot_id"
+            /** String. Unique ID for the selected affordance. */
+            const val AFFORDANCE_ID = "affordance_id"
+            /** String. Human-readable name for the affordance. */
+            const val AFFORDANCE_NAME = "affordance_name"
+        }
+    }
+
+    /**
+     * Table for flags.
+     *
+     * Flags are key-value pairs.
+     *
+     * Supported operations:
+     * - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will
+     * contain rows, each of which with the columns from [FlagsTable.Columns].
+     */
+    object FlagsTable {
+        const val TABLE_NAME = "flags"
+        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
+
+        /**
+         * Flag denoting whether the customizable lock screen quick affordances feature is enabled.
+         */
+        const val FLAG_NAME_FEATURE_ENABLED = "is_feature_enabled"
+
+        object Columns {
+            /** String. Unique ID for the flag. */
+            const val NAME = "name"
+            /** Int. Value of the flag. `1` means `true` and `0` means `false`. */
+            const val VALUE = "value"
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/keyguard/shared/model/KeyguardQuickAffordanceSlots.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordanceSlots.kt
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/shared/keyguard/shared/model/KeyguardQuickAffordanceSlots.kt
rename to packages/SystemUI/customization/src/com/android/systemui/shared/quickaffordance/shared/model/KeyguardQuickAffordanceSlots.kt
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index a156aab..7290e7e 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -753,7 +753,7 @@
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/userswitcher/StatusBarUserSwitcherControllerOldImplTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ConnectivityPipelineLoggerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryStateNotifierTest.kt
diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags
index 6976786..e598afe 100644
--- a/packages/SystemUI/proguard.flags
+++ b/packages/SystemUI/proguard.flags
@@ -26,14 +26,11 @@
 -keep class ** extends androidx.preference.PreferenceFragment
 -keep class com.android.systemui.tuner.*
 
-# The plugins and animation subpackages both act as shared libraries that might be referenced in
+# The plugins subpackage acts as a shared library that might be referenced in
 # dynamically-loaded plugin APKs.
 -keep class com.android.systemui.plugins.** {
     *;
 }
--keep class !com.android.systemui.animation.R$**,com.android.systemui.animation.** {
-    *;
-}
 -keep class com.android.systemui.fragments.FragmentService$FragmentCreator {
     *;
 }
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_flashlight_off.xml b/packages/SystemUI/res-keyguard/drawable/ic_flashlight_off.xml
new file mode 100644
index 0000000..e850d68
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_flashlight_off.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="#1f1f1f"
+      android:pathData="M8,22V11L6,8V2H18V8L16,11V22ZM12,15.5Q11.375,15.5 10.938,15.062Q10.5,14.625 10.5,14Q10.5,13.375 10.938,12.938Q11.375,12.5 12,12.5Q12.625,12.5 13.062,12.938Q13.5,13.375 13.5,14Q13.5,14.625 13.062,15.062Q12.625,15.5 12,15.5ZM8,5H16V4H8ZM16,7H8V7.4L10,10.4V20H14V10.4L16,7.4ZM12,12Z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/ic_flashlight_on.xml b/packages/SystemUI/res-keyguard/drawable/ic_flashlight_on.xml
new file mode 100644
index 0000000..91b9ae5
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/ic_flashlight_on.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="#1f1f1f"
+      android:pathData="M6,5V2H18V5ZM12,15.5Q12.625,15.5 13.062,15.062Q13.5,14.625 13.5,14Q13.5,13.375 13.062,12.938Q12.625,12.5 12,12.5Q11.375,12.5 10.938,12.938Q10.5,13.375 10.5,14Q10.5,14.625 10.938,15.062Q11.375,15.5 12,15.5ZM8,22V11L6,8V7H18V8L16,11V22Z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
index 898935f..2cac9c7 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_user_switcher.xml
@@ -21,8 +21,6 @@
     android:id="@+id/keyguard_bouncer_user_switcher"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:clipChildren="false"
-    android:clipToPadding="false"
     android:orientation="vertical"
     android:gravity="center"
     android:importantForAccessibility="yes"> <!-- Needed because TYPE_WINDOW_STATE_CHANGED is sent
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index b49afee..218c5cc 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -35,6 +35,7 @@
         android:visibility="invisible" />
     <FrameLayout
         android:id="@+id/lockscreen_clock_view_large"
+        android:layout_marginTop="@dimen/keyguard_large_clock_top_margin"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:clipChildren="false"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
index 411fea5..316ad39 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_num_pad_key.xml
@@ -18,6 +18,8 @@
     <TextView
         android:id="@+id/digit_text"
         style="@style/Widget.TextView.NumPadKey.Digit"
+        android:autoSizeMaxTextSize="32sp"
+        android:autoSizeTextType="uniform"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         />
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 2b7bdc2..c772c96 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -27,7 +27,7 @@
     android:orientation="vertical"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    androidprv:layout_maxWidth="@dimen/keyguard_security_width"
+    androidprv:layout_maxWidth="@dimen/biometric_auth_pattern_view_max_size"
     android:layout_gravity="center_horizontal|bottom"
     android:clipChildren="false"
     android:clipToPadding="false">
diff --git a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
index 669f8fb..e5e17b7 100644
--- a/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-h650dp/dimens.xml
@@ -17,4 +17,7 @@
 
 <resources>
     <dimen name="widget_big_font_size">54dp</dimen>
+
+    <!-- Margin above the ambient indication container -->
+    <dimen name="ambient_indication_container_margin_top">10dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 579824a..57e5f8a 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -74,7 +74,7 @@
     <string name="kg_password_pin_failed" msgid="5136259126330604009">"Bewerking met pincode voor simkaart is mislukt."</string>
     <string name="kg_password_puk_failed" msgid="6778867411556937118">"Bewerking met pukcode voor simkaart is mislukt."</string>
     <string name="accessibility_ime_switch_button" msgid="9082358310194861329">"Invoermethode wijzigen"</string>
-    <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuigmodus"</string>
+    <string name="airplane_mode" msgid="2528005343938497866">"Vliegtuig­modus"</string>
     <string name="kg_prompt_reason_restart_pattern" msgid="4720554342633852066">"Patroon vereist nadat het apparaat opnieuw is opgestart"</string>
     <string name="kg_prompt_reason_restart_pin" msgid="1587671566498057656">"Pincode vereist nadat het apparaat opnieuw is opgestart"</string>
     <string name="kg_prompt_reason_restart_password" msgid="8061279087240952002">"Wachtwoord vereist nadat het apparaat opnieuw is opgestart"</string>
diff --git a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml b/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
deleted file mode 100644
index a3c37e4..0000000
--- a/packages/SystemUI/res-keyguard/values-sw540dp-port/dimens.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* //device/apps/common/assets/res/any/dimens.xml
-**
-** Copyright 2013, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<resources>
-    <!-- Height of the sliding KeyguardSecurityContainer
-        (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">550dp</dimen>
-</resources>
diff --git a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
index 1dc61c5..b7a1bb4 100644
--- a/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values-sw720dp/dimens.xml
@@ -17,10 +17,5 @@
 */
 -->
 <resources>
-
-    <!-- Height of the sliding KeyguardSecurityContainer
-         (includes 2x keyguard_security_view_top_margin) -->
-    <dimen name="keyguard_security_height">470dp</dimen>
-
     <dimen name="widget_big_font_size">100dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index 3861d98..6cc5b9d 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -29,9 +29,6 @@
          (includes 2x keyguard_security_view_top_margin) -->
     <dimen name="keyguard_security_height">420dp</dimen>
 
-    <!-- Max Height of the sliding KeyguardSecurityContainer
-         (includes 2x keyguard_security_view_top_margin) -->
-
     <!-- pin/password field max height -->
     <dimen name="keyguard_password_height">80dp</dimen>
 
@@ -41,6 +38,9 @@
     <!-- Minimum bottom margin under the security view -->
     <dimen name="keyguard_security_view_bottom_margin">60dp</dimen>
 
+    <!-- Margin above the ambient indication container -->
+    <dimen name="ambient_indication_container_margin_top">0dp</dimen>
+
     <dimen name="keyguard_eca_top_margin">18dp</dimen>
     <dimen name="keyguard_eca_bottom_margin">12dp</dimen>
 
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index a129fb6..da485a9 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -53,7 +53,7 @@
     <string name="keyguard_plugged_in_charging_slowly"><xliff:g id="percentage">%s</xliff:g> • Charging slowly</string>
 
     <!-- When the lock screen is showing and the phone plugged in, and the defend mode is triggered, say that charging is temporarily limited.  -->
-    <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging is paused to protect battery</string>
+    <string name="keyguard_plugged_in_charging_limited"><xliff:g id="percentage">%s</xliff:g> • Charging paused to protect battery</string>
 
     <!-- On the keyguard screen, when pattern lock is disabled, only tell them to press menu to unlock.  This is shown in small font at the bottom. -->
     <string name="keyguard_instructions_when_pattern_disabled">Press Menu to unlock.</string>
diff --git a/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml b/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml
new file mode 100644
index 0000000..9a02296
--- /dev/null
+++ b/packages/SystemUI/res/drawable/screenrecord_options_spinner_popup_background.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+        android:shape="rectangle">
+    <corners android:radius="@dimen/screenrecord_spinner_background_radius"/>
+    <solid android:color="?androidprv:attr/colorAccentSecondary" />
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/screenshare_options_spinner_background.xml b/packages/SystemUI/res/drawable/screenshare_options_spinner_background.xml
new file mode 100644
index 0000000..34e7d0a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/screenshare_options_spinner_background.xml
@@ -0,0 +1,35 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:paddingMode="stack">
+    <item>
+        <shape android:shape="rectangle">
+            <corners android:radius="@dimen/screenrecord_spinner_background_radius" />
+            <stroke
+                android:width="1dp"
+                android:color="?androidprv:attr/textColorTertiary" />
+            <solid android:color="@android:color/transparent"/>
+        </shape>
+    </item>
+    <item
+        android:drawable="@drawable/ic_ksh_key_down"
+        android:gravity="end|center_vertical"
+        android:textColor="?androidprv:attr/textColorPrimary"
+        android:width="@dimen/screenrecord_spinner_arrow_size"
+        android:height="@dimen/screenrecord_spinner_arrow_size"
+        android:end="20dp" />
+</layer-list>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
index 6e0e38b..88f138f 100644
--- a/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout-land/auth_credential_pattern_view.xml
@@ -71,8 +71,8 @@
         <com.android.internal.widget.LockPatternView
             android:id="@+id/lockPattern"
             android:layout_gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
+            android:layout_width="@dimen/biometric_auth_pattern_view_size"
+            android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
 
         <TextView
             android:id="@+id/error"
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education.xml b/packages/SystemUI/res/layout/activity_rear_display_education.xml
new file mode 100644
index 0000000..73d3f02
--- /dev/null
+++ b/packages/SystemUI/res/layout/activity_rear_display_education.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:app="http://schemas.android.com/apk/res-auto"
+             android:layout_width="wrap_content"
+             android:layout_height="wrap_content"
+             android:orientation="vertical"
+             android:gravity="center" >
+
+    <androidx.cardview.widget.CardView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:cardElevation="0dp"
+        app:cardCornerRadius="28dp"
+        app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
+
+            <com.airbnb.lottie.LottieAnimationView
+                android:id="@+id/rear_display_folded_animation"
+                android:layout_width="@dimen/rear_display_animation_width"
+                android:layout_height="@dimen/rear_display_animation_height"
+                android:layout_gravity="center"
+                android:contentDescription="@null"
+                android:scaleType="fitXY"
+                app:lottie_rawRes="@raw/rear_display_folded"
+                app:lottie_autoPlay="true"
+                app:lottie_repeatMode="reverse"/>
+    </androidx.cardview.widget.CardView>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_fold_bottom_sheet_title"
+        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        android:lineSpacingExtra="2sp"
+        android:paddingTop="@dimen/rear_display_title_top_padding"
+        android:paddingBottom="@dimen/rear_display_title_bottom_padding"
+        android:gravity="center_horizontal|center_vertical"
+    />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_bottom_sheet_description"
+        android:textAppearance="@style/TextAppearance.Dialog.Body"
+        android:lineSpacingExtra="2sp"
+        android:translationY="-1.24sp"
+        android:gravity="center_horizontal|top"
+    />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
new file mode 100644
index 0000000..20b93d9
--- /dev/null
+++ b/packages/SystemUI/res/layout/activity_rear_display_education_opened.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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:app="http://schemas.android.com/apk/res-auto"
+              android:layout_width="wrap_content"
+              android:layout_height="wrap_content"
+              android:orientation="vertical"
+              android:gravity="center" >
+
+    <androidx.cardview.widget.CardView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        app:cardElevation="0dp"
+        app:cardCornerRadius="28dp"
+        app:cardBackgroundColor="@color/rear_display_overlay_animation_background_color">
+
+        <com.airbnb.lottie.LottieAnimationView
+            android:id="@+id/rear_display_folded_animation"
+            android:layout_width="@dimen/rear_display_animation_width"
+            android:layout_height="@dimen/rear_display_animation_height"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:scaleType="fitXY"
+            app:lottie_rawRes="@raw/rear_display_turnaround"
+            app:lottie_autoPlay="true"
+            app:lottie_repeatMode="reverse"/>
+    </androidx.cardview.widget.CardView>
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_unfold_bottom_sheet_title"
+        android:textAppearance="@style/TextAppearance.Dialog.Title"
+        android:lineSpacingExtra="2sp"
+        android:paddingTop="@dimen/rear_display_title_top_padding"
+        android:paddingBottom="@dimen/rear_display_title_bottom_padding"
+        android:gravity="center_horizontal|center_vertical"
+    />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_bottom_sheet_description"
+        android:textAppearance="@style/TextAppearance.Dialog.Body"
+        android:lineSpacingExtra="2sp"
+        android:translationY="-1.24sp"
+        android:gravity="center_horizontal|top"
+    />
+
+    <TextView
+        android:id="@+id/rear_display_warning_text_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:text="@string/rear_display_bottom_sheet_warning"
+        android:textAppearance="@style/TextAppearance.Dialog.Body"
+        android:lineSpacingExtra="2sp"
+        android:gravity="center_horizontal|top"
+    />
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
index 891c6af..81ca3718 100644
--- a/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
+++ b/packages/SystemUI/res/layout/auth_credential_pattern_view.xml
@@ -67,8 +67,8 @@
         <com.android.internal.widget.LockPatternView
             android:id="@+id/lockPattern"
             android:layout_gravity="center"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"/>
+            android:layout_width="@dimen/biometric_auth_pattern_view_size"
+            android:layout_height="@dimen/biometric_auth_pattern_view_size"/>
 
         <TextView
             android:id="@+id/error"
diff --git a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
index 2d67d95..efcb6f3 100644
--- a/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_complication_clock_time.xml
@@ -14,25 +14,32 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
 -->
-<com.android.systemui.shared.shadow.DoubleShadowTextClock
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
-    android:id="@+id/time_view"
     android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:fontFamily="@*android:string/config_clockFontFamily"
-    android:textColor="@android:color/white"
-    android:format12Hour="@string/dream_time_complication_12_hr_time_format"
-    android:format24Hour="@string/dream_time_complication_24_hr_time_format"
-    android:fontFeatureSettings="pnum, lnum"
-    android:letterSpacing="0.02"
-    android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"
-    app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius"
-    app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx"
-    app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy"
-    app:keyShadowAlpha="0.3"
-    app:ambientShadowBlur="@dimen/dream_overlay_clock_ambient_text_shadow_radius"
-    app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx"
-    app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy"
-    app:ambientShadowAlpha="0.3"
-/>
+    android:layout_height="wrap_content">
+
+    <com.android.systemui.shared.shadow.DoubleShadowTextClock
+        android:id="@+id/time_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:fontFamily="@*android:string/config_clockFontFamily"
+        android:textColor="@android:color/white"
+        android:format12Hour="@string/dream_time_complication_12_hr_time_format"
+        android:format24Hour="@string/dream_time_complication_24_hr_time_format"
+        android:fontFeatureSettings="pnum, lnum"
+        android:letterSpacing="0.02"
+        android:textSize="@dimen/dream_overlay_complication_clock_time_text_size"
+        android:translationY="@dimen/dream_overlay_complication_clock_time_translation_y"
+        app:keyShadowBlur="@dimen/dream_overlay_clock_key_text_shadow_radius"
+        app:keyShadowOffsetX="@dimen/dream_overlay_clock_key_text_shadow_dx"
+        app:keyShadowOffsetY="@dimen/dream_overlay_clock_key_text_shadow_dy"
+        app:keyShadowAlpha="0.3"
+        app:ambientShadowBlur="@dimen/dream_overlay_clock_ambient_text_shadow_radius"
+        app:ambientShadowOffsetX="@dimen/dream_overlay_clock_ambient_text_shadow_dx"
+        app:ambientShadowOffsetY="@dimen/dream_overlay_clock_ambient_text_shadow_dy"
+        app:ambientShadowAlpha="0.3"
+        />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
index 4f0a78e..de96e97 100644
--- a/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
+++ b/packages/SystemUI/res/layout/dream_overlay_home_controls_chip.xml
@@ -14,16 +14,21 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License.
 -->
-<ImageView
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/home_controls_chip"
-    android:layout_height="@dimen/keyguard_affordance_fixed_height"
-    android:layout_width="@dimen/keyguard_affordance_fixed_width"
-    android:layout_gravity="bottom|start"
-    android:scaleType="center"
-    android:tint="?android:attr/textColorPrimary"
-    android:src="@drawable/controls_icon"
-    android:background="@drawable/keyguard_bottom_affordance_bg"
-    android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
-    android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-    android:contentDescription="@string/quick_controls_title" />
+    android:layout_height="wrap_content"
+    android:layout_width="wrap_content"
+    android:paddingVertical="@dimen/dream_overlay_complication_home_controls_padding">
+
+    <ImageView
+        android:id="@+id/home_controls_chip"
+        android:layout_height="@dimen/keyguard_affordance_fixed_height"
+        android:layout_width="@dimen/keyguard_affordance_fixed_width"
+        android:layout_gravity="bottom|start"
+        android:scaleType="center"
+        android:tint="?android:attr/textColorPrimary"
+        android:src="@drawable/controls_icon"
+        android:background="@drawable/keyguard_bottom_affordance_bg"
+        android:contentDescription="@string/quick_controls_title" />
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
index 79ba7ead..aa655e6 100644
--- a/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
+++ b/packages/SystemUI/res/layout/media_smartspace_recommendations.xml
@@ -41,7 +41,7 @@
         android:layout_width="@dimen/qs_media_app_icon_size"
         android:layout_height="@dimen/qs_media_app_icon_size"
         android:layout_marginStart="@dimen/qs_media_padding"
-        android:layout_marginTop="@dimen/qs_media_padding"
+        android:layout_marginTop="@dimen/qs_media_rec_icon_top_margin"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent" />
 
diff --git a/packages/SystemUI/res/layout/screen_record_options.xml b/packages/SystemUI/res/layout/screen_record_options.xml
index d6c9e98..3f0eea9 100644
--- a/packages/SystemUI/res/layout/screen_record_options.xml
+++ b/packages/SystemUI/res/layout/screen_record_options.xml
@@ -16,7 +16,8 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:orientation="vertical">
+    android:orientation="vertical"
+    android:paddingBottom="@dimen/screenrecord_options_padding_bottom">
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
@@ -72,7 +73,7 @@
             android:gravity="center_vertical"
             android:text="@string/screenrecord_taps_label"
             android:textAppearance="?android:attr/textAppearanceMedium"
-            android:fontFamily="@*android:string/config_headlineFontFamily"
+            android:fontFamily="@*android:string/config_bodyFontFamily"
             android:textColor="?android:attr/textColorPrimary"
             android:contentDescription="@string/screenrecord_taps_label"/>
         <Switch
diff --git a/packages/SystemUI/res/layout/screen_share_dialog.xml b/packages/SystemUI/res/layout/screen_share_dialog.xml
index ac46cdb..bd71989 100644
--- a/packages/SystemUI/res/layout/screen_share_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_share_dialog.xml
@@ -16,7 +16,7 @@
 
 <!-- Scrollview is necessary to fit everything in landscape layout -->
 <ScrollView  xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/screen_share_permission_dialog"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
@@ -32,10 +32,11 @@
         android:gravity="center_horizontal">
 
         <ImageView
+            android:id="@+id/screen_share_dialog_icon"
             android:layout_width="@dimen/screenrecord_logo_size"
             android:layout_height="@dimen/screenrecord_logo_size"
-            android:src="@drawable/ic_screenrecord"
-            android:tint="@color/screenrecord_icon_color"
+            android:src="@drawable/ic_media_projection_permission"
+            android:tint="?androidprv:attr/colorAccentPrimary"
             android:importantForAccessibility="no"/>
         <TextView
             android:id="@+id/screen_share_dialog_title"
@@ -43,34 +44,37 @@
             android:layout_height="wrap_content"
             android:textAppearance="?android:attr/textAppearanceLarge"
             android:fontFamily="@*android:string/config_headlineFontFamily"
-            android:layout_marginTop="22dp"
-            android:layout_marginBottom="15dp"/>
+            android:layout_marginTop="@dimen/screenrecord_title_margin_top"
+            android:gravity="center"/>
         <Spinner
             android:id="@+id/screen_share_mode_spinner"
-            android:layout_width="320dp"
-            android:layout_height="72dp"
-            android:layout_marginTop="24dp"
-            android:layout_marginBottom="24dp" />
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/screenrecord_spinner_height"
+            android:layout_marginTop="@dimen/screenrecord_spinner_margin"
+            android:layout_marginBottom="@dimen/screenrecord_spinner_margin"
+            android:gravity="center_vertical"
+            android:background="@drawable/screenshare_options_spinner_background"
+            android:popupBackground="@drawable/screenrecord_options_spinner_popup_background"/>
         <ViewStub
             android:id="@+id/options_stub"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"/>
         <TextView
             android:id="@+id/text_warning"
-            android:layout_width="wrap_content"
+            android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="@string/screenrecord_description"
             android:textAppearance="?android:attr/textAppearanceSmall"
             android:textColor="?android:textColorSecondary"
             android:gravity="start"
-            android:layout_marginBottom="20dp"/>
+            android:lineHeight="@dimen/screenrecord_warning_line_height"/>
 
         <!-- Buttons -->
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:orientation="horizontal"
-            android:layout_marginTop="36dp">
+            android:layout_marginTop="@dimen/screenrecord_buttons_margin_top">
             <TextView
                 android:id="@+id/button_cancel"
                 android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml b/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml
new file mode 100644
index 0000000..66c2155
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_share_dialog_spinner_item_text.xml
@@ -0,0 +1,27 @@
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+    android:id="@android:id/text1"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:textColor="?androidprv:attr/textColorOnAccent"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="@dimen/screenrecord_spinner_height"
+    android:gravity="center_vertical"
+    android:ellipsize="marquee"
+    android:paddingStart="@dimen/screenrecord_spinner_text_padding_start"
+    android:paddingEnd="@dimen/screenrecord_spinner_text_padding_end"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/screen_share_dialog_spinner_text.xml b/packages/SystemUI/res/layout/screen_share_dialog_spinner_text.xml
new file mode 100644
index 0000000..4cc4cba
--- /dev/null
+++ b/packages/SystemUI/res/layout/screen_share_dialog_spinner_text.xml
@@ -0,0 +1,26 @@
+<!--
+  Copyright (C) 2022 The Android Open Source Project
+
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:textAppearance="?android:attr/textAppearanceMedium"
+    android:fontFamily="@*android:string/config_bodyFontFamily"
+    android:textColor="?android:textColorPrimary"
+    android:singleLine="true"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:gravity="center_vertical"
+    android:ellipsize="marquee"
+    android:paddingStart="@dimen/screenrecord_spinner_text_padding_start"
+    android:paddingEnd="@dimen/screenrecord_spinner_text_padding_end"/>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index f7600e6..64aa629 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -55,6 +55,7 @@
             android:id="@+id/status_bar_start_side_container"
             android:layout_height="match_parent"
             android:layout_width="0dp"
+            android:clipChildren="false"
             android:layout_weight="1">
 
             <!-- Container that is wrapped around the views on the start half of the status bar.
diff --git a/packages/SystemUI/res/layout/status_bar_no_notifications.xml b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
index a2abdb2..856ba92 100644
--- a/packages/SystemUI/res/layout/status_bar_no_notifications.xml
+++ b/packages/SystemUI/res/layout/status_bar_no_notifications.xml
@@ -21,12 +21,29 @@
         android:layout_height="wrap_content"
         android:visibility="gone"
         >
-    <TextView
-            android:id="@+id/no_notifications"
+    <LinearLayout android:orientation="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:minHeight="64dp"
-            android:textAppearance="?android:attr/textAppearanceButton"
+            android:layout_gravity="center"
             android:gravity="center"
-            android:text="@string/empty_shade_text"/>
+            >
+        <TextView
+                android:id="@+id/no_notifications"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:minHeight="64dp"
+                android:gravity="center"
+                android:textAppearance="?android:attr/textAppearanceButton"
+                android:text="@string/empty_shade_text"/>
+        <TextView
+                android:id="@+id/no_notifications_footer"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_horizontal"
+                android:gravity="center"
+                android:drawablePadding="8dp"
+                android:visibility="gone"
+                android:textAppearance="?android:attr/textAppearanceButton"
+                android:text="@string/unlock_to_see_notif_text"/>
+    </LinearLayout>
 </com.android.systemui.statusbar.EmptyShadeView>
diff --git a/packages/SystemUI/res/raw/rear_display_folded.json b/packages/SystemUI/res/raw/rear_display_folded.json
new file mode 100644
index 0000000..5140f41
--- /dev/null
+++ b/packages/SystemUI/res/raw/rear_display_folded.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":412,"h":300,"nm":"Close to Open - Generic Version V01","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"SHUTTER_ANIMATION 2","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":270.564,"ix":3},"y":{"a":0,"k":239.916,"ix":4}},"a":{"a":0,"k":[460.228,450.736,0],"ix":1,"l":2},"s":{"a":0,"k":[138.889,138.889,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.528,0],[0,-2.528],[2.528,0],[0,2.528]],"o":[[2.528,0],[0,2.528],[-2.528,0],[0,-2.528]],"v":[[0,-4.5],[4.5,0],[0,4.5],[-4.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 599","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[140,140],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_01","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.337,0],[0,-5.337],[5.337,0],[0,5.337]],"o":[[5.337,0],[0,5.337],[-5.337,0],[0,-5.337]],"v":[[0,-9.5],[9.5,0],[0,9.5],[-9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 598","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_02","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":196,"st":-90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"CAMERA_CASING","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.125,149.875,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[20,20,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77.334,"s":[{"i":[[0.121,-8.986],[-0.129,-6.81],[0,0],[0.079,-13.74],[-0.055,-2.977],[0,0],[-0.084,4.25],[0,5.834],[0,20.89],[-0.063,-6.336]],"o":[[-0.029,2.163],[0.129,6.811],[0,0],[-0.079,13.74],[0.123,6.697],[0,0],[0.045,-2.268],[0,-6.193],[0,-0.486],[0.247,24.895]],"v":[[-248.474,-424.663],[-248.252,-408.338],[-247.986,-395.258],[-248.158,-368.523],[-248.248,-337.322],[-243.792,-329.875],[-243.834,-338.44],[-243.875,-350.098],[-244.25,-495.639],[-248.374,-488.414]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78,"s":[{"i":[[0.121,-8.986],[-0.035,-6.791],[0,0],[0.257,-54.598],[-0.08,-2.976],[0,0],[-0.084,4.25],[0,5.834],[0,20.89],[0.187,-5.461]],"o":[[-0.029,2.163],[0.035,6.791],[0,0],[-0.257,54.598],[0.121,4.51],[0,0],[0.045,-2.268],[0,-6.193],[0,-0.486],[-0.853,24.882]],"v":[[-246.724,-424.581],[-246.689,-408.295],[-246.611,-395.254],[-247.145,-286.802],[-247.56,-173.885],[-239.293,-170.875],[-239.335,-179.44],[-239.251,-191.098],[-239,-495.889],[-246.437,-493.601]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79,"s":[{"i":[[0.714,-8.993],[0.023,-5.892],[0,0],[0.218,-62.519],[-0.04,-3.021],[0,0],[-2.041,1.97],[0,5.92],[0,21.197],[1.374,-7.356]],"o":[[-0.174,2.184],[-0.023,5.892],[0,0],[-0.218,62.519],[0.061,5.942],[0,0],[0.335,-2.259],[0,-6.284],[0,-0.493],[-3.801,24.629]],"v":[[-249.702,-423.916],[-249.966,-409.403],[-249.968,-398.166],[-250.414,-273.882],[-250.801,-145.067],[-238.043,-139.562],[-231.043,-142.595],[-229.959,-182.924],[-230,-497.57],[-247.031,-494.301]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[1.306,-9],[0.081,-4.992],[0,0],[0.2,-61.534],[0,-3.065],[0,0],[-6.497,19.5],[0,6.005],[0,21.503],[2.562,-9.251]],"o":[[-0.32,2.204],[-0.081,4.992],[0,0],[-0.2,61.535],[0,7.375],[0,0],[0.738,-2.215],[0,-6.375],[0,-0.5],[-6.75,24.375]],"v":[[-252.681,-423.25],[-253.243,-410.511],[-253.325,-401.078],[-253.726,-278.775],[-254.126,-151.875],[-236.876,-143.875],[-224.128,-171.375],[-221.128,-194.75],[-221,-499.25],[-241.375,-496.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81,"s":[{"i":[[0,0],[2.977,-4.617],[0.592,-15.582],[0.085,-28.87],[-7.478,-2.938],[0,0],[-7.716,4.062],[0.774,19.04],[0.351,22.315],[4.742,-7.015]],"o":[[0,0],[-5.02,7.785],[-0.054,1.42],[-0.036,12.426],[7.58,-2.313],[0,0],[6.882,-3.623],[-0.821,-20.201],[-4.272,-4.668],[-5.774,8.542]],"v":[[-281.915,-495.91],[-289.56,-482.16],[-299.005,-452.549],[-298.089,-174.301],[-285.022,-158.312],[-272.428,-163.108],[-254.243,-172.187],[-246.548,-198.415],[-247.911,-507.832],[-271.41,-509.792]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83,"s":[{"i":[[0,0],[5.84,-4.09],[0.943,-15.582],[-0.504,-28.868],[-9.184,-4.813],[0,0],[-12.283,4.062],[0.017,19.08],[0.558,22.315],[10.444,-5.833]],"o":[[0,0],[-9.041,6.332],[-0.086,1.42],[0.293,16.801],[12.066,-2.313],[0,0],[10.956,-3.623],[-0.018,-20.335],[-6.483,-6.543],[-12.057,6.734]],"v":[[-335.521,-505.91],[-351.465,-495.91],[-370.479,-463.799],[-369.043,-170.551],[-352.691,-149.562],[-328.662,-154.983],[-300.058,-162.812],[-286.232,-189.04],[-289.767,-509.707],[-316.694,-517.917]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86,"s":[{"i":[[0,0],[10.236,-2.84],[1.247,-15.582],[0,-28.874],[-6.428,0.187],[0,0],[-16.249,4.062],[0,17.165],[0.739,22.315],[11.672,-3.958]],"o":[[0,0],[-13.709,3.803],[-0.114,1.42],[0,17.426],[15.447,-2.313],[0,0],[14.494,-3.623],[0,-20.252],[-3.545,-8.418],[-17.281,5.861]],"v":[[-411.704,-507.785],[-438.297,-499.035],[-463.451,-466.924],[-464.325,-183.676],[-446.9,-161.437],[-413.235,-166.858],[-377.21,-173.437],[-354.78,-199.04],[-356.455,-507.207],[-381.047,-517.292]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[0,0],[11.399,-2.84],[1.389,-15.582],[-0.154,-28.874],[-10.466,-4.813],[0,0],[-18.094,4.062],[0.311,21.54],[0.823,22.315],[12.693,-2.083]],"o":[[0,0],[-15.266,3.803],[-0.127,1.42],[0.136,25.551],[16.344,-2.733],[0,0],[16.14,-3.623],[-0.293,-20.255],[-6.423,-10.918],[-20.046,3.29]],"v":[[-453.081,-516.535],[-484.085,-509.035],[-512.096,-476.924],[-511.208,-201.176],[-491.095,-170.812],[-450.071,-176.858],[-415.594,-182.187],[-391.248,-214.04],[-394.202,-507.207],[-419.568,-523.542]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91,"s":[{"i":[[0,0],[11.98,-2.84],[1.46,-15.582],[-0.514,-28.87],[-22.839,0.574],[0,0],[-19.017,4.062],[-1.512,28.415],[0.865,22.315],[18.516,-1.458]],"o":[[0,0],[-16.044,3.803],[-0.133,1.42],[0.514,28.87],[17.426,-0.438],[0,0],[16.962,-3.623],[1.076,-20.231],[-2.031,-12.793],[-21.281,1.676]],"v":[[-517.52,-526.535],[-550.105,-520.285],[-579.544,-488.174],[-580.475,-228.676],[-552.254,-182.687],[-515.05,-186.858],[-479.472,-193.437],[-453.852,-232.165],[-454.219,-505.957],[-481.641,-531.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[9.594,-0.965],[1.674,-15.582],[-0.589,-28.87],[-26.176,0.574],[0,0],[-26.125,4.687],[-0.648,20.252],[0.991,22.315],[23.63,-1.458]],"o":[[0,0],[-18.792,1.889],[-0.153,1.42],[0.589,28.87],[19.971,-0.438],[0,0],[19.531,-3.504],[0.648,-20.252],[-5.417,-15.918],[-24.412,1.507]],"v":[[-566.624,-545.91],[-605.219,-542.785],[-638.958,-510.674],[-640.256,-243.676],[-605.048,-197.687],[-564.208,-201.233],[-524.5,-205.937],[-494.422,-252.79],[-495.208,-520.332],[-526.755,-548.542]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[10.756,0.606],[1.787,-15.582],[-0.629,-28.87],[-29.482,0.187],[0,0],[-26.75,1.562],[-0.693,20.252],[1.058,22.315],[29.006,2.879]],"o":[[0,0],[-20.135,-1.134],[-0.163,1.42],[0.629,28.87],[22.579,-0.143],[0,0],[21.139,-1.234],[0.693,-20.252],[-0.991,-20.899],[-22.881,-2.271]],"v":[[-590.882,-561.535],[-630.768,-559.035],[-666.802,-526.924],[-667.496,-244.926],[-626.768,-198.312],[-587.72,-199.358],[-544.491,-201.562],[-512.976,-245.915],[-513.29,-522.832],[-546.76,-561.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.524,-1.302],[0,0],[-22.316,2.187],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[23.032,1.051],[0,0],[21.519,-2.108],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-603.82,-572.785],[-647.049,-572.785],[-683.846,-540.674],[-684.555,-258.676],[-646.156,-212.687],[-598.091,-212.483],[-558.309,-214.687],[-525.505,-260.29],[-527.086,-532.832],[-561.264,-571.667]],"c":true}]},{"t":115,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.524,-1.302],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[23.032,1.051],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-605.07,-581.535],[-648.299,-581.535],[-685.096,-549.424],[-685.805,-263.676],[-647.406,-217.687],[-601.841,-216.858],[-560.092,-217.187],[-527.348,-259.04],[-528.336,-541.582],[-562.514,-580.417]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":78,"op":241,"st":60,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"FRONT_LENS","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[269.043,44.23,0],"ix":2,"l":2},"a":{"a":0,"k":[387.188,-561.875,0],"ix":1,"l":2},"s":{"a":0,"k":[18.519,18.519,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[1.484,-19.734],[20.984,-0.234],[1.484,19.266],[-18.016,-0.234]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[385.5,-561.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":241,"st":60,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"FRONT_SCREEN 2","parent":5,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[268.577,150.446,0],"ix":2,"l":2},"a":{"a":0,"k":[-2.142,1.067,0],"ix":1,"l":2},"s":{"a":0,"k":[18.894,18.894,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[635,1210],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":50,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0.641,0.871],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 2","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":241,"st":60,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Figure","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[207.459,144.79,0],"to":[0.312,0,0],"ti":[-1.146,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63.334,"s":[209.334,144.79,0],"to":[1.146,0,0],"ti":[-2.125,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66.666,"s":[214.334,144.79,0],"to":[2.125,0,0],"ti":[-2.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[222.084,144.79,0],"to":[2.812,0,0],"ti":[-4.396,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[231.209,144.79,0],"to":[4.396,0,0],"ti":[-5.104,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[248.459,144.79,0],"to":[5.104,0,0],"ti":[-3.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[261.834,144.79,0],"to":[3.812,0,0],"ti":[-2.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[271.334,144.79,0],"to":[2.667,0,0],"ti":[-1.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[277.834,144.79,0],"to":[1.812,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106.666,"s":[282.209,144.79,0],"to":[1.083,0,0],"ti":[-0.458,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113.334,"s":[284.334,144.79,0],"to":[0.458,0,0],"ti":[-0.104,0,0]},{"t":120,"s":[284.959,144.79,0]}],"ix":2,"l":2},"a":{"a":0,"k":[270.209,145.54,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.55,0.55,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.001]},"t":60,"s":[108,108,100]},{"t":120,"s":[106.5,106.5,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.939,-1.387],[6.061,-1.3],[0.907,1.308]],"o":[[1.066,0.711],[2.423,1.734],[-4.85,1.04],[0,0]],"v":[[-0.582,-6.237],[5.035,-2.37],[2.01,5.979],[-6.77,3.354]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[272.026,152.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Nose","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.926,7.277],[-8.848,0],[-3.783,2.669],[18.309,-0.059],[0.81,-15.17],[-4.916,0]],"o":[[3.926,7.277],[4.982,0],[-0.845,-15.213],[-18.267,0.059],[3.755,2.604],[8.848,0]],"v":[[-0.106,3.616],[20.359,15.839],[33.729,11.589],[-0.12,-15.891],[-33.793,11.7],[-20.571,15.839]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,9.805],[9.805,0],[0,-9.805],[-9.805,0]],"o":[[0,-9.805],[-9.805,0],[0,9.805],[9.805,0]],"v":[[-6.59,-22.526],[-24.345,-40.281],[-42.099,-22.526],[-24.345,-4.772]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.23137255013,0.129411771894,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.47,108.276],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Hair","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.446,13.962],[0,0],[0,0],[-0.313,2.62],[0.015,4.351],[0,0],[-18.83,0.06],[-0.051,-15.806],[0,0],[-0.49,-2.669],[-1.873,-4.352],[-0.89,-3.988],[0,-4.307],[8.014,-5.508],[12.335,-0.04],[8.035,5.309],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.222,-4.479],[0.309,-2.598],[0,0],[-0.051,-15.806],[18.83,-0.06],[0,0],[0.013,4.276],[0.495,2.702],[3.604,8.387],[0.884,3.962],[0,7.459],[-7.997,5.495],[-12.35,0.04],[-8.04,-5.313],[0,0],[0,-6.072]],"v":[[-36.861,-4.598],[-36.804,-4.703],[-36.772,-4.819],[-34.61,-14.535],[-34.324,-24.06],[-34.324,-24.128],[-0.614,-53.129],[33.278,-24.345],[33.278,-24.252],[33.789,-14.641],[37.134,-4.922],[43.41,12.489],[44.307,23.718],[31.53,43.997],[0.092,53.129],[-31.449,44.589],[-44.307,24.009],[-44.307,23.977]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[4.598,1.656],[-2.64,7.412],[-4.598,-1.656],[2.64,-7.412]],"o":[[-4.6,-1.657],[2.64,-7.412],[4.6,1.657],[-2.64,7.412]],"v":[[30.635,-0.09],[27.088,-16.51],[40.195,-26.931],[43.742,-10.511]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[4.598,-1.656],[2.64,7.412],[-4.598,1.656],[-2.64,-7.412]],"o":[[-4.6,1.657],[-2.64,-7.412],[4.6,-1.657],[2.64,7.412]],"v":[[-32.206,-0.025],[-45.315,-10.446],[-41.768,-26.866],[-28.659,-16.445]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.996,145.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Head","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[32.75,0],[5.125,-6.5],[0,0],[0,0],[0.125,7.75]],"o":[[-36.75,0],[-0.25,11],[0,0],[0,0],[-14.25,-12.5]],"v":[[269.5,203.875],[202.375,231.25],[202.125,265.125],[335.375,265.125],[335.375,229.75]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.105865478516,0.450958251953,0.901947021484,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Body","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0],[0,-5.243]],"o":[[0,0],[0,0],[0,0],[5.243,0],[0,0]],"v":[[335.369,264.28],[202.496,264.441],[202.496,35.601],[325.98,35.551],[335.473,45.044]],"c":true},"ix":2},"nm":"Mask","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.815673828125,0.88232421875,0.980377197266,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Background","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":660,"st":60,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"FOLDABLE_BODY","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.125,149.875,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[20,20,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-16.75],[0,0],[0.131,-20.875],[0,0],[0,0],[-1.054,43.75],[0,0],[55.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.07,32.5],[0,0],[0,0],[50.138,1],[0,0],[0.75,-40.75],[0,0],[0,0],[-0.317,13.125]],"v":[[-380.75,-475.25],[-381.945,472.625],[-381.756,573.5],[-381.766,647.625],[278.237,648.25],[356.555,572.75],[356.375,-566.125],[277.933,-644.25],[-380.936,-644.5],[-380.183,-550.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":63.334,"s":[{"i":[[0,-16.75],[0,0],[0.131,-20.875],[0,0],[0,0],[-1.054,43.75],[0,0],[55.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.07,32.5],[0,0],[0,0],[50.138,1],[0,0],[0.75,-40.75],[0,0],[0,0],[-0.317,13.125]],"v":[[-373.625,-475],[-373.633,472.562],[-373.444,573.438],[-373.454,647.562],[287.112,648.375],[364.93,573.625],[364.75,-566.938],[285.995,-645],[-373.811,-644.25],[-373.058,-550.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66.666,"s":[{"i":[[0,-16.75],[0,0],[0.131,-20.875],[0,0],[0,0],[-1.054,43.75],[0,0],[55.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.07,32.5],[0,0],[0,0],[50.138,1],[0,0],[0.75,-40.75],[0,0],[0,0],[-0.317,13.125]],"v":[[-350,-475.25],[-349.82,472.5],[-349.631,573.375],[-349.641,647.5],[311.487,647],[388.805,573],[389.125,-566.75],[310.058,-644.75],[-350.186,-644.5],[-349.433,-550.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,-16.75],[0,0],[0.131,-20.875],[0,0],[0,0],[-1.054,43.75],[0,0],[54.942,-0.625],[0,0],[0,0]],"o":[[0,0],[0.07,32.5],[0,0],[0,0],[50.138,1],[0,0],[0.187,-41.375],[0,0],[0,0],[-0.317,13.125]],"v":[[-315.875,-476.875],[-315.445,471],[-315.256,571.875],[-315.266,646],[348.612,647.562],[427.555,572.75],[427.438,-565.75],[349.058,-643.688],[-316.077,-643.625],[-315.308,-552.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[{"i":[[0,-16.75],[0,0],[0.131,-20.875],[0,0],[0,0],[-1.054,43.75],[0,0],[54.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.07,32.5],[0,0],[0,0],[50.138,1],[0,0],[0.75,-40.75],[0,0],[0,0],[-0.317,13.125]],"v":[[-278.75,-478],[-278.57,469.75],[-278.381,570.625],[-278.391,644.75],[395.237,645.125],[471.554,571],[471.25,-564],[393.808,-642.125],[-278.968,-642.25],[-278.183,-553.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-16.75],[0,0],[-0.119,-21.25],[0,0],[0,0],[-1.054,42.938],[0,0],[54.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.32,32.625],[0,0],[0,0],[50.075,0.562],[0,0],[0.75,-40.75],[0,0],[0,0],[0.183,12.75]],"v":[[-248.25,-479],[-248.82,468.5],[-248.381,550.25],[-248.516,643.75],[440.3,644.25],[515.804,570.375],[516,-564.375],[438.058,-641],[-248.468,-640.125],[-248.308,-541.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.334,"s":[{"i":[[0,-16.75],[0,0],[0.081,-18.8],[0,0],[0,0],[-1.054,42.287],[0,0],[54.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.52,32.725],[0,0],[0,0],[50.025,0.212],[0,0],[0.75,-40.75],[0,0],[0,0],[-1.317,12.05]],"v":[[-223.65,-479.7],[-224.12,467.9],[-224.081,534.35],[-224.116,642.5],[471.15,643.15],[548.004,570.275],[548.2,-564.675],[468.658,-640.1],[-224.668,-638.65],[-224.208,-523.1]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,-16.75],[0,0],[-2.744,-18],[0,0],[0,0],[-1.054,42.125],[0,0],[54.442,-0.625],[0,0],[0,0]],"o":[[0,0],[0.57,32.75],[0,0],[0,0],[50.013,0.125],[0,0],[0.75,-40.75],[0,0],[0,0],[-1.692,11.875]],"v":[[-233.75,-479.75],[-233.57,467.5],[-229.881,530.125],[-213.641,642.5],[478.862,642.875],[556.054,570.25],[556.25,-564.75],[476.308,-639.875],[-212.468,-638.5],[-230.683,-518.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.666,"s":[{"i":[[0.133,-15.433],[0,0],[-4.881,-15.762],[0,0],[0,0],[-1.067,41.975],[0,0],[54.08,-0.675],[0,0],[0,0]],"o":[[0,0],[0.458,32.95],[0,0],[0,0],[49.838,0.162],[0,0],[0.75,-40.625],[0,0],[0,0],[-6.455,9.608]],"v":[[-267.883,-471.067],[-267.329,462.242],[-262.735,514.346],[-201.341,642],[486.187,642.638],[563.142,570.212],[563.35,-564.412],[483.87,-639.625],[-201.81,-638.275],[-260.045,-517.358]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82,"s":[{"i":[[0.4,-12.8],[0,0],[-9.156,-11.287],[0,0],[0,0],[-1.092,41.675],[0,0],[53.355,-0.775],[0,0],[0,0]],"o":[[0,0],[0.233,33.35],[0,0],[0,0],[49.488,0.238],[0,0],[0.75,-40.375],[0,0],[0,0],[-10.48,6.825]],"v":[[-331.65,-460.45],[-331.47,451.725],[-319.444,518.037],[-181.241,641.75],[500.837,642.162],[577.317,570.138],[577.55,-563.737],[498.995,-639.125],[-180.493,-637.825],[-318.77,-515.325]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0,-16.75],[0,0],[-13.431,-6.812],[0,0],[0,0],[-1.117,41.375],[0,0],[52.63,-0.875],[0,0],[0,0]],"o":[[0,0],[0.008,33.75],[0,0],[0,0],[49.138,0.312],[0,0],[0.75,-40.125],[0,0],[0,0],[-18.005,8.375]],"v":[[-387.75,-461.75],[-388.82,454.125],[-369.569,523.312],[-159.641,641.25],[515.487,641.688],[591.492,570.062],[591.75,-563.062],[514.12,-638.625],[-160.843,-637.375],[-367.495,-521.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.666,"s":[{"i":[[0,-16.75],[0,0],[-20.006,-7.188],[0,0],[0,0],[-1.142,41.075],[0,0],[49.955,-0.925],[0,0],[0,0]],"o":[[0,0],[-0.217,34.15],[0,0],[0,0],[48.788,0.387],[0,0],[0.75,-39.875],[0,0],[0,0],[-24.98,7.975]],"v":[[-439.2,-468.15],[-438.72,458.425],[-413.244,530.237],[-141.041,640.35],[527.537,641.212],[603.067,569.987],[603.15,-564.787],[526.445,-638.125],[-143.993,-637.125],[-411.07,-528.125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0,-16.75],[0,0],[-29.869,-7.75],[0,0],[0,0],[-1.179,40.625],[0,0],[45.942,-1],[0,0],[0,0]],"o":[[0,0],[-0.555,34.75],[0,0],[0,0],[48.263,0.5],[0,0],[0.75,-39.5],[0,0],[0,0],[-35.442,7.375]],"v":[[-503.25,-477.75],[-503.57,464.25],[-468.756,540],[-113.141,639],[545.612,640.5],[620.429,569.875],[620.25,-567.375],[544.933,-637.375],[-118.718,-636.75],[-463.308,-537.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0.062,-18.625],[0,0],[-31.869,-6.438],[0,0],[0,0],[-1.179,40.438],[0,0],[44.63,-1],[0,0],[0,0]],"o":[[0,0],[-0.43,34.75],[0,0],[0,0],[47.638,0.625],[0,0],[0.5,-39.062],[0,0],[0,0],[-38.817,5.938]],"v":[[-584.938,-494.688],[-585.445,486.188],[-542.506,557.375],[-88.141,639],[570.612,639.75],[646.054,568.625],[646.188,-566.875],[570.495,-636.625],[-92.093,-636],[-537.183,-555.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0.125,-20.5],[0,0],[-33.869,-5.125],[0,0],[0,0],[-1.179,40.25],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.305,34.75],[0,0],[0,0],[47.013,0.75],[0,0],[0.25,-38.625],[0,0],[0,0],[-42.192,4.5]],"v":[[-640.125,-510.625],[-640.32,507.125],[-589.256,573.75],[-63.141,639],[591.112,639.25],[667.179,567.625],[666.625,-567.5],[593.058,-635.5],[-65.468,-635.25],[-584.558,-571.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0.062,-30.685],[0,0],[-36.306,-4.562],[0,0],[0,0],[-0.59,40.56],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.43,36.25],[0,0],[0,0],[45.45,0.25],[0,0],[0.25,-38.625],[0,0],[0,0],[-41.442,3.938]],"v":[[-676.125,-519.625],[-676.008,522.062],[-617.819,589.812],[-46.391,638.5],[609.862,638.75],[684.617,567.25],[684.375,-566.125],[610.808,-634.75],[-47.593,-634.5],[-616.558,-587.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,-40.869],[0,0],[-38.744,-4],[0,0],[0,0],[0,40.869],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.555,37.75],[0,0],[0,0],[43.888,-0.25],[0,0],[0.25,-38.625],[0,0],[0,0],[-40.692,3.375]],"v":[[-697.625,-528.125],[-696.945,535.5],[-634.381,602.875],[-29.641,638],[625.612,638.25],[699.054,566.875],[699.125,-564.75],[625.558,-634],[-29.718,-633.75],[-633.558,-599.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106.666,"s":[{"i":[[0,-40.869],[0,0],[-42.994,-3.25],[0,0],[0,0],[0,40.869],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.93,42.625],[0,0],[0,0],[43.888,-0.25],[0,0],[0.25,-38.625],[0,0],[0,0],[-41.067,2.125]],"v":[[-715.875,-547.625],[-715.945,550.5],[-647.881,622.875],[-8.891,637.25],[646.487,637.75],[719.679,565.375],[718.875,-563.25],[646.183,-633.75],[-9.218,-633.875],[-649.058,-619.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113.334,"s":[{"i":[[0,-40.869],[0,0],[-44.369,-2],[0,0],[0,0],[0,40.869],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.305,42.5],[0,0],[0,0],[43.888,-0.25],[0,0],[0.25,-38.625],[0,0],[0,0],[-40.423,0]],"v":[[-720.125,-562.375],[-720.82,561.25],[-649.131,634],[3.109,637.25],[658.987,636.625],[729.679,566.125],[729.625,-564.75],[657.308,-633.375],[2.907,-633.625],[-649.808,-630.5]],"c":true}]},{"t":120,"s":[{"i":[[0,-40.869],[0,0],[-46.994,-1.25],[0,0],[0,0],[0,40.869],[0,0],[43.317,-1],[0,0],[0,0]],"o":[[0,0],[-0.305,42.5],[0,0],[0,0],[43.888,-0.25],[0,0],[0.75,-40],[0,0],[0,0],[-40.423,0]],"v":[[-721.75,-564.375],[-721.57,561.5],[-649.631,637.75],[-3.641,637.25],[659.862,637],[733.179,565.625],[732.75,-564.875],[659.058,-634.25],[2.032,-633.75],[-648.683,-634.375]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"rd","nm":"Round Corners 1","r":{"a":0,"k":18,"ix":1},"ix":2,"mn":"ADBE Vector Filter - RC","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-3,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":241,"st":60,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"BUTTON","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[71.498,114.825,0],"ix":2,"l":2},"a":{"a":0,"k":[-698.509,46.873,0],"ix":1,"l":2},"s":{"a":0,"k":[40,18,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-0.549,1.538],[0,0]],"o":[[0,0],[-0.554,-3.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[27.005,73.269],[26.312,72.137],[26,64.269],[25.741,-76.022],[26.183,-82.526],[27.125,-83.046]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-0.987,1.288],[0,0]],"o":[[0,0],[-0.741,-2.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[10.88,76.769],[7.625,75.627],[6.812,68.26],[6.553,-78.594],[7.808,-85.536],[11.375,-86.11]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.424,1.038],[0,0]],"o":[[0,0],[-0.929,-1.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-1.995,80.394],[-4.313,79.127],[-5.625,72.26],[-5.884,-81.156],[-3.817,-88.536],[-1.625,-89.046]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.581,0.831],[0,0]],"o":[[0,0],[-1.154,-1.025],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-4.92,81.663],[-10.263,80.552],[-11.8,73.81],[-11.934,-81.831],[-9.692,-89.236],[-4.55,-89.626]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.817,0.519],[0,0]],"o":[[0,0],[-1.491,-0.875],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-10.917,83.519],[-16.922,82.69],[-18.797,76.135],[-18.744,-82.844],[-16.239,-90.286],[-10.547,-90.546]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.052,0.208],[0,0]],"o":[[0,0],[-1.829,-0.725],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-16.289,85.394],[-21.456,84.827],[-23.669,78.46],[-23.428,-83.856],[-20.661,-91.336],[-15.919,-91.446]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.054,-0.625],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-20.027,86.635],[-23.438,86.252],[-25.875,80.01],[-25.509,-84.531],[-22.567,-92.036],[-19.656,-92.055]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.069,-0.563],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-20.345,86.897],[-24.538,86.552],[-26.994,80.535],[-26.609,-85.031],[-23.661,-92.186],[-19.969,-92.205]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.116,-0.375],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-21.718,87.685],[-26.535,87.452],[-29.048,82.11],[-28.605,-86.531],[-25.64,-92.636],[-21.323,-92.655]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.163,-0.188],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-22.982,88.472],[-27.674,88.352],[-30.243,83.685],[-29.742,-88.031],[-26.76,-93.086],[-22.568,-93.105]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.194,-0.063],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.293,88.997],[-28.485,88.952],[-31.091,84.735],[-30.553,-89.031],[-27.558,-93.386],[-23.866,-93.405]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.558,89.26],[-28.188,89.252],[-30.812,85.26],[-30.255,-89.531],[-27.255,-93.536],[-24.125,-93.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.765,89.36],[-28.394,89.352],[-31.219,85.359],[-30.748,-89.532],[-27.548,-93.536],[-24.419,-93.555]],"c":true}]},{"t":120,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-25.373,90.005],[-27.502,89.998],[-31.127,86],[-31.005,-89.291],[-27.005,-93.291],[-25.375,-93.31]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-698.509,46.873],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":96,"op":241,"st":60,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"BUTTON 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[71.498,179.325,0],"ix":2,"l":2},"a":{"a":0,"k":[-698.509,46.873,0],"ix":1,"l":2},"s":{"a":0,"k":[40,25,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-0.549,1.538],[0,0]],"o":[[0,0],[-0.554,-3.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[27.005,73.269],[26.312,72.137],[26,64.269],[25.741,-76.022],[26.183,-82.526],[27.125,-83.046]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-0.987,1.288],[0,0]],"o":[[0,0],[-0.741,-2.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[10.88,76.769],[7.625,75.627],[6.812,68.26],[6.553,-78.594],[7.808,-85.536],[11.375,-86.11]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.424,1.038],[0,0]],"o":[[0,0],[-0.929,-1.125],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-1.995,80.394],[-4.313,79.127],[-5.625,72.26],[-5.884,-81.156],[-3.817,-88.536],[-1.625,-89.046]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.581,0.831],[0,0]],"o":[[0,0],[-1.154,-1.025],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-4.92,81.663],[-10.263,80.552],[-11.8,73.81],[-11.934,-81.831],[-9.692,-89.236],[-4.55,-89.626]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-1.817,0.519],[0,0]],"o":[[0,0],[-1.491,-0.875],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-10.917,83.519],[-16.922,82.69],[-18.797,76.135],[-18.744,-82.844],[-16.239,-90.286],[-10.547,-90.546]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.052,0.208],[0,0]],"o":[[0,0],[-1.829,-0.725],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-16.289,85.394],[-21.456,84.827],[-23.669,78.46],[-23.428,-83.856],[-20.661,-91.336],[-15.919,-91.446]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":106.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.054,-0.625],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-20.027,86.635],[-23.438,86.252],[-25.875,80.01],[-25.509,-84.531],[-22.567,-92.036],[-19.656,-92.055]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.069,-0.563],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-20.345,86.897],[-24.538,86.552],[-26.994,80.535],[-26.609,-85.031],[-23.661,-92.186],[-19.969,-92.205]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.116,-0.375],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-21.718,87.685],[-26.535,87.452],[-29.048,82.11],[-28.605,-86.531],[-25.64,-92.636],[-21.323,-92.655]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.163,-0.188],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-22.982,88.472],[-27.674,88.352],[-30.243,83.685],[-29.742,-88.031],[-26.76,-93.086],[-22.568,-93.105]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.194,-0.063],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.293,88.997],[-28.485,88.952],[-31.091,84.735],[-30.553,-89.031],[-27.558,-93.386],[-23.866,-93.405]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113.334,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.558,89.26],[-28.188,89.252],[-30.812,85.26],[-30.255,-89.531],[-27.255,-93.536],[-24.125,-93.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.666,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-24.765,89.36],[-28.394,89.352],[-31.219,85.359],[-30.748,-89.532],[-27.548,-93.536],[-24.419,-93.555]],"c":true}]},{"t":120,"s":[{"i":[[0,0],[0,0],[0,2.209],[0,0],[-2.209,0],[0,0]],"o":[[0,0],[-2.209,0],[0,0],[0,-2.209],[0,0],[0,0]],"v":[[-25.373,89.63],[-27.502,89.623],[-31.127,85.625],[-31.005,-89.666],[-27.005,-93.666],[-25.375,-93.685]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-698.509,46.873],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":96,"op":241,"st":60,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/rear_display_turnaround.json b/packages/SystemUI/res/raw/rear_display_turnaround.json
new file mode 100644
index 0000000..82204c7
--- /dev/null
+++ b/packages/SystemUI/res/raw/rear_display_turnaround.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":412,"h":300,"nm":"Turnaround - Generic Version V01","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"SHUTTER_ANIMATION 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":55,"s":[100]},{"t":60,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":320.842,"ix":3},"y":{"a":0,"k":149.716,"ix":4}},"a":{"a":0,"k":[460.228,450.736,0],"ix":1,"l":2},"s":{"a":0,"k":[150,150,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.528,0],[0,-2.528],[2.528,0],[0,2.528]],"o":[[2.528,0],[0,2.528],[-2.528,0],[0,-2.528]],"v":[[0,-4.5],[4.5,0],[0,4.5],[-4.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 599","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[140,140],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_01","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.337,0],[0,-5.337],[5.337,0],[0,5.337]],"o":[[5.337,0],[0,5.337],[-5.337,0],[0,-5.337]],"v":[[0,-9.5],[9.5,0],[0,9.5],[-9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 598","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_02","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":150,"st":-90,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"SHUTTER_ANIMATION","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":51,"s":[0]},{"t":56,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"s":true,"x":{"a":0,"k":286.342,"ix":3},"y":{"a":0,"k":245.716,"ix":4}},"a":{"a":0,"k":[460.228,450.736,0],"ix":1,"l":2},"s":{"a":0,"k":[150,150,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-2.528,0],[0,-2.528],[2.528,0],[0,2.528]],"o":[[2.528,0],[0,2.528],[-2.528,0],[0,-2.528]],"v":[[0,-4.5],[4.5,0],[0,4.5],[-4.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 599","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[140,140],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":129,"s":[0]},{"t":139,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_01","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.337,0],[0,-5.337],[5.337,0],[0,5.337]],"o":[[5.337,0],[0,5.337],[-5.337,0],[0,-5.337]],"v":[[0,-9.5],[9.5,0],[0,9.5],[-9.5,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 598","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tr","p":{"a":0,"k":[460.228,450.736],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":129,"s":[0]},{"t":139,"s":[100]}],"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"SHUTTER_02","np":1,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":129,"op":279,"st":39,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"PATCH 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.062,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[54.347,-125.337],[54.347,125.337],[-15.847,125.337],[-15.847,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[34.347,-125.337],[34.347,125.337],[-35.847,125.337],[-35.847,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.166,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.683,-125.337],[-3.683,125.337],[-73.877,125.337],[-73.877,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-3.867,-125.337],[-3.867,125.337],[-74.061,125.337],[-74.061,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":113.334,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.606,-125.337],[-1.606,125.337],[-71.799,125.337],[-71.799,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":115,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[0.775,-125.337],[0.775,125.337],[-69.418,125.337],[-69.418,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":117.5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4.347,-125.337],[4.347,125.337],[-65.847,125.337],[-65.847,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":121.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[9.686,-125.337],[9.686,125.337],[-60.508,125.337],[-60.508,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":122.5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[11.954,-125.337],[11.954,125.337],[-58.24,125.337],[-58.24,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":125.834,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[14.759,-125.337],[14.759,125.337],[-55.435,125.337],[-55.435,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[15.668,-125.337],[15.668,125.337],[-54.525,125.337],[-54.525,-125.337]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":128.334,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[15.987,-125.337],[15.987,125.337],[-54.206,125.337],[-54.206,-125.337]],"c":true}]},{"t":135,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[16.847,-125.337],[16.847,125.337],[-53.347,125.337],[-53.347,-125.337]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-674.097,51.337],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":99,"op":300,"st":60,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"PATCH","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[207.908,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[722.046,-80],[722.046,165.813],[708.25,165.813],[708.25,-80]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[736.168,-80],[736.168,165.813],[722.372,165.813],[722.372,-80]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65.834,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[737.98,-80],[737.98,165.813],[724.184,165.813],[724.184,-80]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[739.435,-80],[739.435,165.813],[725.639,165.813],[725.639,-80]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":67.5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[740.796,-80],[740.796,165.813],[727,165.813],[727,-80]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":69.166,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[743.651,-79.231],[743.651,166.583],[729.855,166.583],[729.855,-79.231]],"c":true}]},{"t":72.5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[738.112,-77.692],[738.112,168.121],[724.316,168.121],[724.316,-77.692]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":0,"op":74,"st":60,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"BUTTON_OUT_BOTTOM 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0},"t":60,"s":[206.312,95.219,0],"to":[0,-2.417,0],"ti":[0,0,0]},{"i":{"x":0.333,"y":1},"o":{"x":0.167,"y":0.167},"t":88,"s":[206.312,80.719,0],"to":[0,0,0],"ti":[0,-2.417,0]},{"t":128,"s":[206.312,95.219,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,18,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-9.113],[0,0],[3.544,-0.062],[0,9.113],[0,0],[-1.905,0.228]],"o":[[0,0],[0,9.113],[-1.908,0.034],[0,0],[0,-9.113],[4.17,-0.5]],"v":[[687.673,-97.826],[687.673,65.299],[679.205,76.875],[675.75,65.375],[675.75,-97.75],[679.205,-108.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,-9.113],[0,0],[4.532,-0.062],[0,9.113],[0,0],[-2.436,0.228]],"o":[[0,0],[0,9.113],[-2.44,0.034],[0,0],[0,-9.113],[5.332,-0.5]],"v":[[699.977,-97.944],[699.977,68.306],[689.293,80],[684.875,68.5],[684.875,-97.75],[689.293,-108.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,-9.113],[0,0],[4.532,-0.062],[0,9.113],[0,0],[-2.436,0.228]],"o":[[0,0],[0,9.113],[-2.44,0.034],[0,0],[0,-9.113],[5.332,-0.5]],"v":[[711.227,-100.491],[711.227,76.697],[700.543,87.875],[696.125,76.375],[696.125,-100.812],[700.543,-111.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,-9.113],[0,0],[5.113,-0.062],[0,9.113],[0,0],[-2.748,0.228]],"o":[[0,0],[0,9.113],[-2.753,0.034],[0,0],[0,-9.113],[6.016,-0.5]],"v":[[700.685,-102.905],[700.685,81.345],[692.568,93.125],[687.583,81.625],[687.583,-102.625],[692.568,-113.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74.166,"s":[{"i":[[0,-9.113],[0,0],[5.694,-0.062],[0,9.113],[0,0],[-3.061,0.228]],"o":[[0,0],[0,9.113],[-3.065,0.034],[0,0],[0,-9.113],[6.699,-0.5]],"v":[[691.581,-103.125],[691.581,83.5],[686.03,95],[680.479,83.5],[680.479,-103.125],[686.03,-114]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,-9.113],[0,0],[6.275,-0.062],[0,9.113],[0,0],[-3.373,0.228]],"o":[[0,0],[0,9.113],[-3.378,0.034],[0,0],[0,-9.113],[7.383,-0.5]],"v":[[683.359,-103.625],[683.359,85.375],[677.242,96.875],[671.125,85.375],[671.125,-103.625],[677.242,-114.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75.834,"s":[{"i":[[0,-9.113],[0,0],[6.856,-0.062],[0,9.113],[0,0],[-3.685,0.228]],"o":[[0,0],[0,9.113],[-3.691,0.034],[0,0],[0,-9.113],[8.066,-0.5]],"v":[[672.305,-104.125],[672.305,87.25],[665.621,98.75],[658.938,87.25],[658.938,-104.125],[665.621,-115]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-9.113],[0,0],[7.438,-0.062],[0,9.113],[0,0],[-3.997,0.228]],"o":[[0,0],[0,9.113],[-4.004,0.034],[0,0],[0,-9.113],[8.75,-0.5]],"v":[[657.5,-104.625],[657.5,89.125],[650.25,100.625],[643,89.125],[643,-104.625],[650.25,-115.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77.5,"s":[{"i":[[0,-9.113],[0,0],[7.149,-0.047],[0,9.113],[0,0],[-4.569,0.171]],"o":[[0,0],[0,9.113],[-4.573,0.025],[0,0],[0,-9.113],[8.133,-0.375]],"v":[[637.562,-104.531],[637.562,90.531],[629.281,103.281],[621,90.531],[621,-104.531],[629.281,-116.812]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78.334,"s":[{"i":[[0,-9.113],[0,0],[6.86,-0.031],[0,9.113],[0,0],[-5.14,0.114]],"o":[[0,0],[0,9.113],[-5.143,0.017],[0,0],[0,-9.113],[7.516,-0.25]],"v":[[612.625,-104.438],[612.625,91.938],[603.312,105.938],[594,91.938],[594,-104.438],[603.312,-118.125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[0,-9.113],[0,0],[6.571,-0.016],[0,9.113],[0,0],[-5.711,0.057]],"o":[[0,0],[0,9.113],[-5.713,0.008],[0,0],[0,-9.113],[6.899,-0.125]],"v":[[580.188,-104.094],[580.188,93.594],[569.844,108.844],[559.5,93.594],[559.5,-104.094],[569.844,-119.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,-9.113],[0,0],[6.282,0],[0,9.113],[0,0],[-6.282,0]],"o":[[0,0],[0,9.113],[-6.282,0],[0,0],[0,-9.113],[6.282,0]],"v":[[540.25,-103.75],[540.25,95.25],[528.875,111.75],[517.5,95.25],[517.5,-103.75],[528.875,-120.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[0,-9.113],[0,0],[6.731,0],[0,9.113],[0,0],[-6.731,0]],"o":[[0,0],[0,9.113],[-6.731,0],[0,0],[0,-9.113],[6.731,0]],"v":[[491.25,-104.562],[491.25,97.688],[479.062,114.188],[466.875,97.688],[466.875,-104.562],[479.062,-121.062]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0,-9.113],[0,0],[7.18,0],[0,9.113],[0,0],[-7.18,0]],"o":[[0,0],[0,9.113],[-7.18,0],[0,0],[0,-9.113],[7.18,0]],"v":[[432.958,-105.375],[432.958,100.125],[419.958,116.625],[406.958,100.125],[406.958,-105.375],[419.958,-121.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[0,-9.113],[0,0],[7.628,0],[0,9.113],[0,0],[-7.628,0]],"o":[[0,0],[0,9.113],[-7.628,0],[0,0],[0,-9.113],[7.628,0]],"v":[[364.854,-106.188],[364.854,102.562],[351.042,119.062],[337.229,102.562],[337.229,-106.188],[351.042,-122.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0,-9.113],[0,0],[8.077,0],[0,9.113],[0,0],[-8.077,0]],"o":[[0,0],[0,9.113],[-8.077,0],[0,0],[0,-9.113],[8.077,0]],"v":[[286.75,-107],[286.75,105],[272.125,121.5],[257.5,105],[257.5,-107],[272.125,-123.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0,-9.113],[0,0],[8.33,0],[0,9.113],[0,0],[-8.33,0]],"o":[[0,0],[0,9.113],[-8.33,0],[0,0],[0,-9.113],[8.33,0]],"v":[[201.667,-107.5],[201.667,106.167],[186.583,122.667],[171.5,106.167],[171.5,-107.5],[186.583,-124]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,-9.113],[0,0],[8.583,0],[0,9.113],[0,0],[-8.583,0]],"o":[[0,0],[0,9.113],[-8.583,0],[0,0],[0,-9.113],[8.583,0]],"v":[[110.333,-108],[110.333,107.333],[94.792,123.833],[79.25,107.333],[79.25,-108],[94.792,-124.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85.834,"s":[{"i":[[0,-9.113],[0,0],[8.837,0],[0,9.113],[0,0],[-8.837,0]],"o":[[0,0],[0,9.113],[-8.837,0],[0,0],[0,-9.113],[8.837,0]],"v":[[16.5,-108.5],[16.5,108.5],[0.5,125],[-15.5,108.5],[-15.5,-108.5],[0.5,-125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0,-9.113],[0,0],[8.698,0],[0,9.113],[0,0],[-8.699,0]],"o":[[0,0],[0,9.113],[-8.699,0],[0,0],[0,-9.113],[8.698,0]],"v":[[-75.766,-108.229],[-75.766,107.667],[-91.516,124.167],[-107.266,107.667],[-107.266,-108.229],[-91.516,-124.729]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0,-9.113],[0,0],[8.56,0],[0,9.113],[0,0],[-8.56,0]],"o":[[0,0],[0,9.113],[-8.56,0],[0,0],[0,-9.113],[8.56,0]],"v":[[-166.781,-107.958],[-166.781,106.833],[-182.281,123.333],[-197.781,106.833],[-197.781,-107.958],[-182.281,-124.458]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[0,-9.113],[0,0],[8.422,0],[0,9.113],[0,0],[-8.422,0]],"o":[[0,0],[0,9.113],[-8.422,0],[0,0],[0,-9.113],[8.422,0]],"v":[[-252.172,-107.688],[-252.172,106],[-267.422,122.5],[-282.672,106],[-282.672,-107.688],[-267.422,-124.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[0,-9.113],[0,0],[8.284,0],[0,9.113],[0,0],[-8.284,0]],"o":[[0,0],[0,9.113],[-8.284,0],[0,0],[0,-9.113],[8.284,0]],"v":[[-330.062,-107.417],[-330.062,105.167],[-345.062,121.667],[-360.062,105.167],[-360.062,-107.417],[-345.062,-123.917]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,-9.113],[0,0],[8.146,0],[0,9.113],[0,0],[-8.146,0]],"o":[[0,0],[0,9.113],[-8.146,0],[0,0],[0,-9.113],[8.146,0]],"v":[[-400.781,-107.146],[-400.781,103.396],[-415.531,119.896],[-430.281,103.396],[-430.281,-107.146],[-415.531,-123.646]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[0,-9.113],[0,0],[8.008,0],[0,9.113],[0,0],[-8.008,0]],"o":[[0,0],[0,9.113],[-8.008,0],[0,0],[0,-9.113],[8.008,0]],"v":[[-462.75,-106.875],[-462.75,101.625],[-477.25,118.125],[-491.75,101.625],[-491.75,-106.875],[-477.25,-123.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[0,-9.113],[0,0],[7.525,0],[0,9.113],[0,0],[-7.525,0]],"o":[[0,0],[0,9.113],[-7.525,0],[0,0],[0,-9.113],[7.525,0]],"v":[[-518.308,-106.5],[-518.308,100.125],[-531.933,116.125],[-545.558,100.125],[-545.558,-106.5],[-531.933,-122.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[0,-9.113],[0,0],[7.042,0],[0,9.113],[0,0],[-7.042,0]],"o":[[0,0],[0,9.113],[-7.042,0],[0,0],[0,-9.113],[7.042,0]],"v":[[-566.367,-106.125],[-566.367,98.625],[-579.117,114.125],[-591.867,98.625],[-591.867,-106.125],[-579.117,-121.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,-9.113],[0,0],[6.558,0],[0,9.113],[0,0],[-6.558,0]],"o":[[0,0],[0,9.113],[-6.558,0],[0,0],[0,-9.113],[6.558,0]],"v":[[-606.925,-105.75],[-606.925,97.125],[-618.8,112.125],[-630.675,97.125],[-630.675,-105.75],[-618.8,-120.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[0,-9.113],[0,0],[6.075,0],[0,9.113],[0,0],[-6.075,0]],"o":[[0,0],[0,9.113],[-6.075,0],[0,0],[0,-9.113],[6.075,0]],"v":[[-641.963,-105.375],[-641.963,95.625],[-652.963,110.125],[-663.963,95.625],[-663.963,-105.375],[-652.963,-119.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,-9.113],[0,0],[5.592,0],[0,9.113],[0,0],[-5.592,0]],"o":[[0,0],[0,9.113],[-5.592,0],[0,0],[0,-9.113],[5.592,0]],"v":[[-671.062,-105],[-671.062,94.125],[-681.188,108.125],[-691.312,94.125],[-691.312,-105],[-681.188,-119]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[0,-9.113],[0,0],[5.295,0],[0,9.113],[0,0],[-5.295,0]],"o":[[0,0],[0,9.113],[-5.295,0],[0,0],[0,-9.113],[5.295,0]],"v":[[-696.971,-104.5],[-696.971,92.5],[-706.558,106.25],[-716.146,92.5],[-716.146,-104.5],[-706.558,-118.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0,-9.113],[0,0],[4.998,0],[0,9.113],[0,0],[-4.998,0]],"o":[[0,0],[0,9.113],[-4.998,0],[0,0],[0,-9.113],[4.998,0]],"v":[[-718.192,-104],[-718.192,90.875],[-727.242,104.375],[-736.292,90.875],[-736.292,-104],[-727.242,-117.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,-9.113],[0,0],[4.701,0],[0,9.113],[0,0],[-4.701,0]],"o":[[0,0],[0,9.113],[-4.701,0],[0,0],[0,-9.113],[4.701,0]],"v":[[-735.35,-103.5],[-735.35,89.25],[-743.862,102.5],[-752.375,89.25],[-752.375,-103.5],[-743.862,-116.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98.334,"s":[{"i":[[0,-9.113],[0,0],[4.404,0],[0,9.113],[0,0],[-4.404,0]],"o":[[0,0],[0,9.113],[-4.404,0],[0,0],[0,-9.113],[4.404,0]],"v":[[-750.425,-103],[-750.425,87.625],[-758.4,100.625],[-766.375,87.625],[-766.375,-103],[-758.4,-116]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,-9.113],[0,0],[4.108,0],[0,9.113],[0,0],[-4.108,0]],"o":[[0,0],[0,9.113],[-4.108,0],[0,0],[0,-9.113],[4.108,0]],"v":[[-761.75,-102.5],[-761.75,86],[-769.188,98.75],[-776.625,86],[-776.625,-102.5],[-769.188,-115.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,-9.113],[0,0],[3.844,-0.015],[0.141,9.991],[0,0],[-4.51,0]],"o":[[0,0],[0,9.113],[-4.635,0.031],[0,0],[0.016,-9.897],[3.844,0]],"v":[[-771.312,-102.188],[-771.312,84.594],[-778.273,97.344],[-785.234,84.594],[-785.234,-102.188],[-778.273,-114.938]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[0,-9.113],[0,0],[3.581,-0.031],[0.281,10.869],[0,0],[-4.913,0]],"o":[[0,0],[0,9.113],[-5.163,0.062],[0,0],[0.031,-10.681],[3.581,0]],"v":[[-779.25,-101.875],[-779.25,83.188],[-785.734,95.938],[-792.219,83.188],[-792.219,-101.875],[-785.734,-114.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0,-9.113],[0,0],[3.317,-0.046],[0.422,11.747],[0,0],[-5.316,0]],"o":[[0,0],[0,9.113],[-5.691,0.094],[0,0],[0.047,-11.466],[3.318,0]],"v":[[-786.125,-101.562],[-786.125,81.781],[-792.133,94.531],[-798.141,81.781],[-798.141,-101.562],[-792.133,-114.312]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":102.5,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.061],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.219,0.125],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-791.75,-101.25],[-791.75,80.375],[-797.281,93.125],[-802.812,80.375],[-802.812,-101.25],[-797.281,-114]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.07],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.51,0.153],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-796.934,-100.556],[-796.934,78.292],[-802.465,91.042],[-807.997,78.292],[-807.997,-100.556],[-802.465,-113.306]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.079],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.802,0.181],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-799.618,-99.861],[-799.618,76.208],[-805.149,88.958],[-810.681,76.208],[-810.681,-99.861],[-805.149,-112.611]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108.334,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.092],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.24,0.222],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-800.61,-98.819],[-800.61,73.083],[-806.141,85.833],[-811.672,73.083],[-811.672,-98.819],[-806.141,-111.569]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-799.188,-98.125],[-799.188,71],[-804.719,83.75],[-814.636,70.875],[-814.636,-98.25],[-804.719,-110.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":119,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-787.944,-96.125],[-787.944,66.75],[-793.475,79.5],[-804.019,66.875],[-804.019,-96],[-793.475,-108.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":124,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-780.109,-96.579],[-780.109,65.77],[-785.64,78.355],[-796.184,65.566],[-796.184,-96.783],[-785.64,-108.836]],"c":true}]},{"t":128,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-779.207,-96.704],[-779.207,65.118],[-784.738,77.54],[-794.029,65.112],[-794.029,-96.71],[-784.738,-108.467]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[53.5,61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":60,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"BUTTON_OUT_BOTTOM","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,157.219,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,25,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-9.113],[0,0],[3.544,-0.062],[0,9.113],[0,0],[-1.905,0.228]],"o":[[0,0],[0,9.113],[-1.908,0.034],[0,0],[0,-9.113],[4.17,-0.5]],"v":[[688.299,-98],[688.299,65.125],[679.205,76.875],[675.75,65.375],[675.75,-97.75],[679.205,-108.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,-9.113],[0,0],[4.532,-0.062],[0,9.113],[0,0],[-2.436,0.228]],"o":[[0,0],[0,9.113],[-2.44,0.034],[0,0],[0,-9.113],[5.332,-0.5]],"v":[[701.856,-97.875],[701.856,68.375],[689.293,80],[684.875,68.5],[684.875,-97.75],[689.293,-108.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[0,-9.113],[0,0],[4.532,-0.062],[0,9.113],[0,0],[-2.436,0.228]],"o":[[0,0],[0,9.113],[-2.44,0.034],[0,0],[0,-9.113],[5.332,-0.5]],"v":[[709.974,-101.062],[709.974,76.125],[700.543,87.875],[696.125,76.375],[696.125,-100.812],[700.543,-111.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73,"s":[{"i":[[0,-9.113],[0,0],[5.113,-0.062],[0,9.113],[0,0],[-2.748,0.228]],"o":[[0,0],[0,9.113],[-2.753,0.034],[0,0],[0,-9.113],[6.016,-0.5]],"v":[[703.818,-102.625],[703.818,81.625],[692.568,93.125],[687.583,81.625],[687.583,-102.625],[692.568,-113.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74.166,"s":[{"i":[[0,-9.113],[0,0],[5.694,-0.062],[0,9.113],[0,0],[-3.061,0.228]],"o":[[0,0],[0,9.113],[-3.065,0.034],[0,0],[0,-9.113],[6.699,-0.5]],"v":[[691.581,-103.125],[691.581,83.5],[686.03,95],[680.479,83.5],[680.479,-103.125],[686.03,-114]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,-9.113],[0,0],[6.275,-0.062],[0,9.113],[0,0],[-3.373,0.228]],"o":[[0,0],[0,9.113],[-3.378,0.034],[0,0],[0,-9.113],[7.383,-0.5]],"v":[[683.359,-103.625],[683.359,85.375],[677.242,96.875],[671.125,85.375],[671.125,-103.625],[677.242,-114.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75.834,"s":[{"i":[[0,-9.113],[0,0],[6.856,-0.062],[0,9.113],[0,0],[-3.685,0.228]],"o":[[0,0],[0,9.113],[-3.691,0.034],[0,0],[0,-9.113],[8.066,-0.5]],"v":[[672.305,-104.125],[672.305,87.25],[665.621,98.75],[658.938,87.25],[658.938,-104.125],[665.621,-115]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-9.113],[0,0],[7.438,-0.062],[0,9.113],[0,0],[-3.997,0.228]],"o":[[0,0],[0,9.113],[-4.004,0.034],[0,0],[0,-9.113],[8.75,-0.5]],"v":[[657.5,-104.625],[657.5,89.125],[650.25,100.625],[643,89.125],[643,-104.625],[650.25,-115.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77.5,"s":[{"i":[[0,-9.113],[0,0],[7.149,-0.047],[0,9.113],[0,0],[-4.569,0.171]],"o":[[0,0],[0,9.113],[-4.573,0.025],[0,0],[0,-9.113],[8.133,-0.375]],"v":[[637.562,-104.531],[637.562,90.531],[629.281,103.281],[621,90.531],[621,-104.531],[629.281,-116.812]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78.334,"s":[{"i":[[0,-9.113],[0,0],[6.86,-0.031],[0,9.113],[0,0],[-5.14,0.114]],"o":[[0,0],[0,9.113],[-5.143,0.017],[0,0],[0,-9.113],[7.516,-0.25]],"v":[[612.625,-104.438],[612.625,91.938],[603.312,105.938],[594,91.938],[594,-104.438],[603.312,-118.125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[0,-9.113],[0,0],[6.571,-0.016],[0,9.113],[0,0],[-5.711,0.057]],"o":[[0,0],[0,9.113],[-5.713,0.008],[0,0],[0,-9.113],[6.899,-0.125]],"v":[[580.188,-104.094],[580.188,93.594],[569.844,108.844],[559.5,93.594],[559.5,-104.094],[569.844,-119.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,-9.113],[0,0],[6.282,0],[0,9.113],[0,0],[-6.282,0]],"o":[[0,0],[0,9.113],[-6.282,0],[0,0],[0,-9.113],[6.282,0]],"v":[[540.25,-103.75],[540.25,95.25],[528.875,111.75],[517.5,95.25],[517.5,-103.75],[528.875,-120.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[0,-9.113],[0,0],[6.731,0],[0,9.113],[0,0],[-6.731,0]],"o":[[0,0],[0,9.113],[-6.731,0],[0,0],[0,-9.113],[6.731,0]],"v":[[491.25,-104.562],[491.25,97.688],[479.062,114.188],[466.875,97.688],[466.875,-104.562],[479.062,-121.062]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0,-9.113],[0,0],[7.18,0],[0,9.113],[0,0],[-7.18,0]],"o":[[0,0],[0,9.113],[-7.18,0],[0,0],[0,-9.113],[7.18,0]],"v":[[432.958,-105.375],[432.958,100.125],[419.958,116.625],[406.958,100.125],[406.958,-105.375],[419.958,-121.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[0,-9.113],[0,0],[7.628,0],[0,9.113],[0,0],[-7.628,0]],"o":[[0,0],[0,9.113],[-7.628,0],[0,0],[0,-9.113],[7.628,0]],"v":[[364.854,-106.188],[364.854,102.562],[351.042,119.062],[337.229,102.562],[337.229,-106.188],[351.042,-122.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0,-9.113],[0,0],[8.077,0],[0,9.113],[0,0],[-8.077,0]],"o":[[0,0],[0,9.113],[-8.077,0],[0,0],[0,-9.113],[8.077,0]],"v":[[286.75,-107],[286.75,105],[272.125,121.5],[257.5,105],[257.5,-107],[272.125,-123.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0,-9.113],[0,0],[8.33,0],[0,9.113],[0,0],[-8.33,0]],"o":[[0,0],[0,9.113],[-8.33,0],[0,0],[0,-9.113],[8.33,0]],"v":[[201.667,-107.5],[201.667,106.167],[186.583,122.667],[171.5,106.167],[171.5,-107.5],[186.583,-124]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,-9.113],[0,0],[8.583,0],[0,9.113],[0,0],[-8.583,0]],"o":[[0,0],[0,9.113],[-8.583,0],[0,0],[0,-9.113],[8.583,0]],"v":[[110.333,-108],[110.333,107.333],[94.792,123.833],[79.25,107.333],[79.25,-108],[94.792,-124.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85.834,"s":[{"i":[[0,-9.113],[0,0],[8.837,0],[0,9.113],[0,0],[-8.837,0]],"o":[[0,0],[0,9.113],[-8.837,0],[0,0],[0,-9.113],[8.837,0]],"v":[[16.5,-108.5],[16.5,108.5],[0.5,125],[-15.5,108.5],[-15.5,-108.5],[0.5,-125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0,-9.113],[0,0],[8.698,0],[0,9.113],[0,0],[-8.699,0]],"o":[[0,0],[0,9.113],[-8.699,0],[0,0],[0,-9.113],[8.698,0]],"v":[[-75.766,-108.229],[-75.766,107.667],[-91.516,124.167],[-107.266,107.667],[-107.266,-108.229],[-91.516,-124.729]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0,-9.113],[0,0],[8.56,0],[0,9.113],[0,0],[-8.56,0]],"o":[[0,0],[0,9.113],[-8.56,0],[0,0],[0,-9.113],[8.56,0]],"v":[[-166.781,-107.958],[-166.781,106.833],[-182.281,123.333],[-197.781,106.833],[-197.781,-107.958],[-182.281,-124.458]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[0,-9.113],[0,0],[8.422,0],[0,9.113],[0,0],[-8.422,0]],"o":[[0,0],[0,9.113],[-8.422,0],[0,0],[0,-9.113],[8.422,0]],"v":[[-252.172,-107.688],[-252.172,106],[-267.422,122.5],[-282.672,106],[-282.672,-107.688],[-267.422,-124.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[0,-9.113],[0,0],[8.284,0],[0,9.113],[0,0],[-8.284,0]],"o":[[0,0],[0,9.113],[-8.284,0],[0,0],[0,-9.113],[8.284,0]],"v":[[-330.062,-107.417],[-330.062,105.167],[-345.062,121.667],[-360.062,105.167],[-360.062,-107.417],[-345.062,-123.917]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,-9.113],[0,0],[8.146,0],[0,9.113],[0,0],[-8.146,0]],"o":[[0,0],[0,9.113],[-8.146,0],[0,0],[0,-9.113],[8.146,0]],"v":[[-400.781,-107.146],[-400.781,103.396],[-415.531,119.896],[-430.281,103.396],[-430.281,-107.146],[-415.531,-123.646]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[0,-9.113],[0,0],[8.008,0],[0,9.113],[0,0],[-8.008,0]],"o":[[0,0],[0,9.113],[-8.008,0],[0,0],[0,-9.113],[8.008,0]],"v":[[-462.75,-106.875],[-462.75,101.625],[-477.25,118.125],[-491.75,101.625],[-491.75,-106.875],[-477.25,-123.375]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[0,-9.113],[0,0],[7.525,0],[0,9.113],[0,0],[-7.525,0]],"o":[[0,0],[0,9.113],[-7.525,0],[0,0],[0,-9.113],[7.525,0]],"v":[[-518.308,-106.5],[-518.308,100.125],[-531.933,116.125],[-545.558,100.125],[-545.558,-106.5],[-531.933,-122.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[0,-9.113],[0,0],[7.042,0],[0,9.113],[0,0],[-7.042,0]],"o":[[0,0],[0,9.113],[-7.042,0],[0,0],[0,-9.113],[7.042,0]],"v":[[-566.367,-106.125],[-566.367,98.625],[-579.117,114.125],[-591.867,98.625],[-591.867,-106.125],[-579.117,-121.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,-9.113],[0,0],[6.558,0],[0,9.113],[0,0],[-6.558,0]],"o":[[0,0],[0,9.113],[-6.558,0],[0,0],[0,-9.113],[6.558,0]],"v":[[-606.925,-105.75],[-606.925,97.125],[-618.8,112.125],[-630.675,97.125],[-630.675,-105.75],[-618.8,-120.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[0,-9.113],[0,0],[6.075,0],[0,9.113],[0,0],[-6.075,0]],"o":[[0,0],[0,9.113],[-6.075,0],[0,0],[0,-9.113],[6.075,0]],"v":[[-641.963,-105.375],[-641.963,95.625],[-652.963,110.125],[-663.963,95.625],[-663.963,-105.375],[-652.963,-119.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,-9.113],[0,0],[5.592,0],[0,9.113],[0,0],[-5.592,0]],"o":[[0,0],[0,9.113],[-5.592,0],[0,0],[0,-9.113],[5.592,0]],"v":[[-671.062,-105],[-671.062,94.125],[-681.188,108.125],[-691.312,94.125],[-691.312,-105],[-681.188,-119]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[0,-9.113],[0,0],[5.295,0],[0,9.113],[0,0],[-5.295,0]],"o":[[0,0],[0,9.113],[-5.295,0],[0,0],[0,-9.113],[5.295,0]],"v":[[-696.971,-104.5],[-696.971,92.5],[-706.558,106.25],[-716.146,92.5],[-716.146,-104.5],[-706.558,-118.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0,-9.113],[0,0],[4.998,0],[0,9.113],[0,0],[-4.998,0]],"o":[[0,0],[0,9.113],[-4.998,0],[0,0],[0,-9.113],[4.998,0]],"v":[[-718.192,-104],[-718.192,90.875],[-727.242,104.375],[-736.292,90.875],[-736.292,-104],[-727.242,-117.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,-9.113],[0,0],[4.701,0],[0,9.113],[0,0],[-4.701,0]],"o":[[0,0],[0,9.113],[-4.701,0],[0,0],[0,-9.113],[4.701,0]],"v":[[-735.35,-103.5],[-735.35,89.25],[-743.862,102.5],[-752.375,89.25],[-752.375,-103.5],[-743.862,-116.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98.334,"s":[{"i":[[0,-9.113],[0,0],[4.404,0],[0,9.113],[0,0],[-4.404,0]],"o":[[0,0],[0,9.113],[-4.404,0],[0,0],[0,-9.113],[4.404,0]],"v":[[-750.425,-103],[-750.425,87.625],[-758.4,100.625],[-766.375,87.625],[-766.375,-103],[-758.4,-116]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,-9.113],[0,0],[4.108,0],[0,9.113],[0,0],[-4.108,0]],"o":[[0,0],[0,9.113],[-4.108,0],[0,0],[0,-9.113],[4.108,0]],"v":[[-761.75,-102.5],[-761.75,86],[-769.188,98.75],[-776.625,86],[-776.625,-102.5],[-769.188,-115.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0,-9.113],[0,0],[3.844,-0.015],[0.141,9.991],[0,0],[-4.51,0]],"o":[[0,0],[0,9.113],[-4.635,0.031],[0,0],[0.016,-9.897],[3.844,0]],"v":[[-771.312,-102.188],[-771.312,84.594],[-778.273,97.344],[-785.234,84.594],[-785.234,-102.188],[-778.273,-114.938]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[0,-9.113],[0,0],[3.581,-0.031],[0.281,10.869],[0,0],[-4.913,0]],"o":[[0,0],[0,9.113],[-5.163,0.062],[0,0],[0.031,-10.681],[3.581,0]],"v":[[-779.25,-101.875],[-779.25,83.188],[-785.734,95.938],[-792.219,83.188],[-792.219,-101.875],[-785.734,-114.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0,-9.113],[0,0],[3.317,-0.046],[0.422,11.747],[0,0],[-5.316,0]],"o":[[0,0],[0,9.113],[-5.691,0.094],[0,0],[0.047,-11.466],[3.318,0]],"v":[[-786.125,-101.562],[-786.125,81.781],[-792.133,94.531],[-798.141,81.781],[-798.141,-101.562],[-792.133,-114.312]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":102.5,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.061],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.219,0.125],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-791.75,-101.25],[-791.75,80.375],[-797.281,93.125],[-802.812,80.375],[-802.812,-101.25],[-797.281,-114]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.07],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.51,0.153],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-796.934,-100.556],[-796.934,78.292],[-802.465,91.042],[-807.997,78.292],[-807.997,-100.556],[-802.465,-113.306]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-9.113],[0,0],[3.054,-0.079],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-6.802,0.181],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-799.618,-99.861],[-799.618,76.208],[-805.149,88.958],[-810.681,76.208],[-810.681,-99.861],[-805.149,-112.611]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":108.334,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.092],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.24,0.222],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-800.61,-98.819],[-800.61,73.083],[-806.141,85.833],[-811.672,73.083],[-811.672,-98.819],[-806.141,-111.569]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-799.188,-98.125],[-799.188,71],[-804.719,83.75],[-814.636,70.875],[-814.636,-98.25],[-804.719,-110.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":119,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-787.944,-96.125],[-787.944,66.75],[-793.475,79.5],[-804.019,66.875],[-804.019,-96],[-793.475,-108.875]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":124,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-780.109,-96.579],[-780.109,65.77],[-785.64,78.355],[-796.184,65.566],[-796.184,-96.783],[-785.64,-108.836]],"c":true}]},{"t":128,"s":[{"i":[[0,-9.113],[0,0],[3.053,-0.101],[0.562,12.625],[0,0],[-5.719,0]],"o":[[0,0],[0,9.113],[-7.531,0.25],[0,0],[0.062,-12.25],[3.055,0]],"v":[[-779.207,-96.704],[-779.207,65.118],[-784.738,77.54],[-794.029,65.112],[-794.029,-96.71],[-784.738,-108.467]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[53.5,61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":300,"st":60,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"CENTER_LENS","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.013,149.919,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-5.969],[5.969,0],[0,0],[0,5.969],[-5.969,0],[0,0]],"o":[[0,5.969],[0,0],[-5.969,0],[0,-5.969],[0,0],[5.969,0]],"v":[[21.408,0],[10.601,10.808],[-10.601,10.808],[-21.408,0],[-10.601,-10.808],[10.601,-10.808]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62.5,"s":[{"i":[[-0.162,-5.954],[5.954,-0.162],[0,0],[0.162,5.954],[-5.954,0.162],[0,0]],"o":[[0.162,5.954],[0,0],[-5.954,0.162],[-0.162,-5.954],[0,0],[5.954,-0.162]],"v":[[23.471,-4.918],[12.899,6.54],[-8.812,6.806],[-19.793,-3.944],[-9.024,-15.178],[12.5,-15.603]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":64.166,"s":[{"i":[[-0.27,-5.944],[5.944,-0.27],[0,0],[0.27,5.944],[-5.944,0.27],[0,0]],"o":[[0.27,5.944],[0,0],[-5.944,0.27],[-0.27,-5.944],[0,0],[5.944,-0.27]],"v":[[24.429,-9.031],[14.014,2.862],[-8.037,3.305],[-19.132,-7.407],[-8.389,-18.924],[13.349,-19.633]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":66.666,"s":[{"i":[[-0.432,-5.929],[5.929,-0.432],[0,0],[0.432,5.929],[-5.929,0.432],[0,0]],"o":[[0.432,5.929],[0,0],[-5.929,0.432],[-0.432,-5.929],[0,0],[5.929,-0.432]],"v":[[24.667,-16.787],[14.488,-4.243],[-8.074,-3.534],[-19.342,-14.188],[-8.638,-26.132],[13.424,-27.266]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[-0.54,-5.92],[5.92,-0.54],[0,0],[0.54,5.92],[-5.92,0.54],[0,0]],"o":[[0.54,5.92],[0,0],[-5.92,0.54],[-0.54,-5.92],[0,0],[5.92,-0.54]],"v":[[23.575,-22.686],[13.553,-9.709],[-9.348,-8.823],[-20.732,-19.439],[-10.053,-31.666],[12.223,-33.083]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70,"s":[{"i":[[-0.648,-5.91],[5.91,-0.648],[0,0],[0.648,5.91],[-5.91,0.648],[0,0]],"o":[[0.648,5.91],[0,0],[-5.91,0.648],[-0.648,-5.91],[0,0],[5.91,-0.648]],"v":[[20.259,-30.049],[10.394,-16.638],[-13.048,-15.324],[-24.296,-25.801],[-13.644,-38.312],[9.173,-40.114]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":71.666,"s":[{"i":[[-0.756,-5.9],[5.9,-0.756],[0,0],[0.756,5.9],[-5.9,0.756],[0,0]],"o":[[0.756,5.9],[0,0],[-5.9,0.756],[-0.756,-5.9],[0,0],[5.9,-0.756]],"v":[[14.171,-38.307],[4.463,-24.462],[-19.518,-22.721],[-30.632,-33.06],[-20.005,-45.855],[3.351,-48.04]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72.5,"s":[{"i":[[-0.81,-5.895],[5.895,-0.81],[0,0],[0.81,5.895],[-5.895,0.81],[0,0]],"o":[[0.81,5.895],[0,0],[-5.895,0.81],[-0.81,-5.895],[0,0],[5.895,-0.81]],"v":[[9.346,-43.279],[-0.283,-29.218],[-24.535,-27.263],[-35.581,-37.533],[-24.967,-50.47],[-1.34,-52.846]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[{"i":[[-0.864,-5.89],[5.89,-0.864],[0,0],[0.864,5.89],[-5.89,0.864],[0,0]],"o":[[0.864,5.89],[0,0],[-5.89,0.864],[-0.864,-5.89],[0,0],[5.89,-0.864]],"v":[[3.001,-48.298],[-6.55,-34.019],[-30.497,-31.851],[-41.476,-42.052],[-30.875,-55.131],[-7.553,-57.699]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74.166,"s":[{"i":[[-0.918,-5.885],[5.885,-0.918],[0,0],[0.918,5.885],[-5.885,0.918],[0,0]],"o":[[0.918,5.885],[0,0],[-5.885,0.918],[-0.918,-5.885],[0,0],[5.885,-0.918]],"v":[[-4.97,-53.817],[-14.443,-39.321],[-38.084,-36.939],[-48.996,-47.071],[-38.408,-60.292],[-15.391,-63.052]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[-0.972,-5.88],[5.88,-0.972],[0,0],[0.972,5.88],[-5.88,0.972],[0,0]],"o":[[0.972,5.88],[0,0],[-5.88,0.972],[-0.972,-5.88],[0,0],[5.88,-0.972]],"v":[[-14.941,-59.46],[-24.335,-44.748],[-47.671,-42.152],[-58.515,-52.215],[-47.94,-65.577],[-25.229,-68.529]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[-1.08,-5.87],[5.87,-1.08],[0,0],[1.08,5.87],[-5.87,1.08],[0,0]],"o":[[1.08,5.87],[0,0],[-5.87,1.08],[-1.08,-5.87],[0,0],[5.87,-1.08]],"v":[[-42.382,-72.123],[-51.619,-56.976],[-74.346,-53.953],[-85.055,-63.877],[-74.506,-77.524],[-52.404,-80.859]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":77.5,"s":[{"i":[[-0.856,-5.865],[5.839,-1.205],[0,0],[0.985,5.907],[-5.839,1.205],[0,0]],"o":[[0.855,5.886],[0,0],[-5.839,1.205],[-0.983,-5.883],[0,0],[5.839,-1.205]],"v":[[-61.785,-78.763],[-70.703,-63.449],[-91.979,-60.128],[-102.22,-70.048],[-92,-83.986],[-71.252,-87.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78.334,"s":[{"i":[[-0.632,-5.86],[5.807,-1.33],[0,0],[0.89,5.944],[-5.807,1.33],[0,0]],"o":[[0.63,5.901],[0,0],[-5.807,1.33],[-0.886,-5.896],[0,0],[5.807,-1.33]],"v":[[-84.656,-85.779],[-93.256,-70.297],[-113.08,-66.679],[-122.854,-76.593],[-112.964,-90.823],[-93.568,-94.893]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[-0.408,-5.856],[5.776,-1.455],[0,0],[0.796,5.981],[-5.776,1.455],[0,0]],"o":[[0.406,5.917],[0,0],[-5.776,1.455],[-0.79,-5.909],[0,0],[5.776,-1.455]],"v":[[-112.027,-92.795],[-120.308,-77.146],[-138.681,-73.229],[-147.987,-83.138],[-138.427,-97.659],[-120.384,-102.097]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[-0.184,-5.851],[5.744,-1.58],[0,0],[0.701,6.017],[-5.744,1.58],[0,0]],"o":[[0.181,5.932],[0,0],[-5.744,1.58],[-0.693,-5.922],[0,0],[5.744,-1.58]],"v":[[-144.7,-99.873],[-152.663,-84.056],[-169.585,-79.842],[-178.423,-89.745],[-169.193,-104.558],[-152.502,-109.364]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[0.039,-5.846],[5.713,-1.705],[0,0],[0.606,6.054],[-5.713,1.705],[0,0]],"o":[[-0.044,5.947],[0,0],[-5.713,1.705],[-0.596,-5.935],[0,0],[5.713,-1.705]],"v":[[-181.936,-106.857],[-189.58,-90.873],[-205.051,-86.361],[-213.421,-96.259],[-204.521,-111.364],[-189.183,-116.536]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0.263,-5.841],[5.681,-1.83],[0,0],[0.511,6.091],[-5.681,1.83],[0,0]],"o":[[-0.269,5.963],[0,0],[-5.681,1.83],[-0.499,-5.948],[0,0],[5.682,-1.83]],"v":[[-225.421,-113.467],[-232.747,-97.315],[-246.767,-92.505],[-254.67,-102.398],[-246.098,-117.794],[-232.114,-123.334]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[0.201,-5.842],[4.849,-1.973],[0,0],[0.428,5.773],[-4.511,1.767],[0,0]],"o":[[-0.205,5.947],[0,0],[-4.849,1.973],[-0.429,-5.935],[0,0],[4.849,-1.973]],"v":[[-275.671,-118.903],[-281.694,-102.971],[-292.741,-98.418],[-299.149,-108.831],[-292.426,-123.38],[-281.329,-128.511]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0.138,-5.843],[4.017,-2.117],[0,0],[0.345,5.456],[-3.34,1.705],[0,0]],"o":[[-0.141,5.931],[0,0],[-4.017,2.117],[-0.359,-5.922],[0,0],[4.017,-2.117]],"v":[[-331.129,-123.089],[-335.849,-107.376],[-343.923,-103.082],[-348.837,-114.013],[-343.962,-127.716],[-335.753,-132.438]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0.075,-5.844],[3.184,-2.261],[0,0],[0.262,5.138],[-2.169,1.643],[0,0]],"o":[[-0.077,5.915],[0,0],[-3.184,2.261],[-0.289,-5.909],[0,0],[4.042,-3.442]],"v":[[-389.712,-125.963],[-393.129,-110.469],[-398.605,-106.433],[-402.024,-117.883],[-398.998,-130.74],[-393.301,-136.302]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0.012,-5.845],[2.352,-2.405],[0,0],[0.179,4.821],[-0.999,1.58],[0,0]],"o":[[-0.012,5.899],[0,0],[-2.352,2.405],[-0.219,-5.895],[0,0],[4.066,-4.767]],"v":[[-451.421,-127.712],[-453.534,-112.437],[-455.663,-108.66],[-457.587,-120.628],[-456.41,-132.638],[-453.975,-136.541]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0.012,-5.845],[0.626,-2.62],[0,0],[0.179,4.821],[-0.999,1.58],[0,0]],"o":[[-0.012,5.899],[0,0],[-1.245,-2.898],[-0.219,-5.895],[0,0],[0.566,-0.017]],"v":[[-512.671,-125.712],[-513.534,-115.437],[-514.163,-115.66],[-514.337,-122.878],[-513.66,-133.888],[-512.975,-134.041]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[509.408,-610.192],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":87,"st":60,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"FRONT_LENS 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[-1.125,-0.688],[0,-10.77],[3.375,0.312],[0,10.77]],"o":[[2.027,1.239],[0,10.77],[-1.122,-0.104],[0,-10.77]],"v":[[-333.875,52.938],[-332.25,68.688],[-333.875,88.188],[-335.5,68.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[-1.661,-0.597],[0,-10.77],[3.518,0.277],[0,10.77]],"o":[[2.541,1.071],[0,10.77],[-1.622,-0.098],[0,-10.77]],"v":[[-304.741,51.121],[-301.683,67.085],[-304.277,86.335],[-307.339,67.121]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[-2.197,-0.507],[0,-10.77],[3.661,0.241],[0,10.77]],"o":[[3.055,0.903],[0,10.77],[-2.123,-0.093],[0,-10.77]],"v":[[-277.357,49.304],[-272.866,65.482],[-276.429,84.482],[-280.929,65.554]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[-3.27,-0.326],[0,-10.77],[3.946,0.17],[0,10.77]],"o":[[4.083,0.567],[0,10.77],[-3.124,-0.082],[0,-10.77]],"v":[[-227.089,45.67],[-219.732,62.277],[-225.232,80.777],[-232.607,62.42]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[-3.806,-0.235],[0,-10.77],[4.089,0.134],[0,10.77]],"o":[[4.597,0.399],[0,10.77],[-3.624,-0.077],[0,-10.77]],"v":[[-205.132,43.467],[-196.561,60.289],[-202.811,78.539],[-211.478,60.467]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[-4.342,-0.145],[0,-10.77],[4.232,0.098],[0,10.77]],"o":[[5.111,0.231],[0,10.77],[-4.125,-0.071],[0,-10.77]],"v":[[-185.301,41.265],[-175.515,58.301],[-182.515,76.301],[-192.473,58.515]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[-4.878,-0.054],[0,-10.77],[4.375,0.062],[0,10.77]],"o":[[5.625,0.062],[0,10.77],[-4.625,-0.066],[0,-10.77]],"v":[[-167.125,38.688],[-156.125,55.938],[-163.875,73.688],[-175.125,56.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[-5.277,0],[-0.118,-10.643],[4.875,0.012],[-0.062,10.649]],"o":[[5.85,0.012],[0.088,10.399],[-5.238,-0.009],[0.07,-10.767]],"v":[[-150.531,36.3],[-139.006,53.575],[-147.306,71.35],[-159.156,53.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[-5.675,0.055],[-0.236,-10.516],[5.375,-0.037],[-0.125,10.528]],"o":[[6.075,-0.038],[0.175,10.028],[-5.852,0.048],[0.14,-10.765]],"v":[[-135.188,33.788],[-123.137,51.088],[-131.988,68.887],[-144.438,51.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[-6.073,0.11],[-0.353,-10.39],[5.875,-0.087],[-0.188,10.407]],"o":[[6.3,-0.087],[0.262,9.657],[-6.465,0.104],[0.211,-10.763]],"v":[[-121.771,31.306],[-109.196,48.631],[-118.596,66.456],[-131.646,48.656]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[-6.472,0.164],[-0.471,-10.263],[6.375,-0.138],[-0.25,10.287]],"o":[[6.525,-0.137],[0.35,9.287],[-7.078,0.161],[0.281,-10.76]],"v":[[-109.104,28.825],[-96.004,46.175],[-105.954,64.025],[-119.604,46.125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[-6.87,0.219],[-0.589,-10.137],[6.875,-0.188],[-0.312,10.166]],"o":[[6.75,-0.188],[0.438,8.916],[-7.691,0.218],[0.351,-10.758]],"v":[[-97.75,26.438],[-84.125,43.812],[-94.625,61.688],[-108.875,43.688]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98.334,"s":[{"i":[[-7.268,0.274],[-0.706,-10.01],[7.375,-0.238],[-0.375,10.045]],"o":[[6.975,-0.238],[0.525,8.545],[-8.305,0.275],[0.421,-10.756]],"v":[[-87.767,24.188],[-73.617,41.588],[-84.667,59.488],[-99.517,41.387]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[-8.065,0.383],[-0.942,-9.757],[8.375,-0.338],[-0.5,9.804]],"o":[[7.425,-0.337],[0.7,7.804],[-9.531,0.388],[0.562,-10.751]],"v":[[-70.425,19.688],[-55.225,37.137],[-67.375,55.088],[-83.425,36.788]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[-8.862,0.492],[-1.177,-9.504],[9.375,-0.438],[-0.625,9.562]],"o":[[7.875,-0.438],[0.875,7.062],[-10.758,0.502],[0.702,-10.747]],"v":[[-56.375,15.188],[-40.125,32.688],[-53.375,50.688],[-70.625,32.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[-9.071,0.394],[-0.942,-9.584],[9.481,-0.35],[-0.5,9.631]],"o":[[8.281,-0.35],[0.7,7.631],[-10.588,0.402],[0.562,-10.579]],"v":[[-45.213,11.238],[-28.625,28.887],[-42.775,47.012],[-60.2,28.488]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[-9.28,0.295],[-0.706,-9.665],[9.588,-0.262],[-0.375,9.7]],"o":[[8.688,-0.262],[0.525,8.2],[-10.417,0.301],[0.421,-10.411]],"v":[[-36.05,7.496],[-19.125,25.296],[-34.175,43.546],[-51.775,24.996]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[-9.384,0.246],[-0.589,-9.705],[9.641,-0.219],[-0.312,9.735]],"o":[[8.891,-0.219],[0.438,8.485],[-10.332,0.251],[0.351,-10.327]],"v":[[-31.875,5.625],[-14.781,23.5],[-30.281,41.812],[-47.969,23.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[-9.593,0.148],[-0.353,-9.786],[9.747,-0.131],[-0.188,9.803]],"o":[[9.297,-0.131],[0.262,9.053],[-10.162,0.151],[0.211,-10.159]],"v":[[-25.337,2.55],[-7.906,20.575],[-24.306,39.012],[-42.169,20.425]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[-9.907,0],[0,-9.907],[9.907,0],[0,9.907]],"o":[[9.907,0],[0,9.907],[-9.907,0],[0,-9.907]],"v":[[-17.125,-2.062],[0.812,16.188],[-16.938,34.812],[-35.062,16.188]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.166,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[-8.781,-9.156],[10.719,10.344],[-8.781,29.844],[-28.281,10.344]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118.334,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[-4.188,-13.375],[15.312,6.125],[-4.188,25.625],[-23.688,6.125]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":122.5,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[-1.562,-16.438],[17.938,3.062],[-1.562,22.562],[-21.062,3.062]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126.666,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[-0.188,-18.25],[19.312,1.25],[-0.188,20.75],[-19.688,1.25]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":130.834,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[0.5,-19.469],[20,0.031],[0.5,19.531],[-19,0.031]],"c":true}]},{"t":135,"s":[{"i":[[-10.77,0],[0,-10.77],[10.77,0],[0,10.77]],"o":[[10.77,0],[0,10.77],[-10.77,0],[0,-10.77]],"v":[[0.688,-20.062],[20.188,-0.562],[0.688,18.938],[-18.812,-0.562]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[385.5,-561.5],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":87,"op":342,"st":60,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"CENTER_SCREEN 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[699,-539],[699,539],[653,585],[-0.999,585],[-653,585],[-699,539],[-699,-539],[-653,-585],[1,-585],[653,-585]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":64.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[707,-547],[707,547],[661,593],[-0.999,585],[-639.273,577],[-685.273,531],[-685.273,-527],[-639.273,-573],[1,-585],[661,-593]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[715,-563],[715,567],[669,613],[-0.999,585],[-617.545,561],[-663.545,515],[-663.545,-511],[-617.545,-557],[1,-585],[669,-609]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[709,-577.4],[709,579],[663,625],[-0.999,585],[-587.709,551.4],[-636.709,505.4],[-636.709,-501.4],[-587.709,-547.4],[1,-585],[663,-623.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72.5,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[705,-587],[705,587],[659,633],[-0.999,585],[-567.818,545],[-613.818,499],[-613.818,-495],[-567.818,-541],[1,-585],[659,-633]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[697.4,-593.4],[697.4,595],[651.4,641],[-0.999,585],[-553.873,539.4],[-599.873,493.4],[-599.873,-490.2],[-553.873,-536.2],[1,-585],[651.4,-639.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[693.8,-599.8],[693.8,603],[647.8,649],[-0.999,585],[-537.927,533.8],[-583.927,487.8],[-583.927,-485.4],[-537.927,-531.4],[1,-585],[647.8,-645.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[678.2,-606.2],[678.2,611],[632.2,657],[-0.999,585],[-519.982,528.2],[-565.982,482.2],[-565.982,-480.6],[-519.982,-526.6],[1,-585],[632.2,-652.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[666.6,-612.6],[666.6,619],[620.6,665],[-0.999,585],[-499.036,522.6],[-545.036,476.6],[-545.036,-475.8],[-499.036,-521.8],[1,-585],[620.6,-658.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[647,-619],[647,627],[601,673],[-0.999,585],[-478.091,517],[-524.091,471],[-524.091,-471],[-478.091,-517],[1,-585],[601,-665]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.223,2.5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-22.441,-1.8],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[600.891,-638.2],[600.891,649.545],[561.618,691.182],[-5.908,586.273],[-428.856,507],[-467.174,466.273],[-467.174,-463],[-420.674,-508.5],[1,-585.6],[554.891,-684.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.132,3.75],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-20.96,-2.7],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[561.836,-647.8],[561.836,660.818],[525.927,700.273],[-8.363,586.909],[-398.739,502],[-433.216,463.909],[-433.216,-459],[-386.466,-504.25],[1,-585.9],[515.836,-693.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.041,5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-19.478,-3.6],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[522.782,-657.4],[522.782,672.091],[490.236,709.364],[-10.817,587.546],[-368.621,497],[-399.258,461.546],[-399.258,-455],[-352.258,-500],[1,-586.2],[476.782,-703.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-24.95,6.25],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-17.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[471.727,-667],[471.727,683.364],[442.545,718.455],[-13.272,588.182],[-332.504,492],[-359.3,459.182],[-359.3,-451],[-312.05,-495.75],[1,-586.5],[425.727,-713]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0.129,-24.588],[0,0],[21.663,1.508],[0,0],[0,0],[0.008,23.224],[0,0],[-21.2,5.875],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-15.329,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[21.8,-2.083]],"v":[[412.352,-679.333],[412.352,694.197],[387.295,726.538],[-16.188,588.015],[-289.754,488.25],[-312.675,457.182],[-312.675,-449],[-272.55,-491.375],[-4.583,-587],[372.894,-720.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[0.258,-23.77],[0,0],[17.922,3.015],[0,0],[0,0],[0.017,21.043],[0,0],[-17.45,5.5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-12.663,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[18.194,-4.167]],"v":[[344.977,-691.667],[344.977,705.03],[324.045,734.621],[-19.105,587.849],[-247.004,484.5],[-266.05,455.182],[-266.05,-447],[-233.05,-487],[-10.166,-587.5],[312.06,-728.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0.386,-22.953],[0,0],[14.18,4.523],[0,0],[0,0],[0.025,18.862],[0,0],[-13.7,5.125],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-9.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[14.589,-6.25]],"v":[[269.602,-704],[269.602,715.864],[252.795,742.705],[-22.022,587.682],[-204.254,480.75],[-219.425,453.182],[-219.425,-445],[-193.55,-482.625],[-15.75,-588],[243.227,-736]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0.773,-20.5],[0,0],[2.955,9.045],[0,0],[0,0],[0.05,12.318],[0,0],[-2.45,4],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-1.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[3.773,-12.5]],"v":[[13.477,-707],[13.477,713.364],[9.045,731.955],[-30.772,587.182],[-58.004,481.5],[-61.55,459.182],[-61.55,-451],[-57.05,-481.5],[-32.5,-581.5],[6.727,-725]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-3,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":87,"st":60,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Figure 10","tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":72.5,"s":[100]},{"t":80.833984375,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[206.959,124.54,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[206.959,124.54,0],"to":[-1.125,0,0],"ti":[1.125,0,0]},{"t":85.833984375,"s":[200.209,124.54,0]}],"ix":2,"l":2},"a":{"a":0,"k":[270.209,145.54,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.55,0.55,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0,0,-0.47]},"t":60,"s":[125,125,100]},{"t":110,"s":[125,125,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,0],[-1.939,-1.387],[6.061,-1.3],[0.907,1.308]],"o":[[1.066,0.711],[2.423,1.734],[-4.85,1.04],[0,0]],"v":[[-0.582,-6.237],[5.035,-2.37],[2.01,5.979],[-6.77,3.354]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[0,0],[-1.877,-1.382],[5.87,-1.295],[0.878,1.303]],"o":[[1.032,0.708],[2.346,1.727],[-4.697,1.036],[0,0]],"v":[[-0.131,-5.771],[5.309,-1.919],[2.379,6.397],[-6.124,3.782]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,0],[-1.627,-1.365],[5.086,-1.278],[0.761,1.287]],"o":[[0.894,0.699],[2.033,1.706],[-4.07,1.023],[0,0]],"v":[[1.024,-4.856],[5.738,-1.053],[3.2,7.16],[-4.168,4.578]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0,0],[-0.79,-1.365],[2.613,-0.951],[0.598,1.216]],"o":[[0.434,0.699],[0.987,1.706],[-1.617,0.588],[0,0]],"v":[[-0.98,-5.389],[1.308,-1.586],[-0.339,6.331],[-4.212,3.985]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0,0],[-0.387,-1.365],[1.28,-0.951],[0.293,1.216]],"o":[[0.213,0.699],[0.483,1.706],[-0.792,0.588],[0,0]],"v":[[-1.492,-5.389],[-0.371,-1.586],[-1.178,6.331],[-3.075,3.985]],"c":false}]},{"t":85.833984375,"s":[{"i":[[0,0],[-0.123,-1.365],[0.408,-0.951],[0.093,1.216]],"o":[[0.068,0.699],[0.154,1.706],[-0.253,0.588],[0,0]],"v":[[-2,-5.389],[-1.642,-1.586],[-1.9,6.331],[-2.505,3.985]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[272.026,152.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Nose","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[-3.926,7.277],[-8.848,0],[-3.783,2.669],[18.309,-0.059],[0.81,-15.17],[-4.916,0]],"o":[[3.926,7.277],[4.982,0],[-0.845,-15.213],[-18.267,0.059],[3.755,2.604],[8.848,0]],"v":[[-0.106,3.616],[20.359,15.839],[33.729,11.589],[-0.12,-15.891],[-33.793,11.7],[-20.571,15.839]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[-3.803,7.248],[-8.57,0],[-3.664,2.658],[17.733,-0.059],[0.785,-15.11],[-4.761,0]],"o":[[3.803,7.248],[4.825,0],[-0.819,-15.153],[-17.692,0.058],[3.637,2.594],[8.57,0]],"v":[[0.379,4.215],[20.2,16.39],[33.149,12.156],[0.365,-15.216],[-32.248,12.267],[-19.442,16.39]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[-3.295,7.158],[-7.426,0],[-3.175,2.625],[15.365,-0.058],[0.472,-17.15],[-4.125,0]],"o":[[3.295,7.158],[4.181,0],[-0.823,-14.189],[-15.33,0.058],[3.151,2.562],[7.426,0]],"v":[[-0.465,5.074],[17.661,15.91],[29.594,11.253],[1.662,-15.066],[-26.597,13.501],[-16.213,17.098]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[-1.951,7.158],[-4.397,0],[-1.88,2.625],[9.099,-0.058],[0.279,-17.15],[-2.443,0]],"o":[[1.951,7.158],[2.476,0],[-0.487,-14.189],[-9.078,0.058],[1.866,2.562],[4.397,0]],"v":[[-0.259,5.074],[10.475,15.91],[17.542,11.253],[1.001,-15.066],[-15.734,13.501],[-9.585,17.098]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[-0.956,7.158],[-2.154,0],[-0.921,2.625],[4.456,-0.058],[0.137,-17.15],[-1.196,0]],"o":[[0.956,7.158],[1.213,0],[-0.239,-14.189],[-4.446,0.058],[0.914,2.562],[2.154,0]],"v":[[-0.818,5.074],[4.203,15.91],[8.137,11.253],[0.036,-15.066],[-7.924,13.501],[-5.622,16.388]],"c":true}]},{"t":85.833984375,"s":[{"i":[[-0.305,7.158],[-0.687,0],[-0.294,2.625],[1.422,-0.058],[0.044,-17.15],[-0.382,0]],"o":[[0.305,7.158],[0.387,0],[-0.076,-14.189],[-1.419,0.058],[0.292,2.562],[0.687,0]],"v":[[-0.725,5.074],[0.877,15.91],[2.132,11.253],[-0.453,-15.066],[-2.992,13.501],[-2.258,16.388]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,9.805],[9.805,0],[0,-9.805],[-9.805,0]],"o":[[0,-9.805],[-9.805,0],[0,9.805],[9.805,0]],"v":[[-6.59,-22.526],[-24.345,-40.281],[-42.099,-22.526],[-24.345,-4.772]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[0,9.767],[9.497,0],[0,-9.767],[-9.497,0]],"o":[[0,-9.767],[-9.497,0],[0,9.767],[9.497,0]],"v":[[-5.901,-21.825],[-23.097,-39.51],[-40.292,-21.825],[-23.097,-4.14]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,9.646],[7.896,0],[0,-9.646],[-7.896,0]],"o":[[0,-9.646],[-7.896,0],[0,9.646],[7.896,0]],"v":[[-4.974,-20.167],[-18.558,-37.632],[-33.567,-20.167],[-19.984,-2.94]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0,9.646],[4.638,0],[0,-9.646],[-4.639,0]],"o":[[0,-9.646],[-4.638,0],[0,9.646],[4.639,0]],"v":[[-2.828,-18.982],[-10.807,-36.448],[-19.625,-18.982],[-11.645,-1.755]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0,9.435],[2.13,0],[0,-9.435],[-2.131,0]],"o":[[0,-9.435],[-2.13,0],[0,9.435],[2.131,0]],"v":[[-2.351,-18.418],[-6.016,-35.501],[-10.066,-18.418],[-6.401,-1.568]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0,9.435],[0.68,0],[0,-9.435],[-0.68,0]],"o":[[0,-9.435],[-0.68,0],[0,9.435],[0.68,0]],"v":[[-1.214,-18.418],[-2.384,-35.501],[-3.676,-18.418],[-2.506,-1.568]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.23137255013,0.129411771894,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.47,108.276],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Hair","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[-7.446,13.962],[0,0],[0,0],[-0.313,2.62],[0.015,4.351],[0,0],[-18.83,0.06],[-0.051,-15.806],[0,0],[-0.49,-2.669],[-1.873,-4.352],[-0.89,-3.988],[0,-4.307],[8.014,-5.508],[12.335,-0.04],[8.035,5.309],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.222,-4.479],[0.309,-2.598],[0,0],[-0.051,-15.806],[18.83,-0.06],[0,0],[0.013,4.276],[0.495,2.702],[3.604,8.387],[0.884,3.962],[0,7.459],[-7.997,5.495],[-12.35,0.04],[-8.04,-5.313],[0,0],[0,-6.072]],"v":[[-36.861,-4.598],[-36.804,-4.703],[-36.772,-4.819],[-34.61,-14.535],[-34.324,-24.06],[-34.324,-24.128],[-0.614,-53.129],[33.278,-24.345],[33.278,-24.252],[33.789,-14.641],[37.134,-4.922],[43.41,12.489],[44.307,23.718],[31.53,43.997],[0.092,53.129],[-31.449,44.589],[-44.307,24.009],[-44.307,23.977]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[-7.211,13.907],[0,0],[0,0],[-0.301,2.61],[0.014,4.334],[0,0],[-18.237,0.06],[-0.049,-15.744],[0,0],[-0.473,-2.659],[-1.812,-4.336],[-0.861,-3.972],[0,-4.29],[7.763,-5.486],[11.947,-0.04],[7.782,5.289],[0,7.963],[0,0]],"o":[[0,0],[0,0],[1.183,-4.461],[0.299,-2.588],[0,0],[-0.049,-15.745],[18.237,-0.06],[0,0],[0.012,4.259],[0.479,2.691],[3.491,8.354],[0.856,3.947],[0,7.43],[-7.746,5.474],[-11.961,0.04],[-7.787,-5.292],[0,0],[0,-6.048]],"v":[[-35.236,-4.113],[-35.18,-4.218],[-35.15,-4.333],[-33.055,-14.011],[-32.779,-23.499],[-32.779,-23.567],[-0.13,-52.454],[32.696,-23.783],[32.696,-23.69],[33.191,-14.117],[36.43,-4.435],[42.509,12.908],[43.377,24.093],[31.002,44.292],[0.554,53.389],[-29.994,44.882],[-42.447,24.383],[-42.447,24.35]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[-6.248,13.734],[0,0],[0,0],[-0.261,2.577],[0.012,4.28],[0,0],[-15.802,0.059],[-0.043,-15.549],[0,0],[-0.41,-2.626],[-1.57,-4.282],[-0.746,-3.923],[0,-4.237],[6.726,-5.417],[10.352,-0.039],[6.743,5.223],[0,7.864],[0,0]],"o":[[0,0],[0,0],[1.025,-4.406],[0.259,-2.556],[0,0],[-0.237,-16.662],[15.802,-0.059],[0,0],[0.011,4.206],[0.415,2.658],[3.025,8.25],[0.742,3.898],[0,7.337],[-6.712,5.406],[-10.364,0.039],[-6.747,-5.226],[0,0],[0,-5.973]],"v":[[-29.256,-3.138],[-29.208,-3.242],[-29.181,-3.355],[-27.366,-12.913],[-27.127,-22.283],[-27.127,-22.35],[1.163,-52.304],[29.606,-22.564],[29.606,-22.471],[30.035,-13.018],[32.842,-3.456],[38.109,13.671],[38.861,24.717],[28.139,44.665],[2.706,53.173],[-23.764,44.772],[-34.554,24.528],[-34.554,24.496]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[-3.7,13.734],[0,0],[0,0],[-0.155,2.577],[0.007,4.28],[0,0],[-9.358,0.059],[-0.025,-15.549],[0,0],[-0.243,-2.626],[-0.93,-4.282],[-0.442,-3.923],[0,-4.237],[3.983,-5.417],[6.13,-0.039],[3.993,5.223],[0,7.864],[0,0]],"o":[[0,0],[0,0],[0.607,-4.406],[0.153,-2.556],[0,0],[-0.14,-16.662],[9.358,-0.059],[0,0],[0.006,4.206],[0.246,2.658],[1.791,8.25],[0.439,3.898],[0,7.337],[-3.975,5.406],[-6.138,0.039],[-3.996,-5.226],[0,0],[0,-5.973]],"v":[[-17.523,-3.138],[-17.495,-3.242],[-17.479,-3.355],[-16.405,-12.913],[-16.263,-22.283],[-16.263,-22.35],[0.491,-52.304],[17.334,-22.564],[17.334,-22.471],[17.588,-13.018],[19.251,-3.456],[22.37,13.671],[22.815,24.717],[16.465,44.665],[1.404,53.173],[-14.271,44.772],[-20.661,24.528],[-20.661,24.496]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[-1.812,13.734],[0,0],[0,0],[-0.076,2.577],[0.004,4.28],[0,0],[-4.583,0.059],[-0.012,-15.549],[0,0],[-0.119,-2.626],[-0.455,-4.282],[-0.216,-3.923],[0,-4.237],[1.951,-5.417],[3.002,-0.039],[1.956,5.223],[0,7.864],[0,0]],"o":[[0,0],[0,0],[0.297,-4.406],[0.075,-2.556],[0,0],[-0.069,-16.662],[4.583,-0.059],[0,0],[0.003,4.206],[0.12,2.658],[0.877,8.25],[0.215,3.898],[0,7.337],[-1.947,5.406],[-3.006,0.039],[-1.957,-5.226],[0,0],[0,-5.973]],"v":[[-9.069,-3.138],[-9.055,-3.242],[-9.047,-3.355],[-8.521,-12.913],[-8.451,-22.283],[-8.451,-22.35],[-0.482,-52.304],[8.004,-22.564],[8.004,-22.471],[8.128,-13.018],[8.469,-3.22],[9.997,13.434],[10.215,24.48],[7.578,44.665],[0.202,53.173],[-7.476,44.772],[-10.605,24.528],[-10.605,24.496]],"c":true}]},{"t":85.833984375,"s":[{"i":[[-0.578,13.734],[0,0],[0,0],[-0.024,2.577],[0.001,4.28],[0,0],[-1.462,0.059],[-0.004,-15.549],[0,0],[-0.038,-2.626],[-0.145,-4.282],[-0.069,-3.923],[0,-4.237],[0.622,-5.417],[0.958,-0.039],[0.624,5.223],[0,7.864],[0,0]],"o":[[0,0],[0,0],[0.095,-4.406],[0.024,-2.556],[0,0],[-0.022,-16.662],[1.462,-0.059],[0,0],[0.001,4.206],[0.038,2.658],[0.28,8.25],[0.069,3.898],[0,7.337],[-0.621,5.406],[-0.959,0.039],[-0.624,-5.226],[0,0],[0,-5.973]],"v":[[-3.716,-3.138],[-3.711,-3.242],[-3.709,-3.355],[-3.541,-12.913],[-3.519,-22.283],[-3.519,-22.35],[-0.976,-52.304],[1.731,-22.564],[1.731,-22.471],[1.771,-13.018],[1.88,-3.22],[2.367,13.434],[2.437,24.48],[1.596,44.665],[-0.758,53.173],[-3.207,44.772],[-4.206,24.528],[-4.206,24.496]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[4.598,1.656],[-2.64,7.412],[-4.598,-1.656],[2.64,-7.412]],"o":[[-4.6,-1.657],[2.64,-7.412],[4.6,1.657],[-2.64,7.412]],"v":[[30.635,-0.09],[27.088,-16.51],[40.195,-26.931],[43.742,-10.511]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[4.453,1.649],[-2.557,7.383],[-4.453,-1.649],[2.557,-7.383]],"o":[[-4.455,-1.65],[2.557,-7.383],[4.455,1.65],[-2.557,7.383]],"v":[[30.136,0.377],[26.7,-15.979],[39.395,-26.359],[42.831,-10.003]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[3.958,1.629],[-2.273,7.291],[-3.958,-1.629],[2.273,-7.291]],"o":[[-3.96,-1.63],[2.273,-7.291],[3.96,1.63],[-2.273,7.291]],"v":[[26.809,-1.08],[23.755,-17.233],[35.038,-27.484],[38.092,-11.332]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[2.344,1.629],[-1.346,7.291],[-2.344,-1.629],[1.346,-7.291]],"o":[[-2.345,-1.63],[1.346,-7.291],[2.345,1.63],[-1.346,7.291]],"v":[[15.441,-1.791],[13.633,-17.943],[20.314,-28.195],[22.123,-12.042]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[1.148,1.629],[-0.659,7.291],[-1.148,-1.629],[0.659,-7.291]],"o":[[-1.149,-1.63],[0.659,-7.291],[1.148,1.63],[-0.659,7.291]],"v":[[7.076,-1.791],[6.191,-17.943],[9.463,-28.195],[10.349,-12.042]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0.366,1.629],[-0.21,7.291],[-0.366,-1.629],[0.21,-7.291]],"o":[[-0.366,-1.63],[0.21,-7.291],[0.366,1.63],[-0.21,7.291]],"v":[[1.436,-1.791],[1.153,-17.943],[2.197,-28.195],[2.48,-12.042]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[4.598,-1.656],[2.64,7.412],[-4.598,1.656],[-2.64,-7.412]],"o":[[-4.6,1.657],[-2.64,-7.412],[4.6,-1.657],[2.64,7.412]],"v":[[-32.206,-0.025],[-45.315,-10.446],[-41.768,-26.866],[-28.659,-16.445]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[4.453,-1.65],[2.557,7.383],[-4.453,1.65],[-2.557,-7.383]],"o":[[-4.455,1.651],[-2.557,-7.383],[4.455,-1.651],[2.557,7.383]],"v":[[-30.727,0.442],[-43.424,-9.938],[-39.988,-26.294],[-27.292,-15.913]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[3.859,-1.629],[2.216,7.291],[-3.859,1.629],[-2.216,-7.291]],"o":[[-3.86,1.63],[-2.216,-7.291],[3.86,-1.63],[2.216,7.291]],"v":[[-25.349,1.36],[-36.351,-8.891],[-33.374,-25.043],[-22.372,-14.792]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[2.285,-1.629],[1.312,7.291],[-2.285,1.629],[-1.312,-7.291]],"o":[[-2.286,1.63],[-1.312,-7.291],[2.286,-1.63],[1.312,7.291]],"v":[[-14.973,2.071],[-21.488,-8.18],[-19.725,-24.332],[-13.21,-14.081]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[1.119,-1.629],[0.643,7.291],[-1.119,1.629],[-0.643,-7.291]],"o":[[-1.12,1.63],[-0.643,-7.291],[1.12,-1.63],[0.643,7.291]],"v":[[-7.819,2.071],[-11.01,-8.18],[-10.147,-24.332],[-6.956,-14.081]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0.357,-1.629],[0.205,7.291],[-0.357,1.629],[-0.205,-7.291]],"o":[[-0.357,1.63],[-0.205,-7.291],[0.357,-1.63],[0.205,7.291]],"v":[[-3.317,2.071],[-4.335,-8.18],[-4.06,-24.332],[-3.042,-14.081]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.996,145.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Head","np":4,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[32.75,0],[9.05,-8.723],[0,0],[0,0],[12.963,11.172]],"o":[[-36.75,0],[-9.05,8.723],[0,0],[0,0],[-12.963,-11.172]],"v":[[269.5,203.875],[202.375,231.25],[180.49,265.037],[357.49,265.037],[335.375,229.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[31.944,0],[8.827,-8.723],[0,0],[0,0],[12.644,11.172]],"o":[[-35.846,0],[-8.827,8.723],[0,0],[0,0],[-12.644,-11.172]],"v":[[269.549,203.875],[204.076,231.25],[186.694,262.646],[356.307,266.949],[333.803,229.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[29.964,0.368],[8.765,-9.559],[0,0],[0,0],[10.827,12.493]],"o":[[-28.262,-0.347],[-8.765,9.559],[0,0],[0,0],[-10.827,-12.493]],"v":[[266.904,204.072],[217.226,226.01],[201.569,257.67],[350.704,277.632],[328.366,234.753]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[17.745,0.368],[4.241,-8.325],[0,0],[0,0],[6.509,11.788]],"o":[[-16.737,-0.347],[-4.241,8.325],[0,0],[0,0],[-6.509,-11.788]],"v":[[266.953,203.361],[239.192,224.352],[231.398,251.757],[320.169,284.732],[304.709,236.885]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[8.691,0.368],[2.251,-8.436],[0,0],[0,0],[2.817,13.796]],"o":[[-8.197,-0.347],[-2.251,8.436],[0,0],[0,0],[-2.817,-13.796]],"v":[[268.056,203.598],[254.994,222.223],[251.276,250.581],[295.322,287.805],[287.494,239.724]],"c":true}]},{"t":85.833984375,"s":[{"i":[[2.773,0.368],[0.492,-8.596],[0,0],[0,0],[0.699,12.45]],"o":[[-2.615,-0.347],[-0.492,8.596],[0,0],[0,0],[-0.699,-12.45]],"v":[[269.236,203.598],[265.068,222.223],[263.435,250.823],[278.044,286.855],[275.437,239.724]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.105865478516,0.450958251953,0.901947021484,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Body","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[403.855,266.954],[134.263,267.281],[133.746,34.114],[403.983,33.534]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[407.68,272.93],[141.435,262.261],[141.874,38.656],[408.046,28.992]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72.5,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[405.196,278.275],[150.215,255.604],[150.652,44.48],[407.113,22.696]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[395.085,285.526],[168.051,250.854],[169.441,49.35],[394.738,15.446]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[372.271,290.107],[194.58,245.643],[195.101,57.011],[373.426,8.258]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[351.971,291.685],[212.112,242.326],[211.844,59.063],[352.098,8.576]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[310.1,293.583],[241.912,240.199],[241.881,60.48],[309.976,6.207]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[279.372,300.675],[263.178,242.092],[263.608,59.062],[278.826,1.479]],"c":true}]}],"ix":2},"nm":"Mask","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.815673828125,0.88232421875,0.980377197266,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Background","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":87,"st":60,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"CAMERA_CASING 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0,0],[0,13.689],[2.562,0.203],[0,0],[0.235,-13.941],[0,0],[-0.817,-3.47],[0,3.644],[0,21.647],[0,11.447]],"o":[[0,0],[0,-11.515],[-0.278,-0.022],[0,0],[-0.157,9.303],[0,0],[3.866,-2.97],[0,-3.644],[0,-5.657],[0,-17.18]],"v":[[355.812,-582.217],[355.812,-651.939],[349.438,-666.703],[349.561,-458.372],[349.68,-455.309],[349.716,-452.543],[349.634,-442.155],[355.812,-452.231],[355.812,-527.897],[355.812,-557.197]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84,"s":[{"i":[[0,0],[0.181,13.689],[3.692,-3.049],[0,0],[0.235,-13.941],[0,0],[-0.817,-3.47],[0.115,3.644],[0.08,21.647],[0.011,11.447]],"o":[[0,0],[-0.152,-11.515],[-0.215,0.151],[0,0],[-0.157,9.303],[0,0],[3.866,-2.97],[-0.115,-3.644],[-0.021,-5.657],[-0.017,-17.18]],"v":[[291.635,-587.821],[292.523,-742.756],[283.027,-757.519],[282.695,-373.749],[282.814,-370.686],[282.85,-362.418],[282.768,-352.029],[291.612,-362.105],[291.605,-533.5],[291.592,-562.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[0,0],[0.355,13.689],[6.542,-0.922],[0,0],[0.37,-13.941],[0,0],[0.057,-3.845],[-0.362,3.644],[-0.253,21.647],[-0.035,11.447]],"o":[[0,0],[-0.298,-11.515],[-0.366,0.052],[0,0],[-0.247,9.303],[0,0],[5.807,-4.595],[0.362,-3.644],[0.066,-5.657],[0.053,-17.18]],"v":[[193.824,-593.342],[194.689,-728.224],[178.533,-742.988],[177.933,-357.043],[178.12,-353.042],[178.176,-343.402],[177.975,-332.388],[193.487,-347.215],[193.916,-523.397],[193.959,-552.697]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86,"s":[{"i":[[0,0],[0.484,13.689],[8.523,-3.859],[0,0],[0.505,-13.941],[0,0],[-1.753,-3.47],[-0.867,3.644],[-0.607,21.647],[-0.085,11.447]],"o":[[0,0],[-0.407,-11.515],[-0.429,0.194],[0,0],[-0.337,9.303],[0,0],[5.997,-7.47],[0.867,-3.644],[0.159,-5.657],[0.128,-17.18]],"v":[[75.679,-597.849],[75.758,-718.949],[53.719,-733.713],[53.693,-344.334],[53.947,-321.896],[54.024,-312.256],[53.705,-300.617],[75.218,-335.193],[75.9,-512.279],[76.004,-541.578]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87,"s":[{"i":[[0,0],[3.485,11.583],[8.955,-4.433],[-0.062,-3.091],[-3.221,-11.86],[0,0],[-2.544,-3.333],[-1.095,5.54],[-0.607,21.647],[3.44,10.582]],"o":[[0,0],[-3.366,-10.6],[-0.589,2.321],[0.062,3.09],[2.943,8.704],[0,0],[8.347,0.703],[0.794,-8.444],[0.159,-5.657],[-3.981,-16.052]],"v":[[0.007,-686.694],[-13.977,-729.743],[-42.282,-733.704],[-42.419,-351.824],[-35.506,-318.32],[-18.172,-282.143],[-17.207,-281.536],[4.303,-291.511],[7.882,-626.94],[5.009,-672.742]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88,"s":[{"i":[[0,0],[7.233,7.337],[10.246,-6.152],[-0.246,-12.344],[-9.136,-8.623],[0,0],[-4.913,-2.921],[-1.776,11.215],[-0.607,21.647],[9.871,10.62]],"o":[[0,0],[-7.601,-8.337],[-1.067,8.69],[0.246,12.344],[9.086,7.021],[0,0],[8.647,1.223],[0.576,-22.816],[0.159,-5.657],[-9.656,-13.055]],"v":[[-96.036,-712.675],[-118.855,-734.697],[-147.972,-735.599],[-146.863,-351.098],[-130.294,-314.045],[-110.979,-299.591],[-90.581,-288.487],[-69.43,-302.648],[-68.325,-642.738],[-74.855,-686.091]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[9.484,3.793],[8.601,-12.274],[-0.441,-20.809],[-28.549,-9.001],[0,0],[-12.63,-1.571],[-1.485,15.967],[0.068,21.914],[19.53,9.541]],"o":[[0,0],[-23.711,-9.556],[-2.126,56.648],[0.441,20.809],[21.714,6.2],[0,0],[16.655,-5.885],[0.585,-24.671],[-0.31,-11.754],[-24.908,-11.845]],"v":[[-256.274,-730.569],[-286.913,-744.674],[-328.463,-731.93],[-328.345,-350.477],[-292.838,-292.848],[-262.739,-284.553],[-227.494,-275.913],[-199.734,-301.739],[-198.453,-680.107],[-223.793,-715.645]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93,"s":[{"i":[[0,0],[10.869,1.69],[0.025,-8.377],[-0.642,-28.87],[-23.311,-3.439],[0,0],[-22.891,-2.452],[-0.707,20.252],[1.081,22.315],[30.895,7.44]],"o":[[0,0],[-26.095,-4.058],[-0.004,1.43],[0.642,28.87],[18.067,2.665],[0,0],[13.227,-9.056],[0.707,-20.252],[-1.012,-20.899],[-21.169,-6.833]],"v":[[-441.081,-726.063],[-476.791,-733.581],[-512.894,-713.271],[-514.67,-343.981],[-483.267,-295.903],[-442.821,-290.271],[-385.72,-282.768],[-366.552,-319.504],[-367.271,-675.98],[-402.702,-717.321]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,0],[10.926,1.148],[0.925,-11.98],[-0.642,-28.87],[-25.802,-3.644],[0,0],[-22.916,-2.187],[-0.707,20.252],[1.081,22.315],[31.032,6.862]],"o":[[0,0],[-23.328,-2.596],[-0.085,1.425],[0.642,28.87],[22.11,3.111],[0,0],[17.386,-3.626],[0.707,-20.252],[-1.012,-20.899],[-22.091,-5.737]],"v":[[-499.893,-697.032],[-539.989,-704.551],[-576.438,-678.34],[-576.108,-326.385],[-541.208,-279.351],[-496.322,-272.988],[-445.018,-267.521],[-419.062,-304.309],[-419.608,-647.001],[-459.425,-688.969]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.293,-3.849],[0,0],[-22.941,-1.921],[-0.707,20.252],[1.081,22.315],[31.169,6.285]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[26.153,3.558],[0,0],[21.546,1.805],[0.707,-20.252],[-1.012,-20.899],[-23.012,-4.64]],"v":[[-551.186,-680.532],[-595.667,-688.051],[-632.464,-655.94],[-635.041,-321.32],[-596.641,-275.331],[-547.318,-268.237],[-501.809,-264.806],[-469.065,-301.646],[-464.426,-630.554],[-508.629,-673.148]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.293,-3.849],[0,0],[-22.942,-1.921],[-0.707,20.252],[1.081,22.315],[31.169,6.285]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[26.153,3.558],[0,0],[21.546,1.805],[0.707,-20.252],[-1.012,-20.899],[-23.012,-4.64]],"v":[[-580.634,-669.881],[-625.743,-675.52],[-662.539,-643.409],[-665.116,-312.548],[-626.717,-266.559],[-578.646,-260.091],[-531.884,-256.034],[-499.14,-292.875],[-493.875,-620.529],[-536.825,-663.123]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.293,-3.849],[0,0],[-22.941,-1.921],[-0.707,20.252],[1.081,22.315],[31.169,6.285]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[26.153,3.558],[0,0],[21.546,1.805],[0.707,-20.252],[-1.012,-20.899],[-23.012,-4.64]],"v":[[-607.577,-656.723],[-648.299,-660.483],[-685.096,-628.371],[-687.672,-308.789],[-649.273,-262.799],[-602.456,-256.958],[-554.441,-252.274],[-521.697,-289.115],[-523.323,-607.997],[-565.02,-650.592]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.293,-3.849],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[26.153,3.558],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-621.361,-629.154],[-663.337,-631.66],[-700.133,-599.549],[-700.203,-298.764],[-661.804,-252.774],[-612.481,-248.187],[-565.719,-246.009],[-535.481,-286.609],[-538.361,-582.935],[-580.058,-625.529]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.293,-3.849],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[26.153,3.558],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-620.108,-617.876],[-663.337,-619.129],[-700.133,-587.018],[-702.71,-292.498],[-664.311,-246.509],[-614.987,-244.427],[-570.731,-243.502],[-537.987,-280.343],[-535.855,-572.91],[-577.551,-615.504]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.457,-2.338],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[28.045,2.304],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-620.108,-605.344],[-663.337,-605.345],[-700.133,-573.233],[-699.589,-281.22],[-661.19,-235.231],[-614.372,-231.896],[-570.117,-230.971],[-537.373,-267.812],[-542.12,-561.631],[-576.298,-602.973]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.524,-1.302],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[23.032,1.051],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-615.095,-592.813],[-658.324,-592.813],[-695.121,-560.702],[-694.577,-276.207],[-656.177,-230.218],[-610.613,-229.39],[-568.864,-229.718],[-536.12,-266.559],[-535.855,-549.1],[-572.539,-591.695]],"c":true}]},{"t":126,"s":[{"i":[[0,0],[10.983,0.606],[1.825,-15.582],[-0.642,-28.87],[-28.524,-1.302],[0,0],[-21.06,0.551],[-0.707,20.252],[1.081,22.315],[29.62,2.879]],"o":[[0,0],[-20.561,-1.134],[-0.166,1.42],[0.642,28.87],[23.032,1.051],[0,0],[21.614,-0.566],[0.707,-20.252],[-1.012,-20.899],[-23.365,-2.271]],"v":[[-605.07,-581.535],[-648.299,-581.535],[-685.096,-549.424],[-685.805,-263.676],[-647.406,-217.687],[-601.841,-216.858],[-560.092,-217.187],[-527.348,-259.04],[-528.336,-541.582],[-562.514,-580.417]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.235294118524,0.250980407,0.262745112181,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":84,"op":342,"st":60,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"FRONT_SCREEN 4","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.25,-9.25],[0,0],[0.25,-0.5],[0,0],[0.5,9.25],[0,0],[-2,-2.5],[0,0]],"o":[[0,0],[0.25,3],[0,0],[-2,2.75],[0,0],[0,-16.016],[0,0],[1.75,3.5]],"v":[[-308,-465.5],[-308,477.25],[-308.25,483],[-356.25,568.25],[-364,573.75],[-364,-560.5],[-354.5,-565],[-310.5,-483]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[1,-13],[0,0],[5,-5],[0,0],[0,16.016],[0,0],[-18,-17],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-11.25,9],[0,0],[0,-16.016],[0,0],[5.5,4.5]],"v":[[-257,-464],[-257,468],[-270.5,493.062],[-345.5,568.5],[-358.25,553.75],[-357,-542.5],[-338,-559],[-265.5,-485.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[0.667,-14.005],[0,0],[8.672,-3.333],[0,0],[0,16.016],[0,0],[-17.339,-11.333],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-12.839,6],[0,0],[0,-16.016],[0,0],[9.005,3]],"v":[[-210.667,-462.333],[-210.667,466],[-229.333,495.708],[-334.833,568.667],[-353,549.167],[-352.167,-541.5],[-329.833,-562.167],[-226,-489.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0.333,-15.011],[0,0],[12.344,-1.667],[0,0],[0,16.016],[0,0],[-16.677,-5.667],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-14.427,3],[0,0],[0,-16.016],[0,0],[12.511,1.5]],"v":[[-167.833,-460.667],[-167.833,464],[-191.667,498.354],[-324.167,568.833],[-347.75,544.583],[-347.333,-540.5],[-321.667,-565.333],[-190,-493.833]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-127,-459],[-127,462],[-156,501],[-313.5,569],[-342.5,540],[-342.5,-539.5],[-313.5,-568.5],[-156,-498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-89.667,-464.667],[-89.667,467.333],[-118.667,503],[-308.667,571.333],[-337.667,542.333],[-337.667,-541.333],[-308.667,-570.333],[-118.667,-500.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-54.833,-470.333],[-54.833,472.667],[-83.833,505],[-303.833,573.667],[-332.833,544.667],[-332.833,-543.167],[-303.833,-572.167],[-83.833,-502.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-24,-476],[-24,478],[-53,507],[-299,576],[-328,547],[-328,-545],[-299,-574],[-53,-505]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[6.073,-479.4],[6.073,481.5],[-22.927,510.5],[-297.12,577.1],[-326.12,548.1],[-326.12,-546.2],[-297.12,-575.2],[-22.927,-508.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[32.647,-482.8],[32.647,485],[3.647,514],[-295.24,578.2],[-324.24,549.2],[-324.24,-547.4],[-295.24,-576.4],[3.647,-511.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[57.22,-486.2],[57.22,488.5],[28.22,517.5],[-293.36,579.3],[-322.36,550.3],[-322.36,-548.6],[-293.36,-577.6],[28.22,-515.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[79.46,-489.6],[79.46,492],[50.46,521],[-291.48,580.4],[-320.48,551.4],[-320.48,-549.8],[-291.48,-578.8],[50.46,-518.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[99.7,-493],[99.7,495.5],[70.7,524.5],[-289.6,581.5],[-318.6,552.5],[-318.6,-551],[-289.6,-580],[70.7,-522]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[136.58,-499.8],[136.58,502.5],[107.58,531.5],[-285.84,583.7],[-314.84,554.7],[-314.84,-553.4],[-285.84,-582.4],[107.58,-528.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[179.4,-510],[179.4,513],[150.4,542],[-280.2,587],[-309.2,558],[-309.2,-557],[-280.2,-586],[150.4,-539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[201.28,-516],[201.28,518.8],[172.28,547.8],[-279.44,588.2],[-308.44,559.2],[-308.44,-558],[-279.44,-587],[172.28,-545]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[212.053,-519],[212.053,521.7],[183.053,550.7],[-279.06,588.8],[-308.06,559.8],[-308.06,-558.5],[-279.06,-587.5],[183.053,-548]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[220.827,-522],[220.827,524.6],[191.827,553.6],[-278.68,589.4],[-307.68,560.4],[-307.68,-559],[-278.68,-588],[191.827,-551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[229.1,-525],[229.1,527.5],[200.1,556.5],[-278.3,590],[-307.3,561],[-307.3,-559.5],[-278.3,-588.5],[200.1,-554]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[256.46,-535.4],[256.46,537.5],[227.46,566.5],[-276.78,592.4],[-305.78,563.4],[-305.78,-561.5],[-276.78,-590.5],[227.46,-564.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[260.8,-538],[260.8,540],[231.8,569],[-276.4,593],[-305.4,564],[-305.4,-562],[-276.4,-591],[231.8,-567]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[273.82,-543.7],[273.82,546],[244.82,575],[-276.16,594.2],[-305.16,565.2],[-305.16,-562.6],[-276.16,-591.6],[244.82,-572.7]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[280.833,-547.5],[280.833,550],[251.833,579],[-276,595],[-305,566],[-305,-563],[-276,-592],[251.833,-576.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[294.867,-555],[294.867,558],[265.867,587],[-275.6,597],[-304.6,568],[-304.6,-564],[-275.6,-593],[265.867,-584]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":122.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[301.9,-559.5],[301.9,563],[272.9,592],[-275.7,597],[-304.7,568],[-304.7,-565],[-275.7,-594],[272.9,-588.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[306.933,-564],[306.933,568],[277.933,597],[-275.8,597],[-304.8,568],[-304.8,-566],[-275.8,-595],[277.933,-593]],"c":true}]},{"t":135,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[310,-568],[310,570],[281,599],[-276,599],[-305,570],[-305,-568],[-276,-597],[281,-597]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.815686285496,0.882352948189,0.980392158031,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[384,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[102,102],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":88,"op":342,"st":60,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Figure 7","tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":93.334,"s":[0]},{"t":101.666015625,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[207.459,144.79,0],"to":[0.312,0,0],"ti":[-1.146,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":62.779,"s":[209.334,144.79,0],"to":[1.146,0,0],"ti":[-2.125,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65.555,"s":[214.334,144.79,0],"to":[2.125,0,0],"ti":[-2.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[222.084,144.79,0],"to":[2.812,0,0],"ti":[-4.396,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":71.111,"s":[231.209,144.79,0],"to":[4.396,0,0],"ti":[-5.104,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[248.459,144.79,0],"to":[5.104,0,0],"ti":[-3.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.223,"s":[261.834,144.79,0],"to":[3.812,0,0],"ti":[-2.667,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.779,"s":[271.334,144.79,0],"to":[2.667,0,0],"ti":[-1.812,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[277.834,144.79,0],"to":[1.812,0,0],"ti":[-1.083,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98.889,"s":[282.209,144.79,0],"to":[1.083,0,0],"ti":[-0.458,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.445,"s":[284.334,144.79,0],"to":[0.458,0,0],"ti":[-0.104,0,0]},{"t":110,"s":[284.959,144.79,0]}],"ix":2,"l":2},"a":{"a":0,"k":[270.209,145.54,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.55,0.55,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.001]},"t":60,"s":[108,108,100]},{"t":110,"s":[106.5,106.5,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0,0],[-0.095,-1.387],[0.299,-1.3],[0.045,1.308]],"o":[[0.052,0.711],[0.119,1.734],[-0.239,1.04],[0,0]],"v":[[-57.799,-6.034],[-57.522,-2.167],[-57.671,6.182],[-58.104,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0,0],[-0.232,-1.387],[0.725,-1.3],[0.109,1.308]],"o":[[0.127,0.711],[0.29,1.734],[-0.58,1.04],[0,0]],"v":[[-53.069,-6.034],[-52.397,-2.167],[-52.759,6.182],[-53.809,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,0],[-0.59,-1.387],[1.846,-1.3],[0.276,1.308]],"o":[[0.325,0.711],[0.738,1.734],[-1.477,1.04],[0,0]],"v":[[-41.097,-6.034],[-39.386,-2.167],[-40.307,6.182],[-42.981,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,0],[-0.953,-1.387],[2.979,-1.3],[0.446,1.308]],"o":[[0.524,0.711],[1.191,1.734],[-2.384,1.04],[0,0]],"v":[[-29.746,-6.034],[-26.986,-2.167],[-28.473,6.182],[-32.788,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,0],[-1.277,-1.387],[3.993,-1.3],[0.598,1.308]],"o":[[0.702,0.711],[1.596,1.734],[-3.195,1.04],[0,0]],"v":[[-19.728,-6.034],[-16.028,-2.167],[-18.021,6.182],[-23.805,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[0,0],[-1.471,-1.387],[4.599,-1.3],[0.688,1.308]],"o":[[0.809,0.711],[1.838,1.734],[-3.68,1.04],[0,0]],"v":[[-13.958,-6.034],[-9.695,-2.167],[-11.991,6.182],[-18.654,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,0],[-1.612,-1.387],[5.042,-1.3],[0.754,1.308]],"o":[[0.886,0.711],[2.015,1.734],[-4.034,1.04],[0,0]],"v":[[-9.542,-6.034],[-4.87,-2.167],[-7.386,6.182],[-14.689,3.557]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[0,0],[-1.826,-1.387],[5.71,-1.3],[0.854,1.308]],"o":[[1.004,0.711],[2.282,1.734],[-4.569,1.04],[0,0]],"v":[[-8.492,-6.268],[-3.201,-2.402],[-6.051,5.947],[-14.321,3.322]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[0,0],[-1.802,-1.387],[5.635,-1.3],[0.843,1.308]],"o":[[0.991,0.711],[2.252,1.734],[-4.509,1.04],[0,0]],"v":[[-5.336,-6.268],[-0.114,-2.402],[-2.926,5.947],[-11.089,3.322]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,0],[-1.899,-1.387],[5.939,-1.3],[0.889,1.308]],"o":[[1.044,0.711],[2.374,1.734],[-4.752,1.04],[0,0]],"v":[[-2.334,-6.268],[3.169,-2.402],[0.205,5.947],[-8.397,3.322]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,0],[-1.939,-1.387],[6.061,-1.3],[0.907,1.308]],"o":[[1.066,0.711],[2.423,1.734],[-4.85,1.04],[0,0]],"v":[[-0.934,-6.268],[4.683,-2.402],[1.658,5.947],[-7.122,3.322]],"c":false}]},{"t":135,"s":[{"i":[[0,0],[-1.939,-1.387],[6.061,-1.3],[0.907,1.308]],"o":[[1.066,0.711],[2.423,1.734],[-4.85,1.04],[0,0]],"v":[[-0.582,-6.237],[5.035,-2.37],[2.01,5.979],[-6.77,3.354]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.596078455448,0.321568638086,0.239215686917,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2.12,"ix":5},"lc":2,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[272.026,152.086],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Nose","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[-0.193,7.277],[-0.436,0],[-0.204,3.66],[0.902,-0.059],[0.071,-14.068],[-0.242,0]],"o":[[0.15,8.062],[0.245,0],[-0.171,-14.63],[-0.9,0.059],[0.185,2.604],[0.436,0]],"v":[[-56.249,5.695],[-55.215,18.856],[-54.713,13.904],[-56.412,-10.293],[-57.945,12.606],[-57.189,17.449]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[-0.47,7.277],[-1.059,0],[-0.496,3.66],[2.191,-0.059],[0.174,-14.068],[-0.588,0]],"o":[[0.364,8.062],[0.596,0],[-0.415,-14.63],[-2.185,0.059],[0.449,2.604],[1.059,0]],"v":[[-51.53,5.695],[-49.016,18.856],[-47.797,13.904],[-51.926,-10.293],[-55.649,12.606],[-53.813,17.449]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-1.196,7.277],[-2.695,0],[-1.262,3.66],[5.577,-0.059],[0.442,-14.068],[-1.497,0]],"o":[[0.928,8.062],[1.517,0],[-1.057,-14.63],[-5.564,0.059],[1.144,2.604],[2.695,0]],"v":[[-39.584,5.695],[-33.184,18.856],[-30.08,13.904],[-40.592,-10.293],[-50.072,12.606],[-45.396,17.449]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[-1.93,7.277],[-4.349,0],[-1.859,2.669],[8.999,-0.059],[0.713,-14.068],[-2.416,0]],"o":[[1.497,8.062],[2.449,0],[-1.705,-14.63],[-8.978,0.059],[1.845,2.604],[4.349,0]],"v":[[-28.26,5.461],[-18.311,18.388],[-12.925,13.904],[-29.887,-10.293],[-45.183,12.606],[-38.394,17.215]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[-2.586,7.277],[-5.829,0],[-2.492,2.669],[12.062,-0.059],[0.956,-14.068],[-3.238,0]],"o":[[2.007,8.062],[3.282,0],[-0.557,-15.213],[-12.034,0.059],[2.474,2.604],[5.829,0]],"v":[[-18.266,5.461],[-4.931,18.388],[2.289,13.904],[-20.446,-11.464],[-40.949,12.606],[-31.849,17.215]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[-2.979,7.277],[-6.715,0],[-2.871,2.669],[13.894,-0.059],[0.615,-15.17],[-3.73,0]],"o":[[2.311,8.062],[3.781,0],[-0.642,-15.213],[-13.862,0.059],[2.849,2.604],[6.715,0]],"v":[[-12.51,4.992],[2.851,17.685],[11.168,13.904],[-15.292,-12.168],[-38.639,12.606],[-28.157,16.746]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[-3.266,7.277],[-7.36,0],[-3.147,2.669],[15.23,-0.059],[0.674,-15.17],[-4.089,0]],"o":[[2.534,8.062],[4.144,0],[-0.703,-15.213],[-15.194,0.059],[3.123,2.604],[7.36,0]],"v":[[-8.876,4.523],[7.962,17.215],[17.592,12.496],[-10.382,-13.106],[-37.517,11.903],[-26.284,16.511]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[-3.478,7.277],[-7.839,0],[-3.352,2.669],[16.221,-0.059],[0.718,-15.17],[-4.355,0]],"o":[[3.478,7.277],[4.414,0],[-0.749,-15.213],[-16.184,0.059],[3.327,2.604],[7.839,0]],"v":[[-5.981,4.288],[11.703,16.746],[21.96,12.496],[-7.336,-13.576],[-36.487,11.903],[-24.772,16.511]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[-3.65,7.277],[-8.226,0],[-3.517,2.669],[17.022,-0.059],[0.753,-15.17],[-4.57,0]],"o":[[3.65,7.277],[4.632,0],[-0.786,-15.213],[-16.983,0.059],[3.491,2.604],[8.226,0]],"v":[[-3.376,3.819],[15.182,16.511],[26.438,12.496],[-4.797,-14.514],[-35.635,11.668],[-23.342,16.511]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[-3.847,7.277],[-8.67,0],[-3.707,2.669],[17.939,-0.059],[0.794,-15.17],[-4.816,0]],"o":[[3.847,7.277],[4.881,0],[-0.828,-15.213],[-17.898,0.059],[3.679,2.604],[8.67,0]],"v":[[-1.836,3.584],[18.215,15.807],[31.315,11.557],[-1.85,-15.923],[-34.843,11.668],[-21.888,15.807]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[-3.926,7.277],[-8.848,0],[-3.783,2.669],[18.309,-0.059],[0.81,-15.17],[-4.916,0]],"o":[[3.926,7.277],[4.982,0],[-0.845,-15.213],[-18.267,0.059],[3.755,2.604],[8.848,0]],"v":[[-0.458,3.584],[20.007,15.807],[33.377,11.557],[-0.472,-15.923],[-34.145,11.668],[-20.923,15.807]],"c":true}]},{"t":135,"s":[{"i":[[-3.926,7.277],[-8.848,0],[-3.783,2.669],[18.309,-0.059],[0.81,-15.17],[-4.916,0]],"o":[[3.926,7.277],[4.982,0],[-0.845,-15.213],[-18.267,0.059],[3.755,2.604],[8.848,0]],"v":[[-0.106,3.616],[20.359,15.839],[33.729,11.589],[-0.12,-15.891],[-33.793,11.7],[-20.571,15.839]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0,9.283],[0.481,0],[0,-9.283],[-0.481,0]],"o":[[0,-9.283],[-0.481,0],[0,9.283],[0.481,0]],"v":[[-56.552,-17.322],[-57.474,-33.907],[-58.358,-17.994],[-57.435,-0.961]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0,9.283],[1.168,0],[0,-9.283],[-1.168,0]],"o":[[0,-9.283],[-1.168,0],[0,9.283],[1.168,0]],"v":[[-52.264,-17.322],[-54.505,-33.907],[-56.652,-17.994],[-54.41,-0.961]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0,9.283],[2.973,0],[0,-9.283],[-2.973,0]],"o":[[0,-9.283],[-2.973,0],[0,9.283],[2.973,0]],"v":[[-41.453,-17.322],[-47.159,-33.907],[-52.623,-17.994],[-46.917,-0.961]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,9.283],[4.797,0],[0,-9.283],[-4.797,0]],"o":[[0,-9.283],[-4.797,0],[0,9.283],[4.797,0]],"v":[[-31.654,-18.258],[-40.861,-34.843],[-49.678,-18.931],[-40.471,-1.898]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,9.532],[6.43,0],[0,-9.532],[-6.43,0]],"o":[[0,-9.532],[-6.43,0],[0,9.532],[6.43,0]],"v":[[-22.815,-18.985],[-35.156,-36.015],[-46.974,-19.676],[-34.633,-2.186]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[0,9.532],[7.407,0],[0,-9.532],[-7.407,0]],"o":[[0,-9.532],[-7.407,0],[0,9.532],[7.407,0]],"v":[[-18.02,-19.689],[-32.236,-36.718],[-45.85,-20.379],[-31.633,-2.89]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,9.723],[8.119,0],[0,-9.723],[-8.119,0]],"o":[[0,-9.723],[-8.119,0],[0,9.723],[8.119,0]],"v":[[-14.659,-20.051],[-30.241,-37.422],[-45.163,-20.755],[-29.58,-2.915]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[0,9.723],[8.648,0],[0,-9.723],[-8.648,0]],"o":[[0,-9.723],[-8.648,0],[0,9.723],[8.648,0]],"v":[[-11.89,-20.755],[-28.488,-38.126],[-44.381,-21.459],[-27.784,-3.619]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[0,9.723],[9.075,0],[0,-9.723],[-9.075,0]],"o":[[0,-9.723],[-9.075,0],[0,9.723],[9.075,0]],"v":[[-10.316,-21.459],[-26.748,-39.065],[-43.18,-21.459],[-26.748,-3.854]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,9.805],[9.607,0],[0,-9.805],[-9.607,0]],"o":[[0,-9.805],[-9.607,0],[0,9.805],[9.607,0]],"v":[[-8.19,-22.558],[-25.585,-40.312],[-42.981,-22.558],[-25.585,-4.804]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,9.805],[9.805,0],[0,-9.805],[-9.805,0]],"o":[[0,-9.805],[-9.805,0],[0,9.805],[9.805,0]],"v":[[-6.942,-22.558],[-24.697,-40.312],[-42.451,-22.558],[-24.697,-4.804]],"c":true}]},{"t":135,"s":[{"i":[[0,9.805],[9.805,0],[0,-9.805],[-9.805,0]],"o":[[0,-9.805],[-9.805,0],[0,9.805],[9.805,0]],"v":[[-6.59,-22.526],[-24.345,-40.281],[-42.099,-22.526],[-24.345,-4.772]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.23137255013,0.129411771894,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.47,108.276],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Hair","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[-0.312,13.512],[0,0],[0,0],[-0.015,2.62],[0.001,4.351],[0,0],[-0.927,0.06],[-0.139,-15.255],[0,0],[-0.024,-2.669],[-0.092,-4.353],[-0.044,-3.988],[0,-4.307],[0.295,-3.002],[0.482,-0.349],[0.391,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.06,-4.479],[0.015,-2.598],[0,0],[-0.003,-15.806],[0.927,-0.06],[0,0],[0.001,4.276],[0.024,2.702],[0.178,8.387],[0.044,3.962],[0,7.459],[-0.49,4.981],[-0.608,0.441],[-0.407,-5.108],[0,0],[0,-6.072]],"v":[[-58.689,-3.691],[-58.726,-4.5],[-58.724,-4.616],[-58.676,-14.567],[-58.471,-23.153],[-58.471,-23.222],[-56.937,-47.531],[-55.247,-22.97],[-55.247,-22.876],[-55.237,-14.204],[-55.068,-5.188],[-54.763,11.754],[-54.743,22.514],[-55.47,41.151],[-56.849,48.639],[-58.387,41.742],[-59.021,24.251],[-59.021,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[-0.757,13.512],[0,0],[0,0],[-0.037,2.62],[0.002,4.351],[0,0],[-2.253,0.06],[-0.337,-15.255],[0,0],[-0.058,-2.669],[-0.224,-4.353],[-0.106,-3.988],[0,-4.307],[0.717,-3.002],[1.17,-0.349],[0.95,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.146,-4.479],[0.037,-2.598],[0,0],[-0.006,-15.806],[2.253,-0.06],[0,0],[0.001,4.276],[0.059,2.702],[0.431,8.387],[0.106,3.962],[0,7.459],[-1.19,4.981],[-1.476,0.441],[-0.989,-5.108],[0,0],[0,-6.072]],"v":[[-56.705,-3.691],[-56.793,-4.5],[-56.789,-4.616],[-56.672,-14.567],[-56.176,-23.153],[-56.176,-23.222],[-52.448,-47.531],[-48.344,-22.97],[-48.344,-22.876],[-48.32,-14.204],[-47.909,-5.188],[-47.168,11.754],[-47.118,22.514],[-48.884,41.151],[-52.234,48.639],[-55.971,41.742],[-57.511,24.251],[-57.511,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[-1.928,13.512],[0,0],[0,0],[-0.095,2.62],[0.005,4.351],[0,0],[-5.736,0.06],[-0.858,-15.255],[0,0],[-0.149,-2.669],[-0.57,-4.353],[-0.271,-3.988],[0,-4.307],[1.826,-3.002],[2.98,-0.349],[2.418,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.372,-4.479],[0.094,-2.598],[0,0],[-0.015,-15.806],[5.736,-0.06],[0,0],[0.004,4.276],[0.151,2.702],[1.098,8.387],[0.269,3.962],[0,7.459],[-3.03,4.981],[-3.758,0.441],[-2.518,-5.108],[0,0],[0,-6.072]],"v":[[-51.946,-3.691],[-52.17,-4.5],[-52.161,-4.616],[-51.862,-14.567],[-50.599,-23.153],[-50.599,-23.222],[-41.108,-47.531],[-30.66,-22.97],[-30.66,-22.876],[-30.598,-14.204],[-29.552,-5.188],[-27.667,11.754],[-27.539,22.514],[-32.036,41.151],[-40.564,48.639],[-50.078,41.742],[-53.999,24.251],[-53.999,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[-3.112,13.512],[0,0],[0,0],[-0.153,2.62],[0.007,4.351],[0,0],[-9.255,0.06],[-1.384,-15.255],[0,0],[-0.24,-2.669],[-0.919,-4.353],[-0.437,-3.988],[0,-4.307],[2.946,-3.002],[4.808,-0.349],[3.902,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.601,-4.479],[0.152,-2.598],[0,0],[-0.025,-15.806],[9.255,-0.06],[0,0],[0.006,4.276],[0.243,2.702],[1.772,8.387],[0.434,3.962],[0,7.459],[-4.889,4.981],[-6.063,0.441],[-4.063,-5.108],[0,0],[0,-6.072]],"v":[[-47.884,-3.691],[-48.247,-4.5],[-48.231,-4.616],[-47.749,-14.567],[-45.712,-23.153],[-45.712,-23.222],[-30.397,-47.531],[-13.538,-22.97],[-13.538,-22.876],[-13.439,-14.204],[-11.75,-5.188],[-8.709,11.754],[-8.502,22.514],[-15.759,41.151],[-29.518,48.639],[-44.87,41.742],[-51.198,24.251],[-51.198,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[-4.171,13.512],[0,0],[0,0],[-0.205,2.62],[0.01,4.351],[0,0],[-12.405,0.06],[-0.034,-15.806],[0,0],[-0.322,-2.669],[-1.232,-4.353],[-0.586,-3.988],[0,-4.307],[5.048,-4.141],[6.445,-0.349],[5.23,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.805,-4.479],[0.203,-2.598],[0,0],[-0.033,-15.806],[12.405,-0.06],[0,0],[0.008,4.276],[0.326,2.702],[2.374,8.387],[0.582,3.962],[0,7.459],[-6.294,5.164],[-8.127,0.441],[-5.446,-5.108],[0,0],[0,-6.072]],"v":[[-44.39,-3.691],[-44.876,-4.5],[-44.856,-4.616],[-44.21,-14.567],[-41.478,-23.153],[-41.478,-23.222],[-20.951,-48.702],[1.646,-22.97],[1.646,-22.876],[1.78,-14.204],[4.043,-5.188],[8.119,11.754],[8.71,22.982],[-1.017,41.619],[-19.46,49.108],[-40.037,42.211],[-48.832,24.251],[-48.832,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[-4.804,13.512],[0,0],[0,0],[-0.236,2.62],[0.011,4.351],[0,0],[-14.289,0.06],[-0.039,-15.806],[0,0],[-0.371,-2.669],[-1.42,-4.353],[-0.675,-3.988],[0,-4.307],[6.374,-5.095],[7.424,-0.349],[6.025,4.905],[0,7.994],[0,0]],"o":[[0,0],[0,0],[0.927,-4.479],[0.234,-2.598],[0,0],[-0.038,-15.806],[14.289,-0.06],[0,0],[0.01,4.276],[0.375,2.702],[2.735,8.387],[0.671,3.962],[0,7.459],[-6.899,5.515],[-9.362,0.441],[-6.274,-5.108],[0,0],[0,-6.072]],"v":[[-42.523,-3.691],[-43.083,-4.5],[-43.059,-4.616],[-42.315,-14.567],[-39.169,-23.153],[-39.169,-23.222],[-15.793,-49.406],[10.507,-22.97],[10.507,-22.876],[10.661,-14.204],[13.268,-5.188],[17.964,11.754],[18.644,22.982],[7.44,42.557],[-13.805,50.046],[-37.508,43.149],[-47.64,24.251],[-47.64,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[-5.266,13.512],[0,0],[0,0],[-0.259,2.62],[0.012,4.351],[0,0],[-15.663,0.06],[-0.042,-15.806],[0,0],[-0.407,-2.669],[-1.556,-4.353],[-0.74,-3.988],[0,-4.307],[6.987,-5.095],[10.261,-0.04],[6.684,5.31],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.016,-4.479],[0.257,-2.598],[0,0],[-0.042,-15.806],[15.663,-0.06],[0,0],[0.011,4.276],[0.411,2.702],[2.998,8.387],[0.735,3.962],[0,7.459],[-7.562,5.515],[-10.273,0.04],[-6.687,-5.313],[0,0],[0,-6.072]],"v":[[-41.467,-3.925],[-42.08,-4.735],[-42.054,-4.851],[-40.724,-14.567],[-38.047,-23.857],[-38.047,-23.925],[-10.882,-50.344],[16.919,-24.377],[16.919,-24.283],[17.344,-14.204],[19.173,-5.188],[24.835,11.754],[25.58,22.982],[14.071,42.792],[-10.245,50.515],[-36.741,43.149],[-46.56,24.251],[-46.56,24.218]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[-5.609,13.512],[0,0],[0,0],[-0.276,2.62],[0.013,4.351],[0,0],[-16.682,0.06],[-0.045,-15.806],[0,0],[-0.433,-2.669],[-1.658,-4.353],[-0.788,-3.988],[0,-4.307],[7.101,-5.507],[10.929,-0.04],[7.119,5.31],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.083,-4.479],[0.273,-2.598],[0,0],[-0.045,-15.806],[16.682,-0.06],[0,0],[0.011,4.276],[0.438,2.702],[3.193,8.387],[0.783,3.962],[0,7.459],[-7.085,5.495],[-10.942,0.04],[-7.123,-5.313],[0,0],[0,-6.072]],"v":[[-40.159,-3.925],[-40.813,-4.735],[-40.785,-4.851],[-38.869,-14.567],[-37.017,-23.857],[-37.017,-23.925],[-7.833,-50.813],[21.277,-24.377],[21.277,-24.283],[21.73,-14.673],[24.928,-5.188],[30.958,11.754],[31.752,22.982],[19.493,43.261],[-7.655,50.984],[-35.376,43.384],[-46.085,24.486],[-46.085,24.453]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[-5.886,13.512],[0,0],[0,0],[-0.289,2.62],[0.014,4.351],[0,0],[-17.506,0.06],[-0.047,-15.806],[0,0],[-0.454,-2.669],[-1.739,-4.353],[-0.827,-3.988],[0,-4.307],[7.452,-5.507],[11.468,-0.04],[7.47,5.31],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.136,-4.479],[0.287,-2.598],[0,0],[-0.047,-15.806],[17.506,-0.06],[0,0],[0.012,4.276],[0.46,2.702],[3.351,8.387],[0.822,3.962],[0,7.459],[-7.435,5.495],[-11.482,0.04],[-7.475,-5.313],[0,0],[0,-6.072]],"v":[[-39.463,-4.63],[-39.41,-4.735],[-39.38,-4.851],[-37.37,-14.567],[-36.165,-24.092],[-36.165,-24.16],[-5.294,-51.752],[25.747,-24.377],[25.747,-24.283],[26.223,-14.673],[29.332,-4.954],[35.168,12.458],[36.001,23.687],[24.122,43.965],[-5.107,51.923],[-34.197,43.853],[-45.681,24.016],[-45.681,23.984]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[-7.295,13.962],[0,0],[0,0],[-0.305,2.62],[0.015,4.351],[0,0],[-18.449,0.06],[-0.05,-15.806],[0,0],[-0.479,-2.669],[-1.833,-4.353],[-0.871,-3.988],[0,-4.307],[7.853,-5.507],[12.086,-0.04],[7.873,5.31],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.197,-4.479],[0.302,-2.598],[0,0],[-0.05,-15.806],[18.449,-0.06],[0,0],[0.012,4.276],[0.485,2.702],[3.532,8.387],[0.866,3.962],[0,7.459],[-7.836,5.495],[-12.101,0.04],[-7.877,-5.313],[0,0],[0,-6.072]],"v":[[-37.86,-4.63],[-37.804,-4.735],[-37.773,-4.851],[-35.654,-14.567],[-35.374,-24.092],[-35.374,-24.16],[-2.345,-53.161],[30.863,-24.377],[30.863,-24.283],[31.364,-14.673],[34.641,-4.954],[40.79,12.458],[41.669,23.687],[29.15,43.965],[-1.653,53.097],[-32.557,44.557],[-45.155,23.978],[-45.155,23.945]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[-7.446,13.962],[0,0],[0,0],[-0.313,2.62],[0.015,4.351],[0,0],[-18.83,0.06],[-0.051,-15.806],[0,0],[-0.49,-2.669],[-1.873,-4.352],[-0.89,-3.988],[0,-4.307],[8.014,-5.508],[12.335,-0.04],[8.035,5.309],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.222,-4.479],[0.309,-2.598],[0,0],[-0.051,-15.806],[18.83,-0.06],[0,0],[0.013,4.276],[0.495,2.702],[3.604,8.387],[0.884,3.962],[0,7.459],[-7.997,5.495],[-12.35,0.04],[-8.04,-5.313],[0,0],[0,-6.072]],"v":[[-37.213,-4.63],[-37.156,-4.735],[-37.125,-4.851],[-34.962,-14.567],[-34.676,-24.092],[-34.676,-24.16],[-0.966,-53.161],[32.926,-24.377],[32.926,-24.283],[33.437,-14.673],[36.782,-4.954],[43.058,12.458],[43.955,23.687],[31.177,43.965],[-0.26,53.097],[-31.801,44.557],[-44.659,23.978],[-44.659,23.945]],"c":true}]},{"t":135,"s":[{"i":[[-7.446,13.962],[0,0],[0,0],[-0.313,2.62],[0.015,4.351],[0,0],[-18.83,0.06],[-0.051,-15.806],[0,0],[-0.49,-2.669],[-1.873,-4.352],[-0.89,-3.988],[0,-4.307],[8.014,-5.508],[12.335,-0.04],[8.035,5.309],[0,7.994],[0,0]],"o":[[0,0],[0,0],[1.222,-4.479],[0.309,-2.598],[0,0],[-0.051,-15.806],[18.83,-0.06],[0,0],[0.013,4.276],[0.495,2.702],[3.604,8.387],[0.884,3.962],[0,7.459],[-7.997,5.495],[-12.35,0.04],[-8.04,-5.313],[0,0],[0,-6.072]],"v":[[-36.861,-4.598],[-36.804,-4.703],[-36.772,-4.819],[-34.61,-14.535],[-34.324,-24.06],[-34.324,-24.128],[-0.614,-53.129],[33.278,-24.345],[33.278,-24.252],[33.789,-14.641],[37.134,-4.922],[43.41,12.489],[44.307,23.718],[31.53,43.997],[0.092,53.129],[-31.449,44.589],[-44.307,24.009],[-44.307,23.977]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0.226,1.656],[-0.13,7.412],[-0.226,-1.656],[0.13,-7.412]],"o":[[-0.227,-1.657],[0.13,-7.412],[0.227,1.657],[-0.13,7.412]],"v":[[-55.466,2.927],[-55.616,-13.258],[-54.921,-22.506],[-54.796,-6.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.55,1.656],[-0.316,7.412],[-0.55,-1.656],[0.316,-7.412]],"o":[[-0.55,-1.657],[0.316,-7.412],[0.55,1.657],[-0.316,7.412]],"v":[[-48.875,2.927],[-49.239,-13.258],[-47.55,-22.506],[-47.247,-6.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[1.401,1.656],[-0.804,7.412],[-1.401,-1.656],[0.804,-7.412]],"o":[[-1.401,-1.657],[0.804,-7.412],[1.401,1.657],[-0.804,7.412]],"v":[[-32.013,2.927],[-32.939,-13.258],[-28.639,-22.506],[-27.867,-6.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[2.26,1.656],[-1.298,7.412],[-2.26,-1.656],[1.298,-7.412]],"o":[[-2.261,-1.657],[1.298,-7.412],[2.261,1.657],[-1.298,7.412]],"v":[[-15.721,2.927],[-17.217,-13.258],[-10.278,-22.506],[-9.031,-6.555]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[3.029,1.656],[-1.74,7.412],[-3.029,-1.656],[1.739,-7.412]],"o":[[-3.031,-1.657],[1.74,-7.412],[3.03,1.657],[-1.739,7.412]],"v":[[-0.652,2.224],[-2.656,-13.961],[6.643,-23.209],[8.315,-7.258]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[3.489,1.656],[-2.004,7.412],[-3.489,-1.656],[2.004,-7.412]],"o":[[-3.491,-1.657],[2.004,-7.412],[3.491,1.657],[-2.004,7.412]],"v":[[7.86,1.52],[5.551,-14.665],[16.264,-23.912],[18.189,-7.962]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[3.825,1.656],[-2.196,7.412],[-3.825,-1.656],[2.196,-7.412]],"o":[[-3.826,-1.657],[2.196,-7.412],[3.826,1.657],[-2.196,7.412]],"v":[[14.017,1.051],[11.486,-15.134],[23.228,-24.381],[25.339,-8.431]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[4.074,1.656],[-2.339,7.412],[-4.074,-1.656],[2.339,-7.412]],"o":[[-4.076,-1.657],[2.339,-7.412],[4.076,1.657],[-2.339,7.412]],"v":[[18.936,-0.122],[16.24,-16.307],[28.747,-25.555],[30.995,-9.604]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[4.275,1.656],[-2.455,7.412],[-4.275,-1.656],[2.455,-7.412]],"o":[[-4.277,-1.657],[2.455,-7.412],[4.277,1.657],[-2.455,7.412]],"v":[[23.29,-0.122],[20.462,-16.307],[33.587,-25.555],[35.946,-9.604]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[4.505,1.656],[-2.587,7.412],[-4.505,-1.656],[2.587,-7.412]],"o":[[-4.507,-1.657],[2.587,-7.412],[4.507,1.657],[-2.587,7.412]],"v":[[28.274,-0.122],[24.798,-16.542],[37.64,-26.963],[41.116,-10.543]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[4.598,1.656],[-2.64,7.412],[-4.598,-1.656],[2.64,-7.412]],"o":[[-4.6,-1.657],[2.64,-7.412],[4.6,1.657],[-2.64,7.412]],"v":[[30.283,-0.122],[26.736,-16.542],[39.843,-26.963],[43.39,-10.543]],"c":true}]},{"t":135,"s":[{"i":[[4.598,1.656],[-2.64,7.412],[-4.598,-1.656],[2.64,-7.412]],"o":[[-4.6,-1.657],[2.64,-7.412],[4.6,1.657],[-2.64,7.412]],"v":[[30.635,-0.09],[27.088,-16.51],[40.195,-26.931],[43.742,-10.511]],"c":true}]}],"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0.226,-1.656],[0.13,7.412],[-0.226,1.656],[-0.13,-7.412]],"o":[[-0.227,1.657],[-0.13,-7.412],[0.227,-1.657],[0.13,7.412]],"v":[[-58.448,-0.292],[-59.074,-9.887],[-58.879,-25.49],[-58.273,-15.539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.55,-1.656],[0.316,7.412],[-0.55,1.656],[-0.316,-7.412]],"o":[[-0.55,1.657],[-0.316,-7.412],[0.55,-1.657],[0.316,7.412]],"v":[[-56.118,-0.292],[-57.64,-9.887],[-57.165,-25.49],[-55.694,-15.539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[1.401,-1.656],[0.804,7.412],[-1.401,1.656],[-0.804,-7.412]],"o":[[-1.401,1.657],[-0.804,-7.412],[1.401,-1.657],[0.804,7.412]],"v":[[-50.453,-0.292],[-54.326,-9.887],[-53.117,-25.49],[-49.372,-15.539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[2.26,-1.656],[1.298,7.412],[-2.26,1.656],[-1.298,-7.412]],"o":[[-2.261,1.657],[-1.298,-7.412],[2.261,-1.657],[1.298,7.412]],"v":[[-45.475,-0.292],[-51.726,-9.887],[-49.775,-25.49],[-43.732,-15.539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[3.029,-1.656],[1.739,7.412],[-3.029,1.656],[-1.739,-7.412]],"o":[[-3.03,1.657],[-1.739,-7.412],[3.03,-1.657],[1.739,7.412]],"v":[[-41.476,-0.761],[-49.854,-10.355],[-47.238,-25.959],[-39.139,-16.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[3.489,-1.656],[2.004,7.412],[-3.489,1.656],[-2.004,-7.412]],"o":[[-3.491,1.657],[-2.004,-7.412],[3.491,-1.657],[2.004,7.412]],"v":[[-39.166,-0.761],[-48.816,-10.355],[-45.804,-25.959],[-36.474,-16.007]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[3.825,-1.656],[2.196,7.412],[-3.825,1.656],[-2.196,-7.412]],"o":[[-3.826,1.657],[-2.196,-7.412],[3.826,-1.657],[2.196,7.412]],"v":[[-37.786,0.178],[-47.85,-10.355],[-45.32,-25.959],[-34.835,-16.242]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[4.074,-1.656],[2.339,7.412],[-4.074,1.656],[-2.339,-7.412]],"o":[[-4.075,1.657],[-2.339,-7.412],[4.075,-1.657],[2.339,7.412]],"v":[[-36.739,-0.057],[-47.459,-10.59],[-44.763,-26.193],[-33.597,-16.477]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[4.275,-1.656],[2.455,7.412],[-4.275,1.656],[-2.455,-7.412]],"o":[[-4.277,1.657],[-2.455,-7.412],[4.277,-1.657],[2.455,7.412]],"v":[[-35.135,-0.057],[-46.384,-10.59],[-43.555,-26.193],[-31.837,-16.477]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[4.505,-1.656],[2.587,7.412],[-4.505,1.656],[-2.587,-7.412]],"o":[[-4.507,1.657],[-2.587,-7.412],[4.507,-1.657],[2.587,7.412]],"v":[[-33.299,-0.057],[-46.143,-10.478],[-42.667,-26.898],[-29.823,-16.477]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[4.598,-1.656],[2.64,7.412],[-4.598,1.656],[-2.64,-7.412]],"o":[[-4.6,1.657],[-2.64,-7.412],[4.6,-1.657],[2.64,7.412]],"v":[[-32.558,-0.057],[-45.667,-10.478],[-42.12,-26.898],[-29.011,-16.477]],"c":true}]},{"t":135,"s":[{"i":[[4.598,-1.656],[2.64,7.412],[-4.598,1.656],[-2.64,-7.412]],"o":[[-4.6,1.657],[-2.64,-7.412],[4.6,-1.657],[2.64,7.412]],"v":[[-32.206,-0.025],[-45.315,-10.446],[-41.768,-26.866],[-28.659,-16.445]],"c":true}]}],"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431391716,0.403921574354,0.305882364511,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[270.996,145.54],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Head","np":4,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[1.662,-1.078],[0.252,-6.5],[0,0],[0,0],[0.006,7.75]],"o":[[-1.809,1.173],[-0.012,11],[0,0],[0,0],[-0.448,-10.219]],"v":[[214.31,197.746],[210.645,231.218],[210.632,265.093],[217.136,244.459],[217.174,217.753]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[4.038,-1.078],[0.613,-6.5],[0,0],[0,0],[0.015,7.75]],"o":[[-4.394,1.173],[-0.03,11],[0,0],[0,0],[-1.088,-10.219]],"v":[[219.157,197.746],[210.255,231.218],[210.225,265.093],[226.024,244.459],[226.116,217.753]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[10.281,-1.078],[1.561,-6.5],[0,0],[0,0],[0.038,7.75]],"o":[[-11.186,1.173],[-0.076,11],[0,0],[0,0],[-2.771,-10.219]],"v":[[231.439,197.746],[208.774,231.218],[208.698,265.093],[248.922,244.459],[249.155,217.753]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[16.589,-1.078],[2.519,-6.5],[0,0],[0,0],[0.061,7.75]],"o":[[-18.049,1.173],[-0.123,11],[0,0],[0,0],[-6.41,-10.783]],"v":[[241.968,198.682],[206.53,231.218],[206.407,265.093],[271.689,247.502],[271.688,217.753]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[22.236,-1.078],[3.376,-6.5],[0,0],[0,0],[0.082,7.75]],"o":[[-24.192,1.173],[-0.165,11],[0,0],[0,0],[-8.592,-10.783]],"v":[[251.88,199.385],[204.38,231.218],[204.215,265.093],[291.799,250.781],[291.744,219.393]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[25.614,-1.078],[3.889,-6.5],[0,0],[0,0],[0.095,7.75]],"o":[[-27.868,1.173],[-0.19,11],[0,0],[0,0],[-9.898,-10.783]],"v":[[257.047,200.557],[202.871,231.218],[202.681,265.093],[303.634,253.83],[303.602,221.269]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[28.076,-1.078],[4.263,-6.5],[0,0],[0,0],[0.104,7.75]],"o":[[-30.546,1.173],[-0.208,11],[0,0],[0,0],[-11.853,-12.5]],"v":[[259.05,201.261],[201.981,231.218],[201.773,265.093],[312.516,256.879],[312.499,222.442]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":107.5,"s":[{"i":[[29.015,0],[4.541,-6.5],[0,0],[0,0],[0.111,7.75]],"o":[[-32.559,0],[-0.221,11],[0,0],[0,0],[-12.625,-12.5]],"v":[[263.029,201.731],[201.994,231.218],[201.773,265.093],[319.85,258.99],[319.818,224.789]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[30.448,0],[4.765,-6.5],[0,0],[0,0],[0.116,7.75]],"o":[[-34.167,0],[-0.232,11],[0,0],[0,0],[-13.249,-12.5]],"v":[[265.316,202.435],[202.005,231.218],[201.773,265.093],[325.671,261.572],[325.765,226.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[32.089,0],[5.021,-6.5],[0,0],[0,0],[0.122,7.75]],"o":[[-36.008,0],[-0.245,11],[0,0],[0,0],[-13.962,-12.5]],"v":[[268.491,203.374],[202.018,231.218],[201.773,265.093],[332.444,263.215],[332.444,228.779]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[32.75,0],[5.125,-6.5],[0,0],[0,0],[0.125,7.75]],"o":[[-36.75,0],[-0.25,11],[0,0],[0,0],[-14.25,-12.5]],"v":[[269.148,203.843],[202.023,231.218],[201.773,265.093],[335.023,265.093],[335.023,229.718]],"c":true}]},{"t":135,"s":[{"i":[[32.75,0],[5.125,-6.5],[0,0],[0,0],[0.125,7.75]],"o":[[-36.75,0],[-0.25,11],[0,0],[0,0],[-14.25,-12.5]],"v":[[269.5,203.875],[202.375,231.25],[202.125,265.125],[335.375,265.125],[335.375,229.75]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.105865478516,0.450958251953,0.901947021484,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Body","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":86,"op":660,"st":60,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"FRONT_SCREEN 5","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":93.334,"s":[0]},{"t":101.666015625,"s":[100]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.25,-9.25],[0,0],[0.25,-0.5],[0,0],[0.5,9.25],[0,0],[-2,-2.5],[0,0]],"o":[[0,0],[0.25,3],[0,0],[-2,2.75],[0,0],[0,-16.016],[0,0],[1.75,3.5]],"v":[[-308,-465.5],[-308,477.25],[-308.25,483],[-356.25,568.25],[-364,573.75],[-364,-560.5],[-354.5,-565],[-310.5,-483]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[1,-13],[0,0],[5,-5],[0,0],[0,16.016],[0,0],[-18,-17],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-11.25,9],[0,0],[0,-16.016],[0,0],[5.5,4.5]],"v":[[-257,-464],[-257,468],[-270.5,493.062],[-345.5,568.5],[-358.25,553.75],[-357,-542.5],[-338,-559],[-265.5,-485.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[0.667,-14.005],[0,0],[8.672,-3.333],[0,0],[0,16.016],[0,0],[-17.339,-11.333],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-12.839,6],[0,0],[0,-16.016],[0,0],[9.005,3]],"v":[[-210.667,-462.333],[-210.667,466],[-229.333,495.708],[-334.833,568.667],[-353,549.167],[-352.167,-541.5],[-329.833,-562.167],[-226,-489.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0.333,-15.011],[0,0],[12.344,-1.667],[0,0],[0,16.016],[0,0],[-16.677,-5.667],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-14.427,3],[0,0],[0,-16.016],[0,0],[12.511,1.5]],"v":[[-167.833,-460.667],[-167.833,464],[-191.667,498.354],[-324.167,568.833],[-347.75,544.583],[-347.333,-540.5],[-321.667,-565.333],[-190,-493.833]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-127,-459],[-127,462],[-156,501],[-313.5,569],[-342.5,540],[-342.5,-539.5],[-313.5,-568.5],[-156,-498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-89.667,-464.667],[-89.667,467.333],[-118.667,503],[-308.667,571.333],[-337.667,542.333],[-337.667,-541.333],[-308.667,-570.333],[-118.667,-500.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-54.833,-470.333],[-54.833,472.667],[-83.833,505],[-303.833,573.667],[-332.833,544.667],[-332.833,-543.167],[-303.833,-572.167],[-83.833,-502.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-24,-476],[-24,478],[-53,507],[-299,576],[-328,547],[-328,-545],[-299,-574],[-53,-505]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[6.073,-479.4],[6.073,481.5],[-22.927,510.5],[-297.12,577.1],[-326.12,548.1],[-326.12,-546.2],[-297.12,-575.2],[-22.927,-508.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[32.647,-482.8],[32.647,485],[3.647,514],[-295.24,578.2],[-324.24,549.2],[-324.24,-547.4],[-295.24,-576.4],[3.647,-511.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[57.22,-486.2],[57.22,488.5],[28.22,517.5],[-293.36,579.3],[-322.36,550.3],[-322.36,-548.6],[-293.36,-577.6],[28.22,-515.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[79.46,-489.6],[79.46,492],[50.46,521],[-291.48,580.4],[-320.48,551.4],[-320.48,-549.8],[-291.48,-578.8],[50.46,-518.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[99.7,-493],[99.7,495.5],[70.7,524.5],[-289.6,581.5],[-318.6,552.5],[-318.6,-551],[-289.6,-580],[70.7,-522]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[136.58,-499.8],[136.58,502.5],[107.58,531.5],[-285.84,583.7],[-314.84,554.7],[-314.84,-553.4],[-285.84,-582.4],[107.58,-528.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[179.4,-510],[179.4,513],[150.4,542],[-280.2,587],[-309.2,558],[-309.2,-557],[-280.2,-586],[150.4,-539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[201.28,-516],[201.28,518.8],[172.28,547.8],[-279.44,588.2],[-308.44,559.2],[-308.44,-558],[-279.44,-587],[172.28,-545]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[212.053,-519],[212.053,521.7],[183.053,550.7],[-279.06,588.8],[-308.06,559.8],[-308.06,-558.5],[-279.06,-587.5],[183.053,-548]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[220.827,-522],[220.827,524.6],[191.827,553.6],[-278.68,589.4],[-307.68,560.4],[-307.68,-559],[-278.68,-588],[191.827,-551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[229.1,-525],[229.1,527.5],[200.1,556.5],[-278.3,590],[-307.3,561],[-307.3,-559.5],[-278.3,-588.5],[200.1,-554]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[256.46,-535.4],[256.46,537.5],[227.46,566.5],[-276.78,592.4],[-305.78,563.4],[-305.78,-561.5],[-276.78,-590.5],[227.46,-564.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[260.8,-538],[260.8,540],[231.8,569],[-276.4,593],[-305.4,564],[-305.4,-562],[-276.4,-591],[231.8,-567]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[273.82,-543.7],[273.82,546],[244.82,575],[-276.16,594.2],[-305.16,565.2],[-305.16,-562.6],[-276.16,-591.6],[244.82,-572.7]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[280.833,-547.5],[280.833,550],[251.833,579],[-276,595],[-305,566],[-305,-563],[-276,-592],[251.833,-576.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[294.867,-555],[294.867,558],[265.867,587],[-275.6,597],[-304.6,568],[-304.6,-564],[-275.6,-593],[265.867,-584]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":122.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[301.9,-559.5],[301.9,563],[272.9,592],[-275.7,597],[-304.7,568],[-304.7,-565],[-275.7,-594],[272.9,-588.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[306.933,-564],[306.933,568],[277.933,597],[-275.8,597],[-304.8,568],[-304.8,-566],[-275.8,-595],[277.933,-593]],"c":true}]},{"t":135,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[310,-568],[310,570],[281,599],[-276,599],[-305,570],[-305,-568],[-276,-597],[281,-597]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.815686285496,0.882352948189,0.980392158031,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[384,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[101.75,101.75],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":87,"op":342,"st":60,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"FRONT_SCREEN 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.25,-9.25],[0,0],[0.25,-0.5],[0,0],[0.5,9.25],[0,0],[-2,-2.5],[0,0]],"o":[[0,0],[0.25,3],[0,0],[-2,2.75],[0,0],[0,-16.016],[0,0],[1.75,3.5]],"v":[[-308,-465.5],[-308,477.25],[-308.25,483],[-356.25,568.25],[-364,573.75],[-364,-560.5],[-354.5,-565],[-310.5,-483]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[1,-13],[0,0],[5,-5],[0,0],[0,16.016],[0,0],[-18,-17],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-11.25,9],[0,0],[0,-16.016],[0,0],[5.5,4.5]],"v":[[-257,-464],[-257,468],[-270.5,493.062],[-345.5,568.5],[-358.25,553.75],[-357,-542.5],[-338,-559],[-265.5,-485.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[0.667,-14.005],[0,0],[8.672,-3.333],[0,0],[0,16.016],[0,0],[-17.339,-11.333],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-12.839,6],[0,0],[0,-16.016],[0,0],[9.005,3]],"v":[[-210.667,-462.333],[-210.667,466],[-229.333,495.708],[-334.833,568.667],[-353,549.167],[-352.167,-541.5],[-329.833,-562.167],[-226,-489.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[0.333,-15.011],[0,0],[12.344,-1.667],[0,0],[0,16.016],[0,0],[-16.677,-5.667],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-14.427,3],[0,0],[0,-16.016],[0,0],[12.511,1.5]],"v":[[-167.833,-460.667],[-167.833,464],[-191.667,498.354],[-324.167,568.833],[-347.75,544.583],[-347.333,-540.5],[-321.667,-565.333],[-190,-493.833]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-127,-459],[-127,462],[-156,501],[-313.5,569],[-342.5,540],[-342.5,-539.5],[-313.5,-568.5],[-156,-498]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-89.667,-464.667],[-89.667,467.333],[-118.667,503],[-308.667,571.333],[-337.667,542.333],[-337.667,-541.333],[-308.667,-570.333],[-118.667,-500.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-54.833,-470.333],[-54.833,472.667],[-83.833,505],[-303.833,573.667],[-332.833,544.667],[-332.833,-543.167],[-303.833,-572.167],[-83.833,-502.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[-24,-476],[-24,478],[-53,507],[-299,576],[-328,547],[-328,-545],[-299,-574],[-53,-505]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[6.073,-479.4],[6.073,481.5],[-22.927,510.5],[-297.12,577.1],[-326.12,548.1],[-326.12,-546.2],[-297.12,-575.2],[-22.927,-508.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[32.647,-482.8],[32.647,485],[3.647,514],[-295.24,578.2],[-324.24,549.2],[-324.24,-547.4],[-295.24,-576.4],[3.647,-511.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[57.22,-486.2],[57.22,488.5],[28.22,517.5],[-293.36,579.3],[-322.36,550.3],[-322.36,-548.6],[-293.36,-577.6],[28.22,-515.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":96.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[79.46,-489.6],[79.46,492],[50.46,521],[-291.48,580.4],[-320.48,551.4],[-320.48,-549.8],[-291.48,-578.8],[50.46,-518.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[99.7,-493],[99.7,495.5],[70.7,524.5],[-289.6,581.5],[-318.6,552.5],[-318.6,-551],[-289.6,-580],[70.7,-522]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":99.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[136.58,-499.8],[136.58,502.5],[107.58,531.5],[-285.84,583.7],[-314.84,554.7],[-314.84,-553.4],[-285.84,-582.4],[107.58,-528.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[179.4,-510],[179.4,513],[150.4,542],[-280.2,587],[-309.2,558],[-309.2,-557],[-280.2,-586],[150.4,-539]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[201.28,-516],[201.28,518.8],[172.28,547.8],[-279.44,588.2],[-308.44,559.2],[-308.44,-558],[-279.44,-587],[172.28,-545]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":104.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[212.053,-519],[212.053,521.7],[183.053,550.7],[-279.06,588.8],[-308.06,559.8],[-308.06,-558.5],[-279.06,-587.5],[183.053,-548]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[220.827,-522],[220.827,524.6],[191.827,553.6],[-278.68,589.4],[-307.68,560.4],[-307.68,-559],[-278.68,-588],[191.827,-551]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[229.1,-525],[229.1,527.5],[200.1,556.5],[-278.3,590],[-307.3,561],[-307.3,-559.5],[-278.3,-588.5],[200.1,-554]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[256.46,-535.4],[256.46,537.5],[227.46,566.5],[-276.78,592.4],[-305.78,563.4],[-305.78,-561.5],[-276.78,-590.5],[227.46,-564.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":110,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[260.8,-538],[260.8,540],[231.8,569],[-276.4,593],[-305.4,564],[-305.4,-562],[-276.4,-591],[231.8,-567]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":112.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[273.82,-543.7],[273.82,546],[244.82,575],[-276.16,594.2],[-305.16,565.2],[-305.16,-562.6],[-276.16,-591.6],[244.82,-572.7]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":114.166,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[280.833,-547.5],[280.833,550],[251.833,579],[-276,595],[-305,566],[-305,-563],[-276,-592],[251.833,-576.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118.334,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[294.867,-555],[294.867,558],[265.867,587],[-275.6,597],[-304.6,568],[-304.6,-564],[-275.6,-593],[265.867,-584]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":122.5,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[301.9,-559.5],[301.9,563],[272.9,592],[-275.7,597],[-304.7,568],[-304.7,-565],[-275.7,-594],[272.9,-588.5]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[306.933,-564],[306.933,568],[277.933,597],[-275.8,597],[-304.8,568],[-304.8,-566],[-275.8,-595],[277.933,-593]],"c":true}]},{"t":135,"s":[{"i":[[0,-16.016],[0,0],[16.016,0],[0,0],[0,16.016],[0,0],[-16.016,0],[0,0]],"o":[[0,0],[0,16.016],[0,0],[-16.016,0],[0,0],[0,-16.016],[0,0],[16.016,0]],"v":[[310,-568],[310,570],[281,599],[-276,599],[-305,570],[-305,-568],[-276,-597],[281,-597]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[384,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[101.75,101.75],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":87,"op":342,"st":60,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"CENTER_SCREEN 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[699,-539],[699,539],[653,585],[-0.999,585],[-653,585],[-699,539],[-699,-539],[-653,-585],[1,-585],[653,-585]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":64.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[707,-547],[707,547],[661,593],[-0.999,585],[-639.273,577],[-685.273,531],[-685.273,-527],[-639.273,-573],[1,-585],[661,-593]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":68.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[715,-563],[715,567],[669,613],[-0.999,585],[-617.545,561],[-663.545,515],[-663.545,-511],[-617.545,-557],[1,-585],[669,-609]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[709,-577.4],[709,579],[663,625],[-0.999,585],[-587.709,551.4],[-636.709,505.4],[-636.709,-501.4],[-587.709,-547.4],[1,-585],[663,-623.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":72.5,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[705,-587],[705,587],[659,633],[-0.999,585],[-567.818,545],[-613.818,499],[-613.818,-495],[-567.818,-541],[1,-585],[659,-633]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[697.4,-593.4],[697.4,595],[651.4,641],[-0.999,585],[-553.873,539.4],[-599.873,493.4],[-599.873,-490.2],[-553.873,-536.2],[1,-585],[651.4,-639.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":74.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[693.8,-599.8],[693.8,603],[647.8,649],[-0.999,585],[-537.927,533.8],[-583.927,487.8],[-583.927,-485.4],[-537.927,-531.4],[1,-585],[647.8,-645.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[678.2,-606.2],[678.2,611],[632.2,657],[-0.999,585],[-519.982,528.2],[-565.982,482.2],[-565.982,-480.6],[-519.982,-526.6],[1,-585],[632.2,-652.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[666.6,-612.6],[666.6,619],[620.6,665],[-0.999,585],[-499.036,522.6],[-545.036,476.6],[-545.036,-475.8],[-499.036,-521.8],[1,-585],[620.6,-658.6]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.405,0],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-25.405,0],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[647,-619],[647,627],[601,673],[-0.999,585],[-478.091,517],[-524.091,471],[-524.091,-471],[-478.091,-517],[1,-585],[601,-665]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":78.334,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.223,2.5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-22.441,-1.8],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[600.891,-638.2],[600.891,649.545],[561.618,691.182],[-5.908,586.273],[-428.856,507],[-467.174,466.273],[-467.174,-463],[-420.674,-508.5],[1,-585.6],[554.891,-684.2]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.132,3.75],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-20.96,-2.7],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[561.836,-647.8],[561.836,660.818],[525.927,700.273],[-8.363,586.909],[-398.739,502],[-433.216,463.909],[-433.216,-459],[-386.466,-504.25],[1,-585.9],[515.836,-693.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-25.041,5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-19.478,-3.6],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[522.782,-657.4],[522.782,672.091],[490.236,709.364],[-10.817,587.546],[-368.621,497],[-399.258,461.546],[-399.258,-455],[-352.258,-500],[1,-586.2],[476.782,-703.4]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[0,-25.405],[0,0],[25.405,0],[0,0],[0,0],[0,25.405],[0,0],[-24.95,6.25],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-17.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[25.405,0]],"v":[[471.727,-667],[471.727,683.364],[442.545,718.455],[-13.272,588.182],[-332.504,492],[-359.3,459.182],[-359.3,-451],[-312.05,-495.75],[1,-586.5],[425.727,-713]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[0.129,-24.588],[0,0],[21.663,1.508],[0,0],[0,0],[0.008,23.224],[0,0],[-21.2,5.875],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-15.329,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[21.8,-2.083]],"v":[[412.352,-679.333],[412.352,694.197],[387.295,726.538],[-16.188,588.015],[-289.754,488.25],[-312.675,457.182],[-312.675,-449],[-272.55,-491.375],[-4.583,-587],[372.894,-720.667]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[0.258,-23.77],[0,0],[17.922,3.015],[0,0],[0,0],[0.017,21.043],[0,0],[-17.45,5.5],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-12.663,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[18.194,-4.167]],"v":[[344.977,-691.667],[344.977,705.03],[324.045,734.621],[-19.105,587.849],[-247.004,484.5],[-266.05,455.182],[-266.05,-447],[-233.05,-487],[-10.166,-587.5],[312.06,-728.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[0.386,-22.953],[0,0],[14.18,4.523],[0,0],[0,0],[0.025,18.862],[0,0],[-13.7,5.125],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-9.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[14.589,-6.25]],"v":[[269.602,-704],[269.602,715.864],[252.795,742.705],[-22.022,587.682],[-204.254,480.75],[-219.425,453.182],[-219.425,-445],[-193.55,-482.625],[-15.75,-588],[243.227,-736]],"c":true}]},{"t":85.833984375,"s":[{"i":[[0.773,-20.5],[0,0],[2.955,9.045],[0,0],[0,0],[0.05,12.318],[0,0],[-2.45,4],[0,0],[0,0]],"o":[[0,0],[0,25.405],[0,0],[0,0],[-1.996,-4.5],[0,0],[0,-25.405],[0,0],[0,0],[3.773,-12.5]],"v":[[13.477,-707],[13.477,713.364],[9.045,731.955],[-30.772,587.182],[-58.004,481.5],[-61.55,459.182],[-61.55,-451],[-57.05,-481.5],[-32.5,-581.5],[6.727,-725]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-3,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":87,"st":60,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"FOLDABLE_BODY 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206.312,149.969,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[19.95,19.95,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":60,"s":[{"i":[[0,-40.869],[0,0],[40.869,0],[0,0],[0,0],[0,40.869],[0,0],[-40.869,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[-40.869,0],[0,0],[0,-40.869],[0,0],[0,0],[40.869,0]],"v":[[733,-567],[733,567],[659,641],[5,643],[-659,641],[-733,567],[-733,-567],[-659,-641],[3.001,-641],[659,-641]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":65,"s":[{"i":[[0,-40.869],[0,0],[40.869,0],[0,0],[0,0],[-0.091,49.495],[0,0],[-40.869,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[-46.341,0.245],[0,0],[-1.795,-49.895],[0,0],[0,0],[40.869,0]],"v":[[748.332,-581.845],[747.391,584.136],[673.391,658.136],[5,644.125],[-640.409,628.505],[-714.409,554.505],[-714.455,-550.855],[-640.455,-627.105],[3.001,-643.25],[674.332,-655.845]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":69.166,"s":[{"i":[[0,-40.869],[0,0],[40.869,0],[0,0],[0,0],[0,40.869],[0,0],[-40.869,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[-40.869,0],[0,0],[0,-40.869],[0,0],[0,0],[40.869,0]],"v":[[755.15,-598.8],[754.8,603],[680.8,677],[5,643],[-610.25,613.05],[-684.25,539.05],[-685.25,-537.4],[-611.25,-611.4],[3.001,-641],[681.15,-672.8]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":70.834,"s":[{"i":[[0,-40.869],[0,0],[42.179,0.978],[0,0],[0,0],[0,40.869],[0,0],[-43.221,1.138],[0,0],[0,0]],"o":[[0,0],[-0.542,42.899],[0,0],[0,0],[-46.299,-2.698],[0,0],[0,-40.869],[0,0],[0,0],[40.869,0]],"v":[[752.228,-610.767],[752.022,614.022],[675.022,688.422],[5,642.2],[-587.372,604.128],[-663.797,530.128],[-665.175,-528.378],[-588.75,-602.378],[3.001,-641],[678.228,-684.767]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":73.334,"s":[{"i":[[0,-40.869],[0,0],[44.144,2.444],[0,0],[0,0],[0,40.869],[0,0],[-46.75,2.844],[0,0],[0,0]],"o":[[0,0],[-1.356,45.944],[0,0],[0,0],[-54.444,-6.745],[0,0],[0,-40.869],[0,0],[0,0],[40.869,0]],"v":[[747.844,-628.717],[747.856,630.556],[666.356,705.556],[5,641],[-553.056,590.745],[-625.618,516.745],[-627.562,-514.844],[-555,-588.844],[3.001,-641],[673.844,-702.717]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":75,"s":[{"i":[[0,-40.869],[0,0],[42.507,1.222],[0,0],[0,0],[0,40.869],[0,0],[-50.375,3.922],[0,0],[0,0]],"o":[[0,0],[-0.678,43.407],[0,0],[0,0],[-54.222,-7.622],[0,0],[0,-40.869],[0,0],[0,0],[46.435,-1.875]],"v":[[734.172,-645.858],[734.428,648.778],[650.678,723.278],[5,642.75],[-513.528,581.122],[-590.559,507.372],[-591.531,-504.922],[-514.5,-578.922],[3.001,-641.875],[649.172,-720.233]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":76.666,"s":[{"i":[[0,-40.869],[0,0],[40.869,0],[0,0],[0,0],[0,40.869],[0,0],[-54,5],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[-54,-8.5],[0,0],[0,-40.869],[0,0],[0,0],[52,-3.75]],"v":[[708.5,-663],[709,667],[635,741],[5,644.5],[-474,571.5],[-545.5,498],[-545.5,-495],[-474,-569],[3.001,-642.75],[624.5,-737.75]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":79.166,"s":[{"i":[[0.9,-49.498],[0,0],[45.297,5.4],[0,0],[0,0],[0,40.869],[0,0],[-40.05,6.8],[0,0],[0,0]],"o":[[0,0],[0.3,47.208],[0,0],[0,0],[-39.15,-8.5],[0,0],[-0.3,-34.008],[0,0],[0,0],[52.45,-11.925]],"v":[[636.05,-692.05],[634.9,699.675],[545.45,770.9],[-7.675,640.525],[-400.05,552.55],[-455.15,479.65],[-453.6,-480.1],[-404,-549.2],[-14.199,-644.325],[537.55,-767.925]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":80.834,"s":[{"i":[[1.5,-55.25],[0,0],[48.25,9],[0,0],[0,0],[0,40.869],[0,0],[-30.75,8],[0,0],[0,0]],"o":[[0,0],[0.5,51.435],[0,0],[0,0],[-29.25,-8.5],[0,0],[-0.5,-29.435],[0,0],[0,0],[52.75,-17.375]],"v":[[549,-717.25],[549.25,723.125],[453.25,792.5],[-16.125,637.875],[-330.75,540.75],[-370.75,480.75],[-372.75,-481],[-331.5,-538.5],[-21.499,-639.125],[448.75,-787.625]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":81.666,"s":[{"i":[[2.15,-55.283],[0,0],[43.55,12.75],[0,0],[0,0],[-0.25,36.729],[0,0],[-24.85,7.933],[0,0],[0,0]],"o":[[0,0],[1.8,55.206],[0,0],[0,0],[-23.033,-8.15],[0,0],[-0.6,-27.148],[0,0],[0,0],[50.633,-18.367]],"v":[[493.267,-729.3],[493.367,733.5],[388.433,800.9],[-21.017,638.133],[-291.55,534.233],[-324,473.767],[-324.933,-478.317],[-290.983,-532.1],[-25.783,-636.917],[386.317,-797.433]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":82.5,"s":[{"i":[[2.8,-55.317],[0,0],[38.85,16.5],[0,0],[0,0],[-0.5,32.59],[0,0],[-18.95,7.867],[0,0],[0,0]],"o":[[0,0],[3.1,58.978],[0,0],[0,0],[-16.817,-7.8],[0,0],[-0.7,-24.861],[0,0],[0,0],[48.517,-19.358]],"v":[[427.533,-741.35],[427.483,743.875],[323.617,809.3],[-25.908,638.392],[-252.35,527.717],[-277.25,466.783],[-277.117,-475.633],[-250.467,-525.7],[-30.066,-634.708],[323.883,-807.242]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":83.334,"s":[{"i":[[3.45,-55.35],[0,0],[34.15,20.25],[0,0],[0,0],[-0.75,28.45],[0,0],[-13.05,7.8],[0,0],[0,0]],"o":[[0,0],[4.4,62.75],[0,0],[0,0],[-10.6,-7.45],[0,0],[-0.8,-22.574],[0,0],[0,0],[46.4,-20.35]],"v":[[351.8,-753.4],[351.6,754.25],[258.8,817.7],[-30.8,638.65],[-213.15,521.2],[-230.5,459.8],[-229.3,-472.95],[-209.95,-519.3],[-34.349,-632.5],[261.45,-817.05]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":84.166,"s":[{"i":[[3.225,-52.425],[0,0],[29.45,24],[0,0],[0,0],[-0.375,34.66],[0,0],[-10.275,9.4],[0,0],[0,0]],"o":[[0,0],[2.7,62.375],[0,0],[0,0],[-7.55,-7.975],[0,0],[-0.9,-20.287],[0,0],[0,0],[45.7,-22.425]],"v":[[269.9,-765.45],[269.55,764.625],[176.9,819.85],[-34.025,634.95],[-163.325,517.6],[-176.25,463.65],[-175.65,-472.975],[-160.475,-516.65],[-39.674,-626.75],[180.475,-821.025]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85,"s":[{"i":[[3,-49.5],[0,0],[24.75,27.75],[0,0],[0,0],[0,40.869],[0,0],[-7.5,11],[0,0],[0,0]],"o":[[0,0],[1,62],[0,0],[0,0],[-4.5,-8.5],[0,0],[-1,-18],[0,0],[0,0],[45,-24.5]],"v":[[182,-777.5],[181.5,775],[95,822],[-37.25,631.25],[-113.5,514],[-122,467.5],[-122,-473],[-111,-514],[-44.999,-621],[99.5,-825]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":85.834,"s":[{"i":[[2.115,-52.053],[0,0],[14.076,24.655],[0,0],[0,0],[0.15,39.565],[0,0],[-4.448,8.548],[0,0],[0,0]],"o":[[0,0],[-2.465,27.536],[0,0],[0,0],[-2.458,-8.114],[0,0],[-0.9,-26.528],[0,0],[0,0],[26.131,-22.782]],"v":[[89.385,-789.28],[89.465,814.464],[14.257,825.512],[-39.14,629.206],[-64.364,505.574],[-68.567,459.152],[-66.85,-455.222],[-64.968,-503.548],[-33.506,-639.074],[16.369,-824.885]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":86.666,"s":[{"i":[[0.346,-57.159],[0,0],[-7.272,18.464],[0,0],[0,0],[0.451,36.956],[0,0],[1.656,3.645],[0,0],[0,0]],"o":[[0,0],[0.605,52.109],[0,0],[0,0],[1.626,-7.341],[0,0],[-0.7,-43.583],[0,0],[0,0],[-11.608,-19.345]],"v":[[-77.846,-794.841],[-76.605,801.391],[5.772,824.536],[14.08,628.118],[25.909,512.723],[30.299,466.457],[32.45,-470.667],[16.094,-533.645],[13.482,-630.223],[3.108,-827.655]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":87.5,"s":[{"i":[[0.346,-57.159],[0,0],[-7.272,18.464],[0,0],[0,0],[0.451,36.956],[0,0],[1.656,3.645],[0,0],[0,0]],"o":[[0,0],[0.605,52.109],[0,0],[0,0],[1.626,-7.341],[0,0],[-0.7,-43.583],[0,0],[0,0],[-11.608,-19.345]],"v":[[-161.846,-788.841],[-160.605,797.391],[-78.228,820.536],[14.08,628.118],[75.909,512.723],[80.299,466.457],[82.45,-470.667],[66.094,-533.645],[13.482,-630.223],[-80.892,-821.655]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":88.334,"s":[{"i":[[0.679,-54.879],[0,0],[-13.362,17.618],[0,0],[0,0],[0.601,35.652],[0,0],[2.96,5.097],[0,0],[0,0]],"o":[[0,0],[0.139,54.646],[0,0],[0,0],[3.668,-6.954],[0,0],[-0.709,-37.134],[0,0],[0,0],[-28.144,-20.461]],"v":[[-243.346,-774.288],[-241.973,784.854],[-150.304,818.382],[12.523,630.074],[120.379,515.297],[132.565,465.957],[134.267,-469.042],[115.459,-527.361],[14.143,-629.964],[-152.023,-818.206]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":89.166,"s":[{"i":[[1.012,-52.598],[0,0],[-19.453,16.773],[0,0],[0,0],[0.752,34.347],[0,0],[4.265,6.548],[0,0],[0,0]],"o":[[0,0],[-0.326,57.182],[0,0],[0,0],[5.71,-6.568],[0,0],[-0.718,-30.686],[0,0],[0,0],[-44.68,-21.576]],"v":[[-317.846,-759.735],[-316.341,772.318],[-229.381,816.227],[10.967,632.03],[164.848,517.871],[180.831,465.457],[182.083,-467.416],[164.824,-521.076],[14.803,-629.705],[-230.153,-814.758]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90,"s":[{"i":[[1.346,-50.318],[0,0],[-25.543,15.927],[0,0],[0,0],[0.902,33.043],[0,0],[5.57,8],[0,0],[0,0]],"o":[[0,0],[-0.791,59.718],[0,0],[0,0],[7.752,-6.182],[0,0],[-0.727,-24.237],[0,0],[0,0],[-61.216,-22.691]],"v":[[-385.346,-745.182],[-383.709,759.782],[-294.457,814.073],[9.41,633.986],[209.318,520.445],[226.598,464.957],[227.4,-465.791],[214.189,-514.791],[15.464,-629.445],[-294.284,-811.309]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":90.834,"s":[{"i":[[1.418,-49.133],[0,0],[-31.384,13.082],[0,0],[0,0],[0.677,35],[0,0],[7.748,7.5],[0,0],[0,0]],"o":[[0,0],[-0.457,57.887],[0,0],[0,0],[9.794,-5.795],[0,0],[-0.682,-25.276],[0,0],[0,0],[-56.377,-19.098]],"v":[[-443.237,-737.295],[-442.077,748.496],[-351.866,806.918],[10.729,633.609],[244.163,523.811],[267.781,467.033],[268.3,-467.923],[248.074,-518.673],[13.874,-629.811],[-352.623,-804.027]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":91.666,"s":[{"i":[[1.491,-47.948],[0,0],[-37.224,10.236],[0,0],[0,0],[0.451,36.956],[0,0],[9.927,7],[0,0],[0,0]],"o":[[0,0],[-0.123,56.057],[0,0],[0,0],[11.836,-5.409],[0,0],[-0.636,-26.316],[0,0],[0,0],[-51.538,-15.505]],"v":[[-496.127,-729.409],[-495.445,737.209],[-404.276,799.764],[12.047,633.232],[279.007,527.177],[306.964,469.109],[307.2,-470.055],[281.96,-522.555],[12.285,-630.177],[-405.962,-796.745]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":92.5,"s":[{"i":[[1.564,-46.762],[0,0],[-43.065,7.391],[0,0],[0,0],[0.226,38.913],[0,0],[12.105,6.5],[0,0],[0,0]],"o":[[0,0],[0.211,54.226],[0,0],[0,0],[13.878,-5.023],[0,0],[-0.591,-27.356],[0,0],[0,0],[-46.699,-11.911]],"v":[[-539.018,-721.523],[-538.814,725.923],[-446.685,792.609],[13.365,632.855],[313.852,530.543],[342.647,471.185],[342.6,-472.186],[315.845,-526.436],[10.695,-630.543],[-449.301,-789.464]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":93.334,"s":[{"i":[[1.636,-45.577],[0,0],[-48.906,4.545],[0,0],[0,0],[0,40.869],[0,0],[14.283,6],[0,0],[0,0]],"o":[[0,0],[0.545,52.395],[0,0],[0,0],[15.919,-4.636],[0,0],[-0.545,-28.395],[0,0],[0,0],[-41.86,-8.318]],"v":[[-576.909,-713.636],[-577.182,714.636],[-484.094,785.455],[14.684,632.477],[348.697,533.909],[377.33,473.261],[377,-474.318],[349.731,-530.318],[9.106,-630.909],[-487.64,-782.182]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":94.166,"s":[{"i":[[1.5,-45.185],[0,0],[-48.199,4.167],[0,0],[0,0],[0,40.869],[0,0],[16.461,5.5],[0,0],[0,0]],"o":[[0,0],[0.5,51.435],[0,0],[0,0],[17.961,-4.25],[0,0],[-0.5,-29.435],[0,0],[0,0],[-41.74,-7.625]],"v":[[-609.5,-705.25],[-609.25,706.583],[-516.07,777.667],[13.048,633.104],[372.373,539.146],[405.552,476.99],[405.333,-478.125],[373.571,-535.625],[8.099,-632],[-520.404,-774.333]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":95.834,"s":[{"i":[[1.227,-44.4],[0,0],[-46.785,3.409],[0,0],[0,0],[0,40.869],[0,0],[20.818,4.5],[0,0],[0,0]],"o":[[0,0],[0.409,49.514],[0,0],[0,0],[22.045,-3.477],[0,0],[-0.409,-31.514],[0,0],[0,0],[-41.501,-6.239]],"v":[[-659.682,-688.477],[-658.386,690.477],[-565.023,762.091],[9.776,634.358],[419.724,549.619],[461.997,484.446],[462,-485.739],[421.25,-546.239],[6.087,-634.182],[-570.932,-758.636]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":97.5,"s":[{"i":[[0.955,-43.615],[0,0],[-45.371,2.652],[0,0],[0,0],[0,40.869],[0,0],[25.175,3.5],[0,0],[0,0]],"o":[[0,0],[0.318,47.593],[0,0],[0,0],[26.129,-2.705],[0,0],[-0.318,-33.592],[0,0],[0,0],[-41.261,-4.852]],"v":[[-693.197,-672.705],[-692.189,674.705],[-601.975,746.515],[6.505,635.612],[457.076,558.093],[507.109,489.902],[506.667,-490.686],[457.596,-554.186],[4.075,-633.03],[-608.126,-744.273]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":98.334,"s":[{"i":[[0.818,-43.223],[0,0],[-44.664,2.273],[0,0],[0,0],[0,40.869],[0,0],[27.353,3],[0,0],[0,0]],"o":[[0,0],[0.273,46.632],[0,0],[0,0],[28.171,-2.318],[0,0],[-0.273,-34.632],[0,0],[0,0],[-41.142,-4.159]],"v":[[-705.455,-664.818],[-704.591,666.818],[-615.951,738.727],[4.869,636.239],[475.752,562.33],[526.665,492.631],[526,-493.159],[475.769,-558.159],[3.069,-632.455],[-622.224,-737.091]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100,"s":[{"i":[[0.545,-42.438],[0,0],[-43.251,1.515],[0,0],[0,0],[0,40.869],[0,0],[31.71,2],[0,0],[0,0]],"o":[[0,0],[0.182,44.711],[0,0],[0,0],[32.255,-1.545],[0,0],[-0.182,-36.711],[0,0],[0,0],[-40.902,-2.773]],"v":[[-723.303,-651.879],[-722.727,654.212],[-635.57,726.485],[1.598,637.492],[498.104,569.803],[562.443,499.754],[561.667,-498.773],[497.782,-566.773],[1.056,-632.97],[-643.418,-724.727]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":100.834,"s":[{"i":[[0.409,-42.046],[0,0],[-42.544,1.136],[0,0],[0,0],[0,40.869],[0,0],[33.888,1.5],[0,0],[0,0]],"o":[[0,0],[0.136,43.75],[0,0],[0,0],[34.297,-1.159],[0,0],[-0.136,-37.751],[0,0],[0,0],[-40.782,-2.08]],"v":[[-731.727,-645.409],[-731.295,647.909],[-644.879,720.364],[-0.038,638.119],[509.28,573.54],[577.332,503.315],[576.5,-501.58],[508.788,-571.08],[0.05,-633.227],[-653.516,-718.545]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":101.666,"s":[{"i":[[0.273,-41.654],[0,0],[-41.837,0.758],[0,0],[0,0],[0,40.869],[0,0],[36.066,1],[0,0],[0,0]],"o":[[0,0],[0.091,42.79],[0,0],[0,0],[36.339,-0.773],[0,0],[-0.091,-38.79],[0,0],[0,0],[-40.663,-1.386]],"v":[[-737.152,-638.939],[-736.864,641.606],[-651.189,714.242],[-1.674,638.746],[520.456,577.277],[590.222,506.877],[589.333,-504.386],[519.795,-575.386],[-0.956,-633.485],[-660.613,-712.364]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":103.334,"s":[{"i":[[0,-40.869],[0,0],[-40.423,0],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[40.423,0],[0,0],[0,-40.869],[0,0],[0,0],[-40.423,0]],"v":[[-744,-626],[-744,629],[-659.808,702],[-4.946,640],[542.808,584.75],[616,514],[615,-510],[541.808,-584],[-2.968,-634],[-670.808,-700]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":105.834,"s":[{"i":[[0,-40.869],[0,0],[-40.423,0],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[40.423,0],[0,0],[0,-40.869],[0,0],[0,0],[-40.423,0]],"v":[[-744.842,-614.959],[-744.6,619.497],[-661.426,691.301],[-2.779,639.354],[564.646,592.557],[643.41,522.301],[642.956,-517.867],[564.192,-591.867],[-2.968,-634.219],[-671.649,-688.959]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":109.166,"s":[{"i":[[0,-40.869],[0,0],[-40.423,0],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[40.423,0],[0,0],[0,-40.869],[0,0],[0,0],[-40.423,0]],"v":[[-745.964,-600.237],[-745.4,606.826],[-663.584,677.035],[0.11,638.493],[593.764,602.967],[672.957,533.369],[673.23,-528.356],[594.037,-602.356],[-2.968,-634.512],[-672.771,-674.237]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":111.666,"s":[{"i":[[0,-40.869],[0,0],[-40.423,0],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[40.423,0],[0,0],[0,-40.869],[0,0],[0,0],[-40.423,0]],"v":[[-746.806,-589.196],[-746,597.323],[-665.202,666.336],[2.276,637.847],[615.603,610.775],[688.795,541.67],[689.614,-536.222],[616.422,-610.222],[-2.968,-634.731],[-673.613,-663.196]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":118,"s":[{"i":[[0,-40.869],[0,0],[-46.482,1.895],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[-1,44.868],[0,0],[0,0],[40.423,0],[0,0],[-0.105,-46.5],[0,0],[0,0],[-40.423,0]],"v":[[-736,-575.053],[-735,579.632],[-656.018,651.105],[8.054,637.474],[642.439,625.645],[714.632,557.105],[715.105,-550],[641.913,-624],[-2.968,-635.316],[-662.808,-649.053]],"c":true}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":126,"s":[{"i":[[0,-40.869],[0,0],[-44.048,1],[0,0],[0,0],[3,43.078],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[43.733,1],[0,0],[1.328,-42.15],[0,0],[0,0],[-40.423,0]],"v":[[-725.575,-563.749],[-725.75,566.434],[-649.952,640.197],[0.904,637.851],[657.767,633.903],[730.959,560.672],[730.922,-559.6],[657.73,-633.6],[-2.968,-638.442],[-656.133,-637.749]],"c":true}]},{"t":135,"s":[{"i":[[0,-40.869],[0,0],[-40.423,0],[0,0],[0,0],[0,40.869],[0,0],[40.423,0],[0,0],[0,0]],"o":[[0,0],[0,40.869],[0,0],[0,0],[40.423,0],[0,0],[0,-40.869],[0,0],[0,0],[-40.423,0]],"v":[[-725,-571],[-725.945,569],[-652.753,640],[-5.891,640],[660.862,640],[734.055,569],[735,-571],[661.808,-639],[-2.968,-639],[-651.808,-639]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.372549027205,0.388235300779,0.407843142748,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-3,-1],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":386,"st":60,"bm":10}],"markers":[]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-h700dp/dimens.xml b/packages/SystemUI/res/values-h700dp/dimens.xml
new file mode 100644
index 0000000..055308f
--- /dev/null
+++ b/packages/SystemUI/res/values-h700dp/dimens.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <!-- Margin above the ambient indication container -->
+    <dimen name="ambient_indication_container_margin_top">15dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-h800dp/dimens.xml b/packages/SystemUI/res/values-h800dp/dimens.xml
index 8efd6f0..3a71994 100644
--- a/packages/SystemUI/res/values-h800dp/dimens.xml
+++ b/packages/SystemUI/res/values-h800dp/dimens.xml
@@ -17,4 +17,7 @@
 <resources>
     <!-- With the large clock, move up slightly from the center -->
     <dimen name="keyguard_large_clock_top_margin">-112dp</dimen>
+
+    <!-- Margin above the ambient indication container -->
+    <dimen name="ambient_indication_container_margin_top">20dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index 49ef330..fff2544 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -40,6 +40,10 @@
     <dimen name="biometric_dialog_button_negative_max_width">140dp</dimen>
     <dimen name="biometric_dialog_button_positive_max_width">116dp</dimen>
 
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
     <dimen name="global_actions_power_dialog_item_height">130dp</dimen>
     <dimen name="global_actions_power_dialog_item_bottom_margin">35dp</dimen>
 
diff --git a/packages/SystemUI/res/values-land/styles.xml b/packages/SystemUI/res/values-land/styles.xml
index aefd998..a0e721e 100644
--- a/packages/SystemUI/res/values-land/styles.xml
+++ b/packages/SystemUI/res/values-land/styles.xml
@@ -29,11 +29,11 @@
 
     <style name="AuthCredentialPatternContainerStyle">
         <item name="android:gravity">center</item>
-        <item name="android:maxHeight">320dp</item>
-        <item name="android:maxWidth">320dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:paddingHorizontal">60dp</item>
+        <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:paddingHorizontal">32dp</item>
         <item name="android:paddingVertical">20dp</item>
     </style>
 
diff --git a/packages/SystemUI/res/values-night/colors.xml b/packages/SystemUI/res/values-night/colors.xml
index 16152f8..08e1bf2 100644
--- a/packages/SystemUI/res/values-night/colors.xml
+++ b/packages/SystemUI/res/values-night/colors.xml
@@ -78,9 +78,6 @@
     <color name="biometric_dialog_accent">@color/material_dynamic_primary70</color>
     <color name="biometric_dialog_error">#fff28b82</color> <!-- red 300 -->
 
-    <!-- UDFPS colors -->
-    <color name="udfps_enroll_icon">#7DA7F1</color>
-
     <color name="GM2_green_500">#FF41Af6A</color>
     <color name="GM2_blue_500">#5195EA</color>
     <color name="GM2_red_500">#E25142</color>
@@ -103,4 +100,13 @@
     <color name="accessibility_floating_menu_message_text">@*android:color/primary_text_default_material_dark</color>
 
     <color name="people_tile_background">@color/material_dynamic_secondary20</color>
+
+    <!-- UDFPS colors -->
+    <color name="udfps_enroll_icon">#7DA7F1</color>
+    <color name="udfps_moving_target_fill">#475670</color>
+    <!-- 50% of udfps_moving_target_fill-->
+    <color name="udfps_moving_target_fill_error">#80475670</color>
+    <color name="udfps_enroll_progress">#7DA7F1</color>
+    <color name="udfps_enroll_progress_help">#607DA7F1</color>
+    <color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
 </resources>
diff --git a/packages/SystemUI/res/values-sw360dp/dimens.xml b/packages/SystemUI/res/values-sw360dp/dimens.xml
index 65ca70b..03365b3 100644
--- a/packages/SystemUI/res/values-sw360dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw360dp/dimens.xml
@@ -25,5 +25,8 @@
 
     <!-- Home Controls -->
     <dimen name="global_actions_side_margin">12dp</dimen>
+
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw392dp-land/dimens.xml b/packages/SystemUI/res/values-sw392dp-land/dimens.xml
new file mode 100644
index 0000000..1e26a69
--- /dev/null
+++ b/packages/SystemUI/res/values-sw392dp-land/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">248dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw392dp/dimens.xml b/packages/SystemUI/res/values-sw392dp/dimens.xml
index 78279ca..96af3c1 100644
--- a/packages/SystemUI/res/values-sw392dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw392dp/dimens.xml
@@ -24,5 +24,8 @@
 
     <!-- Home Controls -->
     <dimen name="global_actions_side_margin">16dp</dimen>
+
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">298dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw410dp-land/dimens.xml b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
new file mode 100644
index 0000000..c4d9b9b
--- /dev/null
+++ b/packages/SystemUI/res/values-sw410dp-land/dimens.xml
@@ -0,0 +1,21 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <!-- Lock pattern view size, align sysui biometric_auth_pattern_view_size -->
+    <dimen name="biometric_auth_pattern_view_size">248dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw410dp/dimens.xml b/packages/SystemUI/res/values-sw410dp/dimens.xml
index 7da47e5..ff6e005 100644
--- a/packages/SystemUI/res/values-sw410dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw410dp/dimens.xml
@@ -27,4 +27,6 @@
     <dimen name="global_actions_grid_item_side_margin">12dp</dimen>
     <dimen name="global_actions_grid_item_height">72dp</dimen>
 
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp-land/styles.xml b/packages/SystemUI/res/values-sw600dp-land/styles.xml
index 8148d3d..5ca2b43 100644
--- a/packages/SystemUI/res/values-sw600dp-land/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/styles.xml
@@ -16,16 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="AuthCredentialPatternContainerStyle">
-        <item name="android:gravity">center</item>
-        <item name="android:maxHeight">420dp</item>
-        <item name="android:maxWidth">420dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:paddingHorizontal">120dp</item>
-        <item name="android:paddingVertical">40dp</item>
-    </style>
-
     <style name="TextAppearance.AuthNonBioCredential.Title">
         <item name="android:fontFamily">google-sans</item>
         <item name="android:layout_marginTop">16dp</item>
diff --git a/packages/SystemUI/res/values-sw600dp-port/styles.xml b/packages/SystemUI/res/values-sw600dp-port/styles.xml
index 771de08..41d931d 100644
--- a/packages/SystemUI/res/values-sw600dp-port/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp-port/styles.xml
@@ -24,16 +24,6 @@
         <item name="android:layout_gravity">top</item>
     </style>
 
-    <style name="AuthCredentialPatternContainerStyle">
-        <item name="android:gravity">center</item>
-        <item name="android:maxHeight">420dp</item>
-        <item name="android:maxWidth">420dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:paddingHorizontal">180dp</item>
-        <item name="android:paddingVertical">80dp</item>
-    </style>
-
     <style name="TextAppearance.AuthNonBioCredential.Title">
         <item name="android:fontFamily">google-sans</item>
         <item name="android:layout_marginTop">24dp</item>
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 80628f9..f4434e8 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -36,7 +36,4 @@
     <integer name="qs_security_footer_maxLines">1</integer>
 
     <bool name="config_use_large_screen_shade_header">true</bool>
-
-    <!-- Whether to show the side fps hint while on bouncer -->
-    <bool name="config_show_sidefps_hint_on_bouncer">true</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 599bf30..9bc0dde 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -92,4 +92,6 @@
     <dimen name="lockscreen_shade_status_bar_transition_distance">@dimen/lockscreen_shade_full_transition_distance</dimen>
     <dimen name="lockscreen_shade_keyguard_transition_distance">@dimen/lockscreen_shade_media_transition_distance</dimen>
 
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 868c003..3fc59e3 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -35,6 +35,11 @@
          not appear immediately after user swipes to the side -->
     <dimen name="qs_tiles_page_horizontal_margin">20dp</dimen>
 
+    <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
+    <dimen name="qs_media_rec_icon_top_margin">27dp</dimen>
+    <dimen name="qs_media_rec_album_size">152dp</dimen>
+    <dimen name="qs_media_rec_album_side_margin">16dp</dimen>
+
     <dimen name="lockscreen_shade_max_over_scroll_amount">42dp</dimen>
 
     <!-- Roughly the same distance as media on LS to media on QS. We will translate by this value
diff --git a/packages/SystemUI/res/values-sw720dp-land/styles.xml b/packages/SystemUI/res/values-sw720dp-land/styles.xml
index f9ed67d..d9406d3 100644
--- a/packages/SystemUI/res/values-sw720dp-land/styles.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/styles.xml
@@ -16,16 +16,6 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="AuthCredentialPatternContainerStyle">
-        <item name="android:gravity">center</item>
-        <item name="android:maxHeight">420dp</item>
-        <item name="android:maxWidth">420dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:paddingHorizontal">120dp</item>
-        <item name="android:paddingVertical">40dp</item>
-    </style>
-
     <style name="TextAppearance.AuthNonBioCredential.Title">
         <item name="android:fontFamily">google-sans</item>
         <item name="android:layout_marginTop">16dp</item>
diff --git a/packages/SystemUI/res/values-sw720dp-port/styles.xml b/packages/SystemUI/res/values-sw720dp-port/styles.xml
index 78d299c..41d931d 100644
--- a/packages/SystemUI/res/values-sw720dp-port/styles.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/styles.xml
@@ -24,16 +24,6 @@
         <item name="android:layout_gravity">top</item>
     </style>
 
-    <style name="AuthCredentialPatternContainerStyle">
-        <item name="android:gravity">center</item>
-        <item name="android:maxHeight">420dp</item>
-        <item name="android:maxWidth">420dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:paddingHorizontal">240dp</item>
-        <item name="android:paddingVertical">120dp</item>
-    </style>
-
     <style name="TextAppearance.AuthNonBioCredential.Title">
         <item name="android:fontFamily">google-sans</item>
         <item name="android:layout_marginTop">24dp</item>
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index 0705017..927059a 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -22,5 +22,8 @@
     <dimen name="controls_padding_horizontal">75dp</dimen>
 
     <dimen name="large_screen_shade_header_height">56dp</dimen>
+
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw800dp/dimens.xml b/packages/SystemUI/res/values-sw800dp/dimens.xml
new file mode 100644
index 0000000..0d82217
--- /dev/null
+++ b/packages/SystemUI/res/values-sw800dp/dimens.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 44ba3f6..5b6c9d3 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -209,5 +209,15 @@
         <attr name="permissionGrantButtonTopStyle" format="reference"/>
         <attr name="permissionGrantButtonBottomStyle" format="reference"/>
     </declare-styleable>
+
+    <declare-styleable name="BiometricsEnrollView">
+        <attr name="biometricsEnrollStyle" format="reference" />
+        <attr name="biometricsEnrollIcon" format="reference|color" />
+        <attr name="biometricsMovingTargetFill" format="reference|color" />
+        <attr name="biometricsMovingTargetFillError" format="reference|color" />
+        <attr name="biometricsEnrollProgress" format="reference|color" />
+        <attr name="biometricsEnrollProgressHelp" format="reference|color" />
+        <attr name="biometricsEnrollProgressHelpWithTalkback" format="reference|color" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 6b4bea1..70d53c7 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -133,13 +133,16 @@
     <color name="biometric_dialog_accent">@color/material_dynamic_primary40</color>
     <color name="biometric_dialog_error">#ffd93025</color>                  <!-- red 600 -->
 
+    <!-- SFPS colors -->
+    <color name="sfps_chevron_fill">@color/material_dynamic_primary90</color>
+
     <!-- UDFPS colors -->
-    <color name="udfps_enroll_icon">#7DA7F1</color>
-    <color name="udfps_moving_target_fill">#475670</color>
+    <color name="udfps_enroll_icon">#699FF3</color>
+    <color name="udfps_moving_target_fill">#C2D7F7</color>
     <!-- 50% of udfps_moving_target_fill-->
-    <color name="udfps_moving_target_fill_error">#80475670</color>
-    <color name="udfps_enroll_progress">#7DA7F1</color>
-    <color name="udfps_enroll_progress_help">#607DA7F1</color>
+    <color name="udfps_moving_target_fill_error">#80C2D7F7</color>
+    <color name="udfps_enroll_progress">#699FF3</color>
+    <color name="udfps_enroll_progress_help">#70699FF3</color>
     <color name="udfps_enroll_progress_help_with_talkback">#FFEE675C</color>
 
     <!-- Floating overlay actions -->
@@ -257,4 +260,8 @@
     <color name="dream_overlay_clock_ambient_text_shadow_color">#4D000000</color>
     <color name="dream_overlay_status_bar_key_text_shadow_color">#66000000</color>
     <color name="dream_overlay_status_bar_ambient_text_shadow_color">#59000000</color>
+
+    <!-- Rear Display Education -->
+    <color name="rear_display_overlay_animation_background_color">#1E1B17</color>
+    <color name="rear_display_overlay_dialog_background_color">#1E1B17</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index b8e2caf..247e44d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -555,7 +555,7 @@
     <string name="config_preferredEmergencySosPackage" translatable="false"></string>
 
     <!-- Whether to show the side fps hint while on bouncer -->
-    <bool name="config_show_sidefps_hint_on_bouncer">false</bool>
+    <bool name="config_show_sidefps_hint_on_bouncer">true</bool>
 
     <!-- Whether to use the split 2-column notification shade -->
     <bool name="config_use_split_notification_shade">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 67e2248..dc7e4e4 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -403,6 +403,8 @@
         (quick_qs_offset_height (60dp)  - ongoing_appops_chip_height (24dp) ) / 2 -->
     <dimen name="notifications_top_padding_split_shade">18dp</dimen>
 
+    <dimen name="notifications_unseen_footer_icon_size">16dp</dimen>
+
     <!-- Height of the status bar header bar when on Keyguard -->
     <dimen name="status_bar_header_height_keyguard">40dp</dimen>
 
@@ -959,6 +961,10 @@
     <!-- Biometric Auth Credential values -->
     <dimen name="biometric_auth_icon_size">48dp</dimen>
 
+    <!-- Biometric Auth pattern view size, better to align keyguard_security_width -->
+    <dimen name="biometric_auth_pattern_view_size">348dp</dimen>
+    <dimen name="biometric_auth_pattern_view_max_size">348dp</dimen>
+
     <!-- Starting text size in sp of batteryLevel for wireless charging animation -->
     <item name="wireless_charging_anim_battery_level_text_size_start" format="float" type="dimen">
         0
@@ -1051,6 +1057,7 @@
     <dimen name="qs_media_session_collapsed_guideline">144dp</dimen>
 
     <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
+    <dimen name="qs_media_rec_icon_top_margin">16dp</dimen>
     <dimen name="qs_media_rec_album_size">88dp</dimen>
     <dimen name="qs_media_rec_album_side_margin">16dp</dimen>
     <dimen name="qs_media_rec_album_bottom_margin">8dp</dimen>
@@ -1177,7 +1184,7 @@
 
     <!-- Screen record dialog -->
     <dimen name="screenrecord_option_padding">18dp</dimen>
-    <dimen name="screenrecord_logo_size">26dp</dimen>
+    <dimen name="screenrecord_logo_size">30dp</dimen>
     <dimen name="screenrecord_option_icon_size">24dp</dimen>
     <!-- Screen record status bar icon -->
     <dimen name="screenrecord_status_text_size">14sp</dimen>
@@ -1185,6 +1192,18 @@
     <dimen name="screenrecord_status_icon_width">21dp</dimen>
     <dimen name="screenrecord_status_icon_height">17.5dp</dimen>
     <dimen name="screenrecord_status_icon_bg_radius">8dp</dimen>
+    <!-- Screen record spinner -->
+    <dimen name="screenrecord_spinner_height">72dp</dimen>
+    <dimen name="screenrecord_spinner_margin">24dp</dimen>
+    <dimen name="screenrecord_spinner_text_padding_start">20dp</dimen>
+    <dimen name="screenrecord_spinner_text_padding_end">80dp</dimen>
+    <dimen name="screenrecord_spinner_arrow_size">24dp</dimen>
+    <dimen name="screenrecord_spinner_background_radius">28dp</dimen>
+
+    <dimen name="screenrecord_title_margin_top">20dp</dimen>
+    <dimen name="screenrecord_warning_line_height">20dp</dimen>
+    <dimen name="screenrecord_options_padding_bottom">16dp</dimen>
+    <dimen name="screenrecord_buttons_margin_top">20dp</dimen>
 
     <!-- Keyguard user switcher -->
     <dimen name="kg_user_switcher_text_size">16sp</dimen>
@@ -1507,13 +1526,15 @@
     <dimen name="dream_overlay_status_bar_extra_margin">8dp</dimen>
 
     <!-- Dream overlay complications related dimensions -->
-    <dimen name="dream_overlay_complication_clock_time_text_size">86sp</dimen>
+    <dimen name="dream_overlay_complication_clock_time_text_size">86dp</dimen>
+    <dimen name="dream_overlay_complication_clock_time_translation_y">28dp</dimen>
     <dimen name="dream_overlay_complication_home_controls_padding">28dp</dimen>
     <dimen name="dream_overlay_complication_clock_subtitle_text_size">24sp</dimen>
     <dimen name="dream_overlay_complication_preview_text_size">36sp</dimen>
     <dimen name="dream_overlay_complication_preview_icon_padding">28dp</dimen>
     <dimen name="dream_overlay_complication_shadow_padding">2dp</dimen>
     <dimen name="dream_overlay_complication_smartspace_padding">24dp</dimen>
+    <dimen name="dream_overlay_complication_smartspace_max_width">408dp</dimen>
 
     <!-- The position of the end guide, which dream overlay complications can align their start with
          if their end is aligned with the parent end. Represented as the percentage over from the
@@ -1611,4 +1632,10 @@
     <dimen name="config_rounded_mask_size">0px</dimen>
     <dimen name="config_rounded_mask_size_top">0px</dimen>
     <dimen name="config_rounded_mask_size_bottom">0px</dimen>
+
+    <!-- Rear Display Education dimens -->
+    <dimen name="rear_display_animation_width">273dp</dimen>
+    <dimen name="rear_display_animation_height">200dp</dimen>
+    <dimen name="rear_display_title_top_padding">24dp</dimen>
+    <dimen name="rear_display_title_bottom_padding">16dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4cf09ab..a4e9983 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -200,6 +200,8 @@
 
     <!-- Informs the user that a screenshot is being saved. [CHAR LIMIT=50] -->
     <string name="screenshot_saving_title">Saving screenshot\u2026</string>
+    <!-- Informs the user that a screenshot is being saved. [CHAR LIMIT=50] -->
+    <string name="screenshot_saving_work_profile_title">Saving screenshot to work profile\u2026</string>
     <!-- Notification title displayed when a screenshot is saved to the Gallery. [CHAR LIMIT=50] -->
     <string name="screenshot_saved_title">Screenshot saved</string>
     <!-- Notification title displayed when we fail to take a screenshot. [CHAR LIMIT=50] -->
@@ -1103,6 +1105,12 @@
     <!-- Text which is shown in the notification shade when there are no notifications. [CHAR LIMIT=30] -->
     <string name="empty_shade_text">No notifications</string>
 
+    <!-- Text which is shown in the expanded notification shade when there are currently no notifications visible that the user hasn't already seen. [CHAR LIMIT=30] -->
+    <string name="no_unseen_notif_text">No new notifications</string>
+
+    <!-- Text which is shown in the locked notification shade when there are currently no notifications, but if the user were to unlock, notifications would appear. [CHAR LIMIT=40] -->
+    <string name="unlock_to_see_notif_text">Unlock to see older notifications</string>
+
     <!-- Disclosure at the bottom of Quick Settings that indicates that parental controls are enabled. [CHAR LIMIT=100] -->
     <string name="quick_settings_disclosure_parental_controls">This device is managed by your parent</string>
 
@@ -2847,4 +2855,17 @@
     shortcut button on the lock screen. [CHAR LIMIT=NONE].
     -->
     <string name="keyguard_affordance_enablement_dialog_home_instruction_2">&#8226; At least one device is available</string>
+
+    <!-- Text for education page of cancel button to hide the page. [CHAR_LIMIT=NONE] -->
+    <string name="rear_display_bottom_sheet_cancel">Cancel</string>
+    <!-- Text for the user to confirm they flipped the device around. [CHAR_LIMIT=NONE] -->
+    <string name="rear_display_bottom_sheet_confirm">Flip now</string>
+    <!-- Text for education page title to guide user to unfold phone. [CHAR_LIMIT=50] -->
+    <string name="rear_display_fold_bottom_sheet_title">Unfold phone for a better selfie</string>
+    <!-- Text for education page title to guide user to flip to the front display. [CHAR_LIMIT=50] -->
+    <string name="rear_display_unfold_bottom_sheet_title">Flip to front display for a better selfie?</string>
+    <!-- Text for education page description to suggest user to use rear selfie capture. [CHAR_LIMIT=NONE] -->
+    <string name="rear_display_bottom_sheet_description">Use the rear-facing camera for a wider photo with higher resolution.</string>
+    <!-- Text for education page description to warn user that the display will turn off if the button is clicked. [CHAR_LIMIT=NONE] -->
+    <string name="rear_display_bottom_sheet_warning"><b>&#x2731; This screen will turn off</b></string>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index fe4f639..aafa47f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -251,11 +251,12 @@
 
     <style name="AuthCredentialPatternContainerStyle">
         <item name="android:gravity">center</item>
-        <item name="android:maxHeight">420dp</item>
-        <item name="android:maxWidth">420dp</item>
-        <item name="android:minHeight">200dp</item>
-        <item name="android:minWidth">200dp</item>
-        <item name="android:padding">20dp</item>
+        <item name="android:maxHeight">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:maxWidth">@dimen/biometric_auth_pattern_view_max_size</item>
+        <item name="android:minHeight">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:minWidth">@dimen/biometric_auth_pattern_view_size</item>
+        <item name="android:paddingHorizontal">32dp</item>
+        <item name="android:paddingVertical">20dp</item>
     </style>
 
     <style name="AuthCredentialPinPasswordContainerStyle">
@@ -314,6 +315,10 @@
 
         <!-- Needed for MediaRoute chooser dialog -->
         <item name="*android:isLightTheme">false</item>
+
+        <!-- Biometrics enroll color style -->
+        <item name="biometricsEnrollStyle">@style/BiometricsEnrollStyle</item>
+
     </style>
 
     <style name="Theme.SystemUI.LightWallpaper">
@@ -1281,7 +1286,6 @@
         <item name="android:textSize">@dimen/broadcast_dialog_btn_text_size</item>
     </style>
 
-
     <!-- The style for log access consent dialog -->
     <style name="LogAccessDialogTheme" parent="@style/Theme.SystemUI.Dialog.Alert">
         <item name="permissionGrantButtonTopStyle">@style/PermissionGrantButtonTop</item>
@@ -1321,4 +1325,13 @@
         <item name="android:layout_marginBottom">2dp</item>
         <item name="android:background">@drawable/grant_permissions_buttons_bottom</item>
     </style>
+
+    <style name="BiometricsEnrollStyle">
+        <item name="biometricsEnrollIcon">@color/udfps_enroll_icon</item>
+        <item name="biometricsMovingTargetFill">@color/udfps_moving_target_fill</item>
+        <item name="biometricsMovingTargetFillError">@color/udfps_moving_target_fill_error</item>
+        <item name="biometricsEnrollProgress">@color/udfps_enroll_progress</item>
+        <item name="biometricsEnrollProgressHelp">@color/udfps_enroll_progress_help</item>
+        <item name="biometricsEnrollProgressHelpWithTalkback">@color/udfps_enroll_progress_help_with_talkback</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/res/xml/combined_qs_header_scene.xml b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
index de855e2..c32de70 100644
--- a/packages/SystemUI/res/xml/combined_qs_header_scene.xml
+++ b/packages/SystemUI/res/xml/combined_qs_header_scene.xml
@@ -124,20 +124,9 @@
         </KeyFrameSet>
     </Transition>
 
-    <Transition
-        android:id="@+id/large_screen_header_transition"
-        app:constraintSetStart="@id/large_screen_header_constraint"
-        app:constraintSetEnd="@id/large_screen_header_constraint"/>
+    <Include app:constraintSet="@xml/large_screen_shade_header"/>
 
-    <!--
-        Placeholder ConstraintSet. They are populated in the controller for this class.
-        This is needed because there's no easy way to just refer to a `ConstraintSet` file. The
-        options are either a layout file or inline the ConstraintSets.
-     -->
-    <ConstraintSet android:id="@id/qqs_header_constraint"/>
+    <Include app:constraintSet="@xml/qs_header"/>
 
-    <ConstraintSet android:id="@id/qs_header_constraint"/>
-
-    <ConstraintSet android:id="@id/large_screen_header_constraint" />
-
+    <Include app:constraintSet="@xml/qqs_header"/>
 </MotionScene>
diff --git a/packages/SystemUI/res/xml/qqs_header.xml b/packages/SystemUI/res/xml/qqs_header.xml
index 5d3650c..e56e5d5 100644
--- a/packages/SystemUI/res/xml/qqs_header.xml
+++ b/packages/SystemUI/res/xml/qqs_header.xml
@@ -59,7 +59,6 @@
         <Layout
             android:layout_width="wrap_content"
             android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
-            app:layout_constrainedWidth="true"
             app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
             app:layout_constraintStart_toEndOf="@id/date"
             app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
@@ -75,7 +74,6 @@
         <Layout
             android:layout_width="wrap_content"
             android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
-            app:layout_constrainedWidth="true"
             app:layout_constraintHeight_min="@dimen/new_qs_header_non_clickable_element_height"
             app:layout_constraintStart_toEndOf="@id/statusIcons"
             app:layout_constraintEnd_toEndOf="@id/end_guide"
@@ -112,5 +110,4 @@
             app:layout_constraintHorizontal_bias="1"
         />
     </Constraint>
-
 </ConstraintSet>
\ No newline at end of file
diff --git a/packages/SystemUI/res/xml/qs_header.xml b/packages/SystemUI/res/xml/qs_header.xml
index 982c422..eca2b2a 100644
--- a/packages/SystemUI/res/xml/qs_header.xml
+++ b/packages/SystemUI/res/xml/qs_header.xml
@@ -56,6 +56,7 @@
         <Layout
             android:layout_width="wrap_content"
             android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
+            app:layout_constrainedWidth="true"
             app:layout_constraintStart_toStartOf="parent"
             app:layout_constraintEnd_toStartOf="@id/space"
             app:layout_constraintBottom_toBottomOf="parent"
@@ -88,7 +89,6 @@
         <Layout
             android:layout_width="wrap_content"
             android:layout_height="@dimen/new_qs_header_non_clickable_element_height"
-            app:layout_constrainedWidth="true"
             app:layout_constraintStart_toEndOf="@id/space"
             app:layout_constraintEnd_toStartOf="@id/batteryRemainingIcon"
             app:layout_constraintTop_toTopOf="@id/date"
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
index 49cc483..e032bb9 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ExternalViewScreenshotTestRule.kt
@@ -34,13 +34,19 @@
 /**
  * A rule that allows to run a screenshot diff test on a view that is hosted in another activity.
  */
-class ExternalViewScreenshotTestRule(emulationSpec: DeviceEmulationSpec) : TestRule {
+class ExternalViewScreenshotTestRule(
+    emulationSpec: DeviceEmulationSpec,
+    assetPathRelativeToBuildRoot: String
+) : TestRule {
 
     private val colorsRule = MaterialYouColorsRule()
     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
     private val screenshotRule =
         ScreenshotTestRule(
-            SystemUIGoldenImagePathManager(getEmulatedDevicePathConfig(emulationSpec))
+            SystemUIGoldenImagePathManager(
+                getEmulatedDevicePathConfig(emulationSpec),
+                assetPathRelativeToBuildRoot
+            )
         )
     private val delegateRule =
         RuleChain.outerRule(colorsRule).around(deviceEmulationRule).around(screenshotRule)
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
index fafc774..72d8c5a 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/SystemUIGoldenImagePathManager.kt
@@ -23,11 +23,11 @@
 /** A [GoldenImagePathManager] that should be used for all SystemUI screenshot tests. */
 class SystemUIGoldenImagePathManager(
     pathConfig: PathConfig,
-    override val assetsPathRelativeToRepo: String = "tests/screenshot/assets"
+    assetsPathRelativeToBuildRoot: String
 ) :
     GoldenImagePathManager(
         appContext = InstrumentationRegistry.getInstrumentation().context,
-        assetsPathRelativeToRepo = assetsPathRelativeToRepo,
+        assetsPathRelativeToBuildRoot = assetsPathRelativeToBuildRoot,
         deviceLocalPath =
             InstrumentationRegistry.getInstrumentation()
                 .targetContext
diff --git a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
index 36ac1ff..6d0cc5e 100644
--- a/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
+++ b/packages/SystemUI/screenshot/src/com/android/systemui/testing/screenshot/ViewScreenshotTestRule.kt
@@ -44,17 +44,16 @@
     emulationSpec: DeviceEmulationSpec,
     private val matcher: BitmapMatcher = UnitTestBitmapMatcher,
     pathConfig: PathConfig = getEmulatedDevicePathConfig(emulationSpec),
-    assetsPathRelativeToRepo: String = ""
+    assetsPathRelativeToBuildRoot: String
 ) : TestRule {
     private val colorsRule = MaterialYouColorsRule()
     private val deviceEmulationRule = DeviceEmulationRule(emulationSpec)
     private val screenshotRule =
         ScreenshotTestRule(
-            if (assetsPathRelativeToRepo.isBlank()) {
-                SystemUIGoldenImagePathManager(pathConfig)
-            } else {
-                SystemUIGoldenImagePathManager(pathConfig, assetsPathRelativeToRepo)
-            }
+            SystemUIGoldenImagePathManager(
+                getEmulatedDevicePathConfig(emulationSpec),
+                assetsPathRelativeToBuildRoot
+            )
         )
     private val activityRule = ActivityScenarioRule(ScreenshotActivity::class.java)
     private val delegateRule =
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/keyguard/data/content/KeyguardQuickAffordanceProviderContract.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/keyguard/data/content/KeyguardQuickAffordanceProviderContract.kt
deleted file mode 100644
index 98d8d3e..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/keyguard/data/content/KeyguardQuickAffordanceProviderContract.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.shared.keyguard.data.content
-
-import android.content.ContentResolver
-import android.net.Uri
-
-/** Contract definitions for querying content about keyguard quick affordances. */
-object KeyguardQuickAffordanceProviderContract {
-
-    const val AUTHORITY = "com.android.systemui.keyguard.quickaffordance"
-    const val PERMISSION = "android.permission.ACCESS_KEYGUARD_QUICK_AFFORDANCES"
-
-    private val BASE_URI: Uri =
-        Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY).build()
-
-    /**
-     * Table for slots.
-     *
-     * Slots are positions where affordances can be placed on the lock screen. Affordances that are
-     * placed on slots are said to be "selected". The system supports the idea of multiple
-     * affordances per slot, though the implementation may limit the number of affordances on each
-     * slot.
-     *
-     * Supported operations:
-     * - Query - to know which slots are available, query the [SlotTable.URI] [Uri]. The result set
-     * will contain rows with the [SlotTable.Columns] columns.
-     */
-    object SlotTable {
-        const val TABLE_NAME = "slots"
-        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
-
-        object Columns {
-            /** String. Unique ID for this slot. */
-            const val ID = "id"
-            /** Integer. The maximum number of affordances that can be placed in the slot. */
-            const val CAPACITY = "capacity"
-        }
-    }
-
-    /**
-     * Table for affordances.
-     *
-     * Affordances are actions/buttons that the user can execute. They are placed on slots on the
-     * lock screen.
-     *
-     * Supported operations:
-     * - Query - to know about all the affordances that are available on the device, regardless of
-     * which ones are currently selected, query the [AffordanceTable.URI] [Uri]. The result set will
-     * contain rows, each with the columns specified in [AffordanceTable.Columns].
-     */
-    object AffordanceTable {
-        const val TABLE_NAME = "affordances"
-        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
-        const val ENABLEMENT_INSTRUCTIONS_DELIMITER = "]["
-        const val COMPONENT_NAME_SEPARATOR = "/"
-
-        object Columns {
-            /** String. Unique ID for this affordance. */
-            const val ID = "id"
-            /** String. User-visible name for this affordance. */
-            const val NAME = "name"
-            /**
-             * Integer. Resource ID for the drawable to load for this affordance. This is a resource
-             * ID from the system UI package.
-             */
-            const val ICON = "icon"
-            /** Integer. `1` if the affordance is enabled or `0` if it disabled. */
-            const val IS_ENABLED = "is_enabled"
-            /**
-             * String. List of strings, delimited by [ENABLEMENT_INSTRUCTIONS_DELIMITER] to be shown
-             * to the user if the affordance is disabled and the user selects the affordance. The
-             * first one is a title while the rest are the steps needed to re-enable the affordance.
-             */
-            const val ENABLEMENT_INSTRUCTIONS = "enablement_instructions"
-            /**
-             * String. Optional label for a button that, when clicked, opens a destination activity
-             * where the user can re-enable the disabled affordance.
-             */
-            const val ENABLEMENT_ACTION_TEXT = "enablement_action_text"
-            /**
-             * String. Optional package name and activity action string, delimited by
-             * [COMPONENT_NAME_SEPARATOR] to use with an `Intent` to start an activity that opens a
-             * destination where the user can re-enable the disabled affordance.
-             */
-            const val ENABLEMENT_COMPONENT_NAME = "enablement_action_intent"
-        }
-    }
-
-    /**
-     * Table for selections.
-     *
-     * Selections are pairs of slot and affordance IDs.
-     *
-     * Supported operations:
-     * - Insert - to insert an affordance and place it in a slot, insert values for the columns into
-     * the [SelectionTable.URI] [Uri]. The maximum capacity rule is enforced by the system.
-     * Selecting a new affordance for a slot that is already full will automatically remove the
-     * oldest affordance from the slot.
-     * - Query - to know which affordances are set on which slots, query the [SelectionTable.URI]
-     * [Uri]. The result set will contain rows, each of which with the columns from
-     * [SelectionTable.Columns].
-     * - Delete - to unselect an affordance, removing it from a slot, delete from the
-     * [SelectionTable.URI] [Uri], passing in values for each column.
-     */
-    object SelectionTable {
-        const val TABLE_NAME = "selections"
-        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
-
-        object Columns {
-            /** String. Unique ID for the slot. */
-            const val SLOT_ID = "slot_id"
-            /** String. Unique ID for the selected affordance. */
-            const val AFFORDANCE_ID = "affordance_id"
-            /** String. Human-readable name for the affordance. */
-            const val AFFORDANCE_NAME = "affordance_name"
-        }
-    }
-
-    /**
-     * Table for flags.
-     *
-     * Flags are key-value pairs.
-     *
-     * Supported operations:
-     * - Query - to know the values of flags, query the [FlagsTable.URI] [Uri]. The result set will
-     * contain rows, each of which with the columns from [FlagsTable.Columns].
-     */
-    object FlagsTable {
-        const val TABLE_NAME = "flags"
-        val URI: Uri = BASE_URI.buildUpon().path(TABLE_NAME).build()
-
-        /**
-         * Flag denoting whether the customizable lock screen quick affordances feature is enabled.
-         */
-        const val FLAG_NAME_FEATURE_ENABLED = "is_feature_enabled"
-
-        object Columns {
-            /** String. Unique ID for the flag. */
-            const val NAME = "name"
-            /** Int. Value of the flag. `1` means `true` and `0` means `false`. */
-            const val VALUE = "value"
-        }
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
index f6c75a2..c9ea794 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/PreviewPositionHelper.java
@@ -39,6 +39,7 @@
     private boolean mIsOrientationChanged;
     private SplitBounds mSplitBounds;
     private int mDesiredStagePosition;
+    private boolean mTaskbarInApp;
 
     public Matrix getMatrix() {
         return mMatrix;
@@ -57,6 +58,10 @@
         mDesiredStagePosition = desiredStagePosition;
     }
 
+    public void setTaskbarInApp(boolean taskbarInApp) {
+        mTaskbarInApp = taskbarInApp;
+    }
+
     /**
      * Updates the matrix based on the provided parameters
      */
@@ -83,8 +88,18 @@
                         ? mSplitBounds.topTaskPercent
                         : (1 - (mSplitBounds.topTaskPercent + mSplitBounds.dividerHeightPercent));
                 // Scale portrait height to that of (actual screen - taskbar inset)
-                fullscreenTaskHeight = (screenHeightPx - taskbarSize) * taskPercent;
-                canvasScreenRatio = canvasHeight / fullscreenTaskHeight;
+                fullscreenTaskHeight = (screenHeightPx) * taskPercent;
+                if (mTaskbarInApp) {
+                    canvasScreenRatio = canvasHeight / fullscreenTaskHeight;
+                } else {
+                    if (mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+                        // Top app isn't cropped at all by taskbar
+                        canvasScreenRatio = 0;
+                    } else {
+                        // Same as fullscreen ratio
+                        canvasScreenRatio = (float) canvasWidth / screenWidthPx;
+                    }
+                }
             } else {
                 // For landscape, scale the width
                 taskPercent = mDesiredStagePosition == STAGE_POSITION_TOP_OR_LEFT
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
index 3748eba..19d0a3d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/shadow/DoubleShadowIconDrawable.kt
@@ -71,7 +71,7 @@
                 mKeyShadowInfo.offsetY,
                 mKeyShadowInfo.alpha
             )
-        val blend = RenderEffect.createBlendModeEffect(ambientShadow, keyShadow, BlendMode.DARKEN)
+        val blend = RenderEffect.createBlendModeEffect(ambientShadow, keyShadow, BlendMode.DST_ATOP)
         renderNode.setRenderEffect(blend)
         return renderNode
     }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
index 93c8073..1b0dacc 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationRunnerCompat.java
@@ -166,15 +166,14 @@
                     counterLauncher.cleanUp(finishTransaction);
                     counterWallpaper.cleanUp(finishTransaction);
                     // Release surface references now. This is apparently to free GPU memory
-                    // while doing quick operations (eg. during CTS).
-                    for (int i = info.getChanges().size() - 1; i >= 0; --i) {
-                        info.getChanges().get(i).getLeash().release();
-                    }
+                    // before GC would.
+                    info.releaseAllSurfaces();
                     // Don't release here since launcher might still be using them. Instead
                     // let launcher release them (eg. via RemoteAnimationTargets)
                     leashMap.clear();
                     try {
                         finishCallback.onTransitionFinished(null /* wct */, finishTransaction);
+                        finishTransaction.close();
                     } catch (RemoteException e) {
                         Log.e("ActivityOptionsCompat", "Failed to call app controlled animation"
                                 + " finished callback", e);
@@ -203,10 +202,13 @@
                 synchronized (mFinishRunnables) {
                     finishRunnable = mFinishRunnables.remove(mergeTarget);
                 }
+                // Since we're not actually animating, release native memory now
+                t.close();
+                info.releaseAllSurfaces();
                 if (finishRunnable == null) return;
                 onAnimationCancelled(false /* isKeyguardOccluded */);
                 finishRunnable.run();
             }
         };
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index d4d3d25..b7e2494 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -126,15 +126,18 @@
             public void mergeAnimation(IBinder transition, TransitionInfo info,
                     SurfaceControl.Transaction t, IBinder mergeTarget,
                     IRemoteTransitionFinishedCallback finishedCallback) {
-                if (!mergeTarget.equals(mToken)) return;
-                if (!mRecentsSession.merge(info, t, recents)) return;
-                try {
-                    finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Error merging transition.", e);
+                if (mergeTarget.equals(mToken) && mRecentsSession.merge(info, t, recents)) {
+                    try {
+                        finishedCallback.onTransitionFinished(null /* wct */, null /* sct */);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Error merging transition.", e);
+                    }
+                    // commit taskAppeared after merge transition finished.
+                    mRecentsSession.commitTasksAppearedIfNeeded(recents);
+                } else {
+                    t.close();
+                    info.releaseAllSurfaces();
                 }
-                // commit taskAppeared after merge transition finished.
-                mRecentsSession.commitTasksAppearedIfNeeded(recents);
             }
         };
         return new RemoteTransition(remote, appThread);
@@ -248,6 +251,8 @@
                 }
                 // In this case, we are "returning" to an already running app, so just consume
                 // the merge and do nothing.
+                info.releaseAllSurfaces();
+                t.close();
                 return true;
             }
             final int layer = mInfo.getChanges().size() * 3;
@@ -264,6 +269,8 @@
                 t.setLayer(targets[i].leash, layer);
             }
             t.apply();
+            // not using the incoming anim-only surfaces
+            info.releaseAnimSurfaces();
             mAppearedTargets = targets;
             return true;
         }
@@ -380,9 +387,7 @@
             }
             // Only release the non-local created surface references. The animator is responsible
             // for releasing the leashes created by local.
-            for (int i = 0; i < mInfo.getChanges().size(); ++i) {
-                mInfo.getChanges().get(i).getLeash().release();
-            }
+            mInfo.releaseAllSurfaces();
             // Reset all members.
             mWrapped = null;
             mFinishCB = null;
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
index 458d22e..a25b281 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButton.java
@@ -25,7 +25,6 @@
 
 import com.android.internal.util.EmergencyAffordanceManager;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.settingslib.Utils;
 
 /**
  * This class implements a smart emergency button that updates itself based
@@ -91,17 +90,6 @@
         return super.onTouchEvent(event);
     }
 
-    /**
-     * Reload colors from resources.
-     **/
-    public void reloadColors() {
-        int color = Utils.getColorAttrDefaultColor(getContext(),
-                com.android.internal.R.attr.textColorOnAccent);
-        setTextColor(color);
-        setBackground(getContext()
-                .getDrawable(com.android.systemui.R.drawable.kg_emergency_button_background));
-    }
-
     @Override
     public boolean performLongClick() {
         return super.performLongClick();
diff --git a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
index c5190e8..ea808eb 100644
--- a/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
+++ b/packages/SystemUI/src/com/android/keyguard/EmergencyButtonController.java
@@ -135,7 +135,7 @@
             mPowerManager.userActivity(SystemClock.uptimeMillis(), true);
         }
         mActivityTaskManager.stopSystemLockTaskMode();
-        mShadeController.collapsePanel(false);
+        mShadeController.collapseShade(false);
         if (mTelecomManager != null && mTelecomManager.isInCall()) {
             mTelecomManager.showInCallScreen(false);
             if (mEmergencyButtonCallback != null) {
diff --git a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
index 4a41b3f..5bb9367 100644
--- a/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
+++ b/packages/SystemUI/src/com/android/keyguard/FaceAuthReason.kt
@@ -48,11 +48,13 @@
 import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_OCCLUSION_CHANGED
 import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_RESET
 import com.android.keyguard.InternalFaceAuthReasons.KEYGUARD_VISIBILITY_CHANGED
+import com.android.keyguard.InternalFaceAuthReasons.NON_STRONG_BIOMETRIC_ALLOWED_CHANGED
 import com.android.keyguard.InternalFaceAuthReasons.OCCLUDING_APP_REQUESTED
 import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN
 import com.android.keyguard.InternalFaceAuthReasons.PRIMARY_BOUNCER_SHOWN_OR_WILL_BE_SHOWN
 import com.android.keyguard.InternalFaceAuthReasons.RETRY_AFTER_HW_UNAVAILABLE
 import com.android.keyguard.InternalFaceAuthReasons.STARTED_WAKING_UP
+import com.android.keyguard.InternalFaceAuthReasons.STRONG_AUTH_ALLOWED_CHANGED
 import com.android.keyguard.InternalFaceAuthReasons.TRUST_DISABLED
 import com.android.keyguard.InternalFaceAuthReasons.TRUST_ENABLED
 import com.android.keyguard.InternalFaceAuthReasons.USER_SWITCHING
@@ -121,6 +123,9 @@
     const val FACE_AUTHENTICATED = "Face auth started/stopped because face is authenticated"
     const val BIOMETRIC_ENABLED =
         "Face auth started/stopped because biometric is enabled on keyguard"
+    const val STRONG_AUTH_ALLOWED_CHANGED = "Face auth stopped because strong auth allowed changed"
+    const val NON_STRONG_BIOMETRIC_ALLOWED_CHANGED =
+        "Face auth stopped because non strong biometric allowed changed"
 }
 
 /**
@@ -204,7 +209,11 @@
     @UiEvent(doc = FACE_AUTHENTICATED)
     FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED(1187, FACE_AUTHENTICATED),
     @UiEvent(doc = BIOMETRIC_ENABLED)
-    FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED);
+    FACE_AUTH_UPDATED_BIOMETRIC_ENABLED_ON_KEYGUARD(1188, BIOMETRIC_ENABLED),
+    @UiEvent(doc = STRONG_AUTH_ALLOWED_CHANGED)
+    FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED(1255, STRONG_AUTH_ALLOWED_CHANGED),
+    @UiEvent(doc = NON_STRONG_BIOMETRIC_ALLOWED_CHANGED)
+    FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED(1256, NON_STRONG_BIOMETRIC_ALLOWED_CHANGED);
 
     override fun getId(): Int = this.id
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index 3e32cf5..860c8e3 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -20,7 +20,6 @@
 import static com.android.internal.util.LatencyTracker.ACTION_CHECK_CREDENTIAL_UNLOCKED;
 import static com.android.keyguard.KeyguardAbsKeyInputView.MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT;
 
-import android.annotation.CallSuper;
 import android.content.res.ColorStateList;
 import android.os.AsyncTask;
 import android.os.CountDownTimer;
@@ -117,13 +116,6 @@
         }
     }
 
-    @CallSuper
-    @Override
-    public void reloadColors() {
-        super.reloadColors();
-        mMessageAreaController.reloadColors();
-    }
-
     @Override
     public boolean needsInput() {
         return false;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index faaba63..2e9ad58 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -16,7 +16,6 @@
 
 package com.android.keyguard;
 
-import android.annotation.CallSuper;
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -142,16 +141,6 @@
     public void showMessage(CharSequence message, ColorStateList colorState) {
     }
 
-    /**
-     * Reload colors from resources.
-     **/
-    @CallSuper
-    public void reloadColors() {
-        if (mEmergencyButton != null) {
-            mEmergencyButton.reloadColors();
-        }
-    }
-
     public void startAppearAnimation() {
         if (TextUtils.isEmpty(mMessageAreaController.getMessage())) {
             mMessageAreaController.setMessage(getInitialMessageResId());
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
index 8197685..52ca166 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardListenModel.kt
@@ -26,7 +26,6 @@
     val credentialAttempted: Boolean,
     val deviceInteractive: Boolean,
     val dreaming: Boolean,
-    val encryptedOrLockdown: Boolean,
     val fingerprintDisabled: Boolean,
     val fingerprintLockedOut: Boolean,
     val goingToSleep: Boolean,
@@ -37,6 +36,7 @@
     val primaryUser: Boolean,
     val shouldListenSfpsState: Boolean,
     val shouldListenForFingerprintAssistant: Boolean,
+    val strongerAuthRequired: Boolean,
     val switchingUser: Boolean,
     val udfps: Boolean,
     val userDoesNotHaveTrust: Boolean
@@ -53,17 +53,17 @@
     val biometricSettingEnabledForUser: Boolean,
     val bouncerFullyShown: Boolean,
     val faceAndFpNotAuthenticated: Boolean,
+    val faceAuthAllowed: Boolean,
     val faceDisabled: Boolean,
     val faceLockedOut: Boolean,
-    val fpLockedOut: Boolean,
     val goingToSleep: Boolean,
     val keyguardAwake: Boolean,
     val keyguardGoingAway: Boolean,
     val listeningForFaceAssistant: Boolean,
     val occludingAppRequestingFaceAuth: Boolean,
     val primaryUser: Boolean,
-    val scanningAllowedByStrongAuth: Boolean,
     val secureCameraLaunched: Boolean,
+    val supportsDetect: Boolean,
     val switchingUser: Boolean,
     val udfpsBouncerShowing: Boolean,
     val udfpsFingerDown: Boolean,
@@ -79,9 +79,8 @@
     // keep sorted
     val awakeKeyguard: Boolean,
     val authInterruptActive: Boolean,
-    val encryptedOrTimedOut: Boolean,
-    val fpLockout: Boolean,
-    val lockDown: Boolean,
+    val fpLockedOut: Boolean,
+    val primaryAuthRequired: Boolean,
     val switchingUser: Boolean,
     val triggerActiveUnlockForAssistant: Boolean,
     val userCanDismissLockScreen: Boolean
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index c29f632..6a92162 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -116,13 +116,6 @@
         return mView.getText();
     }
 
-    /**
-     * Reload colors from resources.
-     **/
-    public void reloadColors() {
-        mView.reloadColor();
-    }
-
     /** Factory for creating {@link com.android.keyguard.KeyguardMessageAreaController}. */
     public static class Factory {
         private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
index 0025986..195e8f9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordViewController.java
@@ -16,7 +16,6 @@
 
 package com.android.keyguard;
 
-import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.os.UserHandle;
 import android.text.Editable;
@@ -39,7 +38,6 @@
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -95,18 +93,6 @@
         }
     };
 
-    @Override
-    public void reloadColors() {
-        super.reloadColors();
-        int textColor = Utils.getColorAttr(mView.getContext(),
-                android.R.attr.textColorPrimary).getDefaultColor();
-        mPasswordEntry.setTextColor(textColor);
-        mPasswordEntry.setHighlightColor(textColor);
-        mPasswordEntry.setBackgroundTintList(ColorStateList.valueOf(textColor));
-        mPasswordEntry.setForegroundTintList(ColorStateList.valueOf(textColor));
-        mSwitchImeButton.setImageTintList(ColorStateList.valueOf(textColor));
-    }
-
     protected KeyguardPasswordViewController(KeyguardPasswordView view,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             SecurityMode securityMode,
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index cdbfb24..571d274 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -35,7 +35,6 @@
 import com.android.internal.widget.LockscreenCredential;
 import com.android.keyguard.EmergencyButtonController.EmergencyButtonCallback;
 import com.android.keyguard.KeyguardSecurityModel.SecurityMode;
-import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingClassifier;
 import com.android.systemui.classifier.FalsingCollector;
@@ -272,16 +271,6 @@
     }
 
     @Override
-    public void reloadColors() {
-        super.reloadColors();
-        mMessageAreaController.reloadColors();
-        int textColor = Utils.getColorAttr(mLockPatternView.getContext(),
-                android.R.attr.textColorSecondary).getDefaultColor();
-        int errorColor = Utils.getColorError(mLockPatternView.getContext()).getDefaultColor();
-        mLockPatternView.setColors(textColor, textColor, errorColor);
-    }
-
-    @Override
     public void onPause() {
         super.onPause();
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
index 7876f07..f51ac32 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinViewController.java
@@ -70,12 +70,6 @@
     }
 
     @Override
-    public void reloadColors() {
-        super.reloadColors();
-        mView.reloadColors();
-    }
-
-    @Override
     public boolean startDisappearAnimation(Runnable finishRunnable) {
         return mView.startDisappearAnimation(
                 mKeyguardUpdateMonitor.needsSlowUnlockTransition(), finishRunnable);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 5c4126e..8f3484a 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -221,10 +221,11 @@
                 public void onEnd(WindowInsetsAnimation animation) {
                     if (!mDisappearAnimRunning) {
                         endJankInstrument(InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_APPEAR);
-                        updateChildren(0 /* translationY */, 1f /* alpha */);
                     } else {
                         endJankInstrument(InteractionJankMonitor.CUJ_LOCKSCREEN_PASSWORD_DISAPPEAR);
+                        setAlpha(0f);
                     }
+                    updateChildren(0 /* translationY */, 1f /* alpha */);
                 }
 
                 private void updateChildren(int translationY, float alpha) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index 01be33e..a72a484 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -363,16 +363,18 @@
         final boolean sfpsEnabled = getResources().getBoolean(
                 R.bool.config_show_sidefps_hint_on_bouncer);
         final boolean fpsDetectionRunning = mUpdateMonitor.isFingerprintDetectionRunning();
-        final boolean needsStrongAuth = mUpdateMonitor.userNeedsStrongAuth();
+        final boolean isUnlockingWithFpAllowed =
+                mUpdateMonitor.isUnlockingWithFingerprintAllowed();
 
-        boolean toShow = mBouncerVisible && sfpsEnabled && fpsDetectionRunning && !needsStrongAuth;
+        boolean toShow = mBouncerVisible && sfpsEnabled && fpsDetectionRunning
+                && isUnlockingWithFpAllowed;
 
         if (DEBUG) {
             Log.d(TAG, "sideFpsToShow=" + toShow + ", "
                     + "mBouncerVisible=" + mBouncerVisible + ", "
                     + "configEnabled=" + sfpsEnabled + ", "
                     + "fpsDetectionRunning=" + fpsDetectionRunning + ", "
-                    + "needsStrongAuth=" + needsStrongAuth);
+                    + "isUnlockingWithFpAllowed=" + isUnlockingWithFpAllowed);
         }
         if (toShow) {
             mSideFpsController.get().show(SideFpsUiRequestSource.PRIMARY_BOUNCER);
@@ -728,16 +730,20 @@
     }
 
     private void reloadColors() {
-        mSecurityViewFlipperController.reloadColors();
+        resetViewFlipper();
         mView.reloadColors();
     }
 
     /** Handles density or font scale changes. */
     private void onDensityOrFontScaleChanged() {
-        mSecurityViewFlipperController.onDensityOrFontScaleChanged();
+        resetViewFlipper();
+        mView.onDensityOrFontScaleChanged();
+    }
+
+    private void resetViewFlipper() {
+        mSecurityViewFlipperController.clearViews();
         mSecurityViewFlipperController.getSecurityView(mCurrentSecurityMode,
                 mKeyguardSecurityCallback);
-        mView.onDensityOrFontScaleChanged();
     }
 
     static class Factory {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 25afe11..a5c8c78 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -74,17 +74,8 @@
         }
     }
 
-    /**
-     * Reload colors of ui elements upon theme change.
-     */
-    public void reloadColors() {
-        for (KeyguardInputViewController<KeyguardInputView> child : mChildren) {
-            child.reloadColors();
-        }
-    }
-
     /** Handles density or font scale changes. */
-    public void onDensityOrFontScaleChanged() {
+    public void clearViews() {
         mView.removeAllViews();
         mChildren.clear();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
index 91bf20f..a16f3047 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinViewController.java
@@ -133,12 +133,6 @@
     }
 
     @Override
-    public void reloadColors() {
-        super.reloadColors();
-        mView.reloadColors();
-    }
-
-    @Override
     protected void verifyPasswordAndUnlock() {
         String entry = mPasswordEntry.getText();
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
index 5995e85..e9405eb 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukViewController.java
@@ -121,12 +121,6 @@
     }
 
     @Override
-    public void reloadColors() {
-        super.reloadColors();
-        mView.reloadColors();
-    }
-
-    @Override
     protected void verifyPasswordAndUnlock() {
         mStateMachine.next();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 39ade34..51ade29 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -27,14 +27,16 @@
 import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_LOCKOUT_TIMED;
 import static android.hardware.biometrics.BiometricConstants.LockoutMode;
 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
+import static android.hardware.biometrics.BiometricSourceType.FACE;
+import static android.hardware.biometrics.BiometricSourceType.FINGERPRINT;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT;
 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;
-import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT;
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.keyguard.FaceAuthReasonKt.apiRequestReasonToUiEvent;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_DREAM_STARTED;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FACE_CANCEL_NOT_RECEIVED;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_STOPPED_FINISHED_GOING_TO_SLEEP;
@@ -63,6 +65,7 @@
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_ON_KEYGUARD_INIT;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_PRIMARY_BOUNCER_SHOWN;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STARTED_WAKING_UP;
+import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED;
 import static com.android.keyguard.FaceAuthUiEvent.FACE_AUTH_UPDATED_USER_SWITCHING;
 import static com.android.systemui.DejankUtils.whitelistIpcs;
 
@@ -168,7 +171,6 @@
 import java.util.Set;
 import java.util.TimeZone;
 import java.util.concurrent.Executor;
-import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
 import javax.inject.Inject;
@@ -228,7 +230,15 @@
      * Biometric authentication: Cancelling and waiting for the relevant biometric service to
      * send us the confirmation that cancellation has happened.
      */
-    private static final int BIOMETRIC_STATE_CANCELLING = 2;
+    @VisibleForTesting
+    protected static final int BIOMETRIC_STATE_CANCELLING = 2;
+
+    /**
+     * Biometric state: During cancelling we got another request to start listening, so when we
+     * receive the cancellation done signal, we should start listening again.
+     */
+    @VisibleForTesting
+    protected static final int BIOMETRIC_STATE_CANCELLING_RESTARTING = 3;
 
     /**
      * Action indicating keyguard *can* start biometric authentiation.
@@ -243,12 +253,6 @@
      */
     private static final int BIOMETRIC_ACTION_UPDATE = 2;
 
-    /**
-     * Biometric state: During cancelling we got another request to start listening, so when we
-     * receive the cancellation done signal, we should start listening again.
-     */
-    private static final int BIOMETRIC_STATE_CANCELLING_RESTARTING = 3;
-
     @VisibleForTesting
     public static final int BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED = -1;
     public static final int BIOMETRIC_HELP_FACE_NOT_RECOGNIZED = -2;
@@ -356,7 +360,8 @@
 
     private KeyguardBypassController mKeyguardBypassController;
     private List<SubscriptionInfo> mSubscriptionInfo;
-    private int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
+    @VisibleForTesting
+    protected int mFingerprintRunningState = BIOMETRIC_STATE_STOPPED;
     private int mFaceRunningState = BIOMETRIC_STATE_STOPPED;
     private boolean mIsDreaming;
     private boolean mLogoutEnabled;
@@ -730,8 +735,8 @@
      */
     public void requestFaceAuthOnOccludingApp(boolean request) {
         mOccludingAppRequestingFace = request;
-        updateFaceListeningState(BIOMETRIC_ACTION_UPDATE,
-                FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED);
+        int action = mOccludingAppRequestingFace ? BIOMETRIC_ACTION_UPDATE : BIOMETRIC_ACTION_STOP;
+        updateFaceListeningState(action, FACE_AUTH_TRIGGERED_OCCLUDING_APP_REQUESTED);
     }
 
     /**
@@ -790,7 +795,7 @@
                 new BiometricAuthenticated(true, isStrongBiometric));
         // Update/refresh trust state only if user can skip bouncer
         if (getUserCanSkipBouncer(userId)) {
-            mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FINGERPRINT);
+            mTrustManager.unlockedByBiometricForUser(userId, FINGERPRINT);
         }
         // Don't send cancel if authentication succeeds
         mFingerprintCancelSignal = null;
@@ -800,7 +805,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAuthenticated(userId, BiometricSourceType.FINGERPRINT,
+                cb.onBiometricAuthenticated(userId, FINGERPRINT,
                         isStrongBiometric);
             }
         }
@@ -833,7 +838,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAuthFailed(BiometricSourceType.FINGERPRINT);
+                cb.onBiometricAuthFailed(FINGERPRINT);
             }
         }
         if (isUdfpsSupported()) {
@@ -858,7 +863,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAcquired(BiometricSourceType.FINGERPRINT, acquireInfo);
+                cb.onBiometricAcquired(FINGERPRINT, acquireInfo);
             }
         }
     }
@@ -892,7 +897,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricHelp(msgId, helpString, BiometricSourceType.FINGERPRINT);
+                cb.onBiometricHelp(msgId, helpString, FINGERPRINT);
             }
         }
     }
@@ -934,17 +939,21 @@
             setFingerprintRunningState(BIOMETRIC_STATE_STOPPED);
         }
 
-        if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE
-                || msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED) {
-            mLogger.logRetryAfterFpError(msgId, errString);
+        if (msgId == FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE) {
+            mLogger.logRetryAfterFpErrorWithDelay(msgId, errString, HAL_ERROR_RETRY_TIMEOUT);
             mHandler.postDelayed(mRetryFingerprintAuthentication, HAL_ERROR_RETRY_TIMEOUT);
         }
 
+        if (msgId == FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED) {
+            mLogger.logRetryAfterFpErrorWithDelay(msgId, errString, 0);
+            updateFingerprintListeningState(BIOMETRIC_ACTION_START);
+        }
+
         boolean lockedOutStateChanged = false;
         if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
             lockedOutStateChanged = !mFingerprintLockedOutPermanent;
             mFingerprintLockedOutPermanent = true;
-            mLogger.d("Fingerprint locked out - requiring strong auth");
+            mLogger.d("Fingerprint permanently locked out - requiring stronger auth");
             mLockPatternUtils.requireStrongAuth(
                     STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, getCurrentUser());
         }
@@ -953,6 +962,7 @@
                 || msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
             lockedOutStateChanged |= !mFingerprintLockedOut;
             mFingerprintLockedOut = true;
+            mLogger.d("Fingerprint temporarily locked out - requiring stronger auth");
             if (isUdfpsEnrolled()) {
                 updateFingerprintListeningState(BIOMETRIC_ACTION_UPDATE);
             }
@@ -963,12 +973,12 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricError(msgId, errString, BiometricSourceType.FINGERPRINT);
+                cb.onBiometricError(msgId, errString, FINGERPRINT);
             }
         }
 
         if (lockedOutStateChanged) {
-            notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
+            notifyLockedOutStateChanged(FINGERPRINT);
         }
     }
 
@@ -996,7 +1006,7 @@
         }
 
         if (changed) {
-            notifyLockedOutStateChanged(BiometricSourceType.FINGERPRINT);
+            notifyLockedOutStateChanged(FINGERPRINT);
         }
     }
 
@@ -1019,7 +1029,7 @@
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onBiometricRunningStateChanged(isFingerprintDetectionRunning(),
-                        BiometricSourceType.FINGERPRINT);
+                        FINGERPRINT);
             }
         }
     }
@@ -1032,7 +1042,7 @@
                 new BiometricAuthenticated(true, isStrongBiometric));
         // Update/refresh trust state only if user can skip bouncer
         if (getUserCanSkipBouncer(userId)) {
-            mTrustManager.unlockedByBiometricForUser(userId, BiometricSourceType.FACE);
+            mTrustManager.unlockedByBiometricForUser(userId, FACE);
         }
         // Don't send cancel if authentication succeeds
         mFaceCancelSignal = null;
@@ -1043,7 +1053,7 @@
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onBiometricAuthenticated(userId,
-                        BiometricSourceType.FACE,
+                        FACE,
                         isStrongBiometric);
             }
         }
@@ -1065,7 +1075,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAuthFailed(BiometricSourceType.FACE);
+                cb.onBiometricAuthFailed(FACE);
             }
         }
         handleFaceHelp(BIOMETRIC_HELP_FACE_NOT_RECOGNIZED,
@@ -1078,7 +1088,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricAcquired(BiometricSourceType.FACE, acquireInfo);
+                cb.onBiometricAcquired(FACE, acquireInfo);
             }
         }
     }
@@ -1113,7 +1123,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onBiometricHelp(msgId, helpString, BiometricSourceType.FACE);
+                cb.onBiometricHelp(msgId, helpString, FACE);
             }
         }
     }
@@ -1181,12 +1191,12 @@
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onBiometricError(msgId, errString,
-                        BiometricSourceType.FACE);
+                        FACE);
             }
         }
 
         if (lockedOutStateChanged) {
-            notifyLockedOutStateChanged(BiometricSourceType.FACE);
+            notifyLockedOutStateChanged(FACE);
         }
     }
 
@@ -1200,7 +1210,7 @@
                 FACE_AUTH_TRIGGERED_FACE_LOCKOUT_RESET), getBiometricLockoutDelay());
 
         if (changed) {
-            notifyLockedOutStateChanged(BiometricSourceType.FACE);
+            notifyLockedOutStateChanged(FACE);
         }
     }
 
@@ -1223,7 +1233,7 @@
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
                 cb.onBiometricRunningStateChanged(isFaceDetectionRunning(),
-                        BiometricSourceType.FACE);
+                        FACE);
             }
         }
     }
@@ -1364,9 +1374,40 @@
     }
 
     public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
-        return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric);
+        // StrongAuthTracker#isUnlockingWithBiometricAllowed includes
+        // STRONG_AUTH_REQUIRED_AFTER_LOCKOUT which is the same as mFingerprintLockedOutPermanent;
+        // however the strong auth tracker does not include the temporary lockout
+        // mFingerprintLockedOut.
+        return mStrongAuthTracker.isUnlockingWithBiometricAllowed(isStrongBiometric)
+                && !mFingerprintLockedOut;
     }
 
+    /**
+     * Whether fingerprint is allowed ot be used for unlocking based on the strongAuthTracker
+     * and temporary lockout state (tracked by FingerprintManager via error codes).
+     */
+    public boolean isUnlockingWithFingerprintAllowed() {
+        return isUnlockingWithBiometricAllowed(FINGERPRINT);
+    }
+
+    /**
+     * Whether the given biometric is allowed based on strongAuth & lockout states.
+     */
+    public boolean isUnlockingWithBiometricAllowed(
+            @NonNull BiometricSourceType biometricSourceType) {
+        switch (biometricSourceType) {
+            case FINGERPRINT:
+                return isUnlockingWithBiometricAllowed(true);
+            case FACE:
+                return isUnlockingWithBiometricAllowed(false);
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Whether the user locked down the device. This doesn't include device policy manager lockdown.
+     */
     public boolean isUserInLockdown(int userId) {
         return containsFlag(mStrongAuthTracker.getStrongAuthForUser(userId),
                 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
@@ -1386,11 +1427,6 @@
         return isEncrypted || isLockDown;
     }
 
-    public boolean userNeedsStrongAuth() {
-        return mStrongAuthTracker.getStrongAuthForUser(getCurrentUser())
-                != LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
-    }
-
     private boolean containsFlag(int haystack, int needle) {
         return (haystack & needle) != 0;
     }
@@ -1403,7 +1439,8 @@
         return mStrongAuthTracker;
     }
 
-    private void notifyStrongAuthStateChanged(int userId) {
+    @VisibleForTesting
+    void notifyStrongAuthAllowedChanged(int userId) {
         Assert.isMainThread();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1411,6 +1448,15 @@
                 cb.onStrongAuthStateChanged(userId);
             }
         }
+        if (userId == getCurrentUser()) {
+            FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED.setExtraInfo(
+                    mStrongAuthTracker.getStrongAuthForUser(getCurrentUser()));
+
+            // Strong auth is only reset when primary auth is used to enter the device,
+            // so we only check whether to stop biometric listening states here
+            updateBiometricListeningState(
+                    BIOMETRIC_ACTION_STOP, FACE_AUTH_UPDATED_STRONG_AUTH_CHANGED);
+        }
     }
 
     private void notifyLockedOutStateChanged(BiometricSourceType type) {
@@ -1422,8 +1468,8 @@
             }
         }
     }
-
-    private void notifyNonStrongBiometricStateChanged(int userId) {
+    @VisibleForTesting
+    void notifyNonStrongBiometricAllowedChanged(int userId) {
         Assert.isMainThread();
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -1431,6 +1477,16 @@
                 cb.onNonStrongBiometricAllowedChanged(userId);
             }
         }
+        if (userId == getCurrentUser()) {
+            FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED.setExtraInfo(
+                    mStrongAuthTracker.isNonStrongBiometricAllowedAfterIdleTimeout(
+                            getCurrentUser()) ? -1 : 1);
+
+            // This is only reset when primary auth is used to enter the device, so we only check
+            // whether to stop biometric listening states here
+            updateBiometricListeningState(BIOMETRIC_ACTION_STOP,
+                    FACE_AUTH_NON_STRONG_BIOMETRIC_ALLOWED_CHANGED);
+        }
     }
 
     private void dispatchErrorMessage(CharSequence message) {
@@ -1560,12 +1616,6 @@
         }
     };
 
-    private final FingerprintManager.FingerprintDetectionCallback mFingerprintDetectionCallback
-            = (sensorId, userId, isStrongBiometric) -> {
-                // Trigger the fingerprint success path so the bouncer can be shown
-                handleFingerprintAuthenticated(userId, isStrongBiometric);
-            };
-
     /**
      * Propagates a pointer down event to keyguard.
      */
@@ -1782,16 +1832,12 @@
         }
     }
 
-    public static class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
-        private final Consumer<Integer> mStrongAuthRequiredChangedCallback;
-        private final Consumer<Integer> mNonStrongBiometricAllowedChanged;
-
-        public StrongAuthTracker(Context context,
-                Consumer<Integer> strongAuthRequiredChangedCallback,
-                Consumer<Integer> nonStrongBiometricAllowedChanged) {
+    /**
+     * Updates callbacks when strong auth requirements change.
+     */
+    public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+        public StrongAuthTracker(Context context) {
             super(context);
-            mStrongAuthRequiredChangedCallback = strongAuthRequiredChangedCallback;
-            mNonStrongBiometricAllowedChanged = nonStrongBiometricAllowedChanged;
         }
 
         public boolean isUnlockingWithBiometricAllowed(boolean isStrongBiometric) {
@@ -1807,7 +1853,7 @@
 
         @Override
         public void onStrongAuthRequiredChanged(int userId) {
-            mStrongAuthRequiredChangedCallback.accept(userId);
+            notifyStrongAuthAllowedChanged(userId);
         }
 
         // TODO(b/247091681): Renaming the inappropriate onIsNonStrongBiometricAllowedChanged
@@ -1815,7 +1861,7 @@
         //  Strong-Auth
         @Override
         public void onIsNonStrongBiometricAllowedChanged(int userId) {
-            mNonStrongBiometricAllowedChanged.accept(userId);
+            notifyNonStrongBiometricAllowedChanged(userId);
         }
     }
 
@@ -1976,8 +2022,7 @@
         mUserTracker = userTracker;
         mTelephonyListenerManager = telephonyListenerManager;
         mDeviceProvisioned = isDeviceProvisionedInSettingsDb();
-        mStrongAuthTracker = new StrongAuthTracker(context, this::notifyStrongAuthStateChanged,
-                this::notifyNonStrongBiometricStateChanged);
+        mStrongAuthTracker = new StrongAuthTracker(context);
         mBackgroundExecutor = backgroundExecutor;
         mBroadcastDispatcher = broadcastDispatcher;
         mInteractionJankMonitor = interactionJankMonitor;
@@ -2552,24 +2597,17 @@
                 || !mLockPatternUtils.isSecure(user);
 
         // Don't trigger active unlock if fp is locked out
-        final boolean fpLockedout = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
+        final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
 
         // Don't trigger active unlock if primary auth is required
-        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
-        final boolean isLockDown =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-        final boolean isEncryptedOrTimedOut =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+        final boolean primaryAuthRequired = !isUnlockingWithBiometricAllowed(true);
 
         final boolean shouldTriggerActiveUnlock =
                 (mAuthInterruptActive || triggerActiveUnlockForAssistant || awakeKeyguard)
                         && !mSwitchingUser
                         && !userCanDismissLockScreen
-                        && !fpLockedout
-                        && !isLockDown
-                        && !isEncryptedOrTimedOut
+                        && !fpLockedOut
+                        && !primaryAuthRequired
                         && !mKeyguardGoingAway
                         && !mSecureCameraLaunched;
 
@@ -2581,9 +2619,8 @@
                         shouldTriggerActiveUnlock,
                         awakeKeyguard,
                         mAuthInterruptActive,
-                        isEncryptedOrTimedOut,
-                        fpLockedout,
-                        isLockDown,
+                        fpLockedOut,
+                        primaryAuthRequired,
                         mSwitchingUser,
                         triggerActiveUnlockForAssistant,
                         userCanDismissLockScreen));
@@ -2635,28 +2672,27 @@
                         && !fingerprintDisabledForUser
                         && (!mKeyguardGoingAway || !mDeviceInteractive)
                         && mIsPrimaryUser
-                        && biometricEnabledForUser;
-
-        final boolean shouldListenBouncerState = !(mFingerprintLockedOut
-                && mPrimaryBouncerIsOrWillBeShowing && mCredentialAttempted);
-
-        final boolean isEncryptedOrLockdownForUser = isEncryptedOrLockdown(user);
+                        && biometricEnabledForUser
+                        && !isUserInLockdown(user);
+        final boolean strongerAuthRequired = !isUnlockingWithFingerprintAllowed();
+        final boolean isSideFps = isSfpsSupported() && isSfpsEnrolled();
+        final boolean shouldListenBouncerState =
+                !strongerAuthRequired || !mPrimaryBouncerIsOrWillBeShowing;
 
         final boolean shouldListenUdfpsState = !isUdfps
                 || (!userCanSkipBouncer
-                && !isEncryptedOrLockdownForUser
+                && !strongerAuthRequired
                 && userDoesNotHaveTrust);
 
         boolean shouldListenSideFpsState = true;
-        if (isSfpsSupported() && isSfpsEnrolled()) {
+        if (isSideFps) {
             shouldListenSideFpsState =
                     mSfpsRequireScreenOnToAuthPrefEnabled ? isDeviceInteractive() : true;
         }
 
         boolean shouldListen = shouldListenKeyguardState && shouldListenUserState
-                && shouldListenBouncerState && shouldListenUdfpsState && !isFingerprintLockedOut()
+                && shouldListenBouncerState && shouldListenUdfpsState
                 && shouldListenSideFpsState;
-
         maybeLogListenerModelData(
                 new KeyguardFingerprintListenModel(
                     System.currentTimeMillis(),
@@ -2668,7 +2704,6 @@
                     mCredentialAttempted,
                     mDeviceInteractive,
                     mIsDreaming,
-                    isEncryptedOrLockdownForUser,
                     fingerprintDisabledForUser,
                     mFingerprintLockedOut,
                     mGoingToSleep,
@@ -2679,6 +2714,7 @@
                     mIsPrimaryUser,
                     shouldListenSideFpsState,
                     shouldListenForFingerprintAssistant,
+                    strongerAuthRequired,
                     mSwitchingUser,
                     isUdfps,
                     userDoesNotHaveTrust));
@@ -2699,17 +2735,7 @@
         final boolean awakeKeyguard = isKeyguardVisible() && mDeviceInteractive
                 && !statusBarShadeLocked;
         final int user = getCurrentUser();
-        final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
-        final boolean isLockDown =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-        final boolean isEncryptedOrTimedOut =
-                containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
-                        || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
-
-        // TODO: always disallow when fp is already locked out?
-        final boolean fpLockedOut = mFingerprintLockedOut || mFingerprintLockedOutPermanent;
-
+        final boolean faceAuthAllowed = isUnlockingWithBiometricAllowed(FACE);
         final boolean canBypass = mKeyguardBypassController != null
                 && mKeyguardBypassController.canBypass();
         // There's no reason to ask the HAL for authentication when the user can dismiss the
@@ -2717,20 +2743,15 @@
         // the lock screen even when TrustAgents are keeping the device unlocked.
         final boolean userNotTrustedOrDetectionIsNeeded = !getUserHasTrust(user) || canBypass;
 
-        // Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
-        // Lock-down mode shouldn't scan, since it is more explicit.
-        boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass
-                && !mPrimaryBouncerFullyShown);
-
-        // If the device supports face detection (without authentication) and bypass is enabled,
-        // allow face scanning to happen if the device is in lockdown mode.
-        // Otherwise, prevent scanning.
-        final boolean supportsDetectOnly = !mFaceSensorProperties.isEmpty()
-                && canBypass
-                && mFaceSensorProperties.get(0).supportsFaceDetection;
-        if (isLockDown && !supportsDetectOnly) {
-            strongAuthAllowsScanning = false;
-        }
+        // If the device supports face detection (without authentication), if bypass is enabled,
+        // allow face detection to happen even if stronger auth is required. When face is detected,
+        // we show the bouncer. However, if the user manually locked down the device themselves,
+        // never attempt to detect face.
+        final boolean supportsDetect = !mFaceSensorProperties.isEmpty()
+                && mFaceSensorProperties.get(0).supportsFaceDetection
+                && canBypass && !mPrimaryBouncerIsOrWillBeShowing
+                && !isUserInLockdown(user);
+        final boolean faceAuthAllowedOrDetectionIsNeeded = faceAuthAllowed || supportsDetect;
 
         // If the face or fp has recently been authenticated do not attempt to authenticate again.
         final boolean faceAndFpNotAuthenticated = !getUserUnlockedWithBiometric(user);
@@ -2751,14 +2772,10 @@
                         || mUdfpsBouncerShowing)
                 && !mSwitchingUser && !faceDisabledForUser && userNotTrustedOrDetectionIsNeeded
                 && !mKeyguardGoingAway && biometricEnabledForUser
-                && strongAuthAllowsScanning && mIsPrimaryUser
+                && faceAuthAllowedOrDetectionIsNeeded && mIsPrimaryUser
                 && (!mSecureCameraLaunched || mOccludingAppRequestingFace)
                 && faceAndFpNotAuthenticated
-                && !mGoingToSleep
-                // We only care about fp locked out state and not face because we still trigger
-                // face auth even when face is locked out to show the user a message that face
-                // unlock was supposed to run but didn't
-                && !fpLockedOut;
+                && !mGoingToSleep;
 
         // Aggregate relevant fields for debug logging.
         maybeLogListenerModelData(
@@ -2768,19 +2785,19 @@
                     shouldListen,
                     mAuthInterruptActive,
                     biometricEnabledForUser,
-                        mPrimaryBouncerFullyShown,
+                    mPrimaryBouncerFullyShown,
                     faceAndFpNotAuthenticated,
+                    faceAuthAllowed,
                     faceDisabledForUser,
                     isFaceLockedOut(),
-                    fpLockedOut,
                     mGoingToSleep,
                     awakeKeyguard,
                     mKeyguardGoingAway,
                     shouldListenForFaceAssistant,
                     mOccludingAppRequestingFace,
                     mIsPrimaryUser,
-                    strongAuthAllowsScanning,
                     mSecureCameraLaunched,
+                    supportsDetect,
                     mSwitchingUser,
                     mUdfpsBouncerShowing,
                     isUdfpsFingerDown,
@@ -2831,15 +2848,22 @@
             // Waiting for restart via handleFingerprintError().
             return;
         }
-        mLogger.v("startListeningForFingerprint()");
 
         if (unlockPossible) {
             mFingerprintCancelSignal = new CancellationSignal();
 
-            if (isEncryptedOrLockdown(userId)) {
-                mFpm.detectFingerprint(mFingerprintCancelSignal, mFingerprintDetectionCallback,
+            if (!isUnlockingWithFingerprintAllowed()) {
+                mLogger.v("startListeningForFingerprint - detect");
+                mFpm.detectFingerprint(
+                        mFingerprintCancelSignal,
+                        (sensorId, user, isStrongBiometric) -> {
+                            mLogger.d("fingerprint detected");
+                            // Trigger the fingerprint success path so the bouncer can be shown
+                            handleFingerprintAuthenticated(user, isStrongBiometric);
+                        },
                         userId);
             } else {
+                mLogger.v("startListeningForFingerprint - authenticate");
                 mFpm.authenticate(null /* crypto */, mFingerprintCancelSignal,
                         mFingerprintAuthenticationCallback, null /* handler */,
                         FingerprintManager.SENSOR_ID_ANY, userId, 0 /* flags */);
@@ -2877,9 +2901,11 @@
             // This would need to be updated for multi-sensor devices
             final boolean supportsFaceDetection = !mFaceSensorProperties.isEmpty()
                     && mFaceSensorProperties.get(0).supportsFaceDetection;
-            if (isEncryptedOrLockdown(userId) && supportsFaceDetection) {
+            if (!isUnlockingWithBiometricAllowed(FACE) && supportsFaceDetection) {
+                mLogger.v("startListeningForFace - detect");
                 mFaceManager.detectFace(mFaceCancelSignal, mFaceDetectionCallback, userId);
             } else {
+                mLogger.v("startListeningForFace - authenticate");
                 final boolean isBypassEnabled = mKeyguardBypassController != null
                         && mKeyguardBypassController.isBypassEnabled();
                 mFaceManager.authenticate(null /* crypto */, mFaceCancelSignal,
@@ -3056,11 +3082,15 @@
             }
         }
 
+        // Immediately stop previous biometric listening states.
+        // Resetting lockout states updates the biometric listening states.
         if (mFaceManager != null && !mFaceSensorProperties.isEmpty()) {
+            stopListeningForFace(FACE_AUTH_UPDATED_USER_SWITCHING);
             handleFaceLockoutReset(mFaceManager.getLockoutModeForUser(
                     mFaceSensorProperties.get(0).sensorId, userId));
         }
         if (mFpm != null && !mFingerprintSensorProperties.isEmpty()) {
+            stopListeningForFingerprint();
             handleFingerprintLockoutReset(mFpm.getLockoutModeForUser(
                     mFingerprintSensorProperties.get(0).sensorId, userId));
         }
@@ -3467,7 +3497,7 @@
     @AnyThread
     public void setSwitchingUser(boolean switching) {
         mSwitchingUser = switching;
-        // Since this comes in on a binder thread, we need to post if first
+        // Since this comes in on a binder thread, we need to post it first
         mHandler.post(() -> updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_USER_SWITCHING));
     }
@@ -3559,8 +3589,8 @@
         Assert.isMainThread();
         mUserFingerprintAuthenticated.clear();
         mUserFaceAuthenticated.clear();
-        mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
-        mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
+        mTrustManager.clearAllBiometricRecognized(FINGERPRINT, unlockedUser);
+        mTrustManager.clearAllBiometricRecognized(FACE, unlockedUser);
         mLogger.d("clearBiometricRecognized");
 
         for (int i = 0; i < mCallbacks.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 1f6441a..b66ae28 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -225,12 +225,13 @@
                 { "Retrying face after HW unavailable, attempt $int1" })
     }
 
-    fun logRetryAfterFpError(msgId: Int, errString: String?) {
+    fun logRetryAfterFpErrorWithDelay(msgId: Int, errString: String?, delay: Int) {
         logBuffer.log(TAG, DEBUG, {
             int1 = msgId
+            int2 = delay
             str1 = "$errString"
         }, {
-            "Fingerprint retrying auth due to($int1) -> $str1"
+            "Fingerprint retrying auth after $int2 ms due to($int1) -> $str1"
         })
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/CoreStartable.java b/packages/SystemUI/src/com/android/systemui/CoreStartable.java
index 929ebea..becf5b3 100644
--- a/packages/SystemUI/src/com/android/systemui/CoreStartable.java
+++ b/packages/SystemUI/src/com/android/systemui/CoreStartable.java
@@ -39,10 +39,13 @@
  */
 public interface CoreStartable extends Dumpable {
 
-    /** Main entry point for implementations. Called shortly after app startup. */
+    /** Main entry point for implementations. Called shortly after SysUI startup. */
     void start();
 
-    /** */
+    /** Called when the device configuration changes. This will not be called before
+     * {@link #start()}, but it could be called before {@link #onBootCompleted()}.
+     *
+     * @see android.app.Application#onConfigurationChanged(Configuration)  */
     default void onConfigurationChanged(Configuration newConfig) {
     }
 
@@ -50,7 +53,11 @@
     default void dump(@NonNull PrintWriter pw, @NonNull String[] args) {
     }
 
-    /** Called when the device reports BOOT_COMPLETED. */
+    /** Called immediately after the system broadcasts
+     * {@link android.content.Intent#ACTION_LOCKED_BOOT_COMPLETED} or during SysUI startup if the
+     * property {@code sys.boot_completed} is already set to 1. The latter typically occurs when
+     * starting a new SysUI instance, such as when starting SysUI for a secondary user.
+     * {@link #onBootCompleted()} will never be called before {@link #start()}. */
     default void onBootCompleted() {
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
index 9a8d532..104b71f 100644
--- a/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/GuestResumeSessionReceiver.java
@@ -17,24 +17,25 @@
 package com.android.systemui;
 
 import android.app.AlertDialog;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
-import android.util.Log;
+
+import androidx.annotation.NonNull;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.qs.QSUserSwitcherEvent;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.util.settings.SecureSettings;
 
+import java.util.concurrent.Executor;
+
 import javax.inject.Inject;
 
 import dagger.assisted.Assisted;
@@ -44,31 +45,66 @@
 /**
  * Manages notification when a guest session is resumed.
  */
-public class GuestResumeSessionReceiver extends BroadcastReceiver {
-
-    private static final String TAG = GuestResumeSessionReceiver.class.getSimpleName();
+public class GuestResumeSessionReceiver {
 
     @VisibleForTesting
     public static final String SETTING_GUEST_HAS_LOGGED_IN = "systemui.guest_has_logged_in";
 
     @VisibleForTesting
     public AlertDialog mNewSessionDialog;
+    private final Executor mMainExecutor;
     private final UserTracker mUserTracker;
     private final SecureSettings mSecureSettings;
-    private final BroadcastDispatcher mBroadcastDispatcher;
     private final ResetSessionDialog.Factory mResetSessionDialogFactory;
     private final GuestSessionNotification mGuestSessionNotification;
 
+    @VisibleForTesting
+    public final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    cancelDialog();
+
+                    UserInfo currentUser = mUserTracker.getUserInfo();
+                    if (!currentUser.isGuest()) {
+                        return;
+                    }
+
+                    int guestLoginState = mSecureSettings.getIntForUser(
+                            SETTING_GUEST_HAS_LOGGED_IN, 0, newUser);
+
+                    if (guestLoginState == 0) {
+                        // set 1 to indicate, 1st login
+                        guestLoginState = 1;
+                        mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState,
+                                newUser);
+                    } else if (guestLoginState == 1) {
+                        // set 2 to indicate, 2nd or later login
+                        guestLoginState = 2;
+                        mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState,
+                                newUser);
+                    }
+
+                    mGuestSessionNotification.createPersistentNotification(currentUser,
+                            (guestLoginState <= 1));
+
+                    if (guestLoginState > 1) {
+                        mNewSessionDialog = mResetSessionDialogFactory.create(newUser);
+                        mNewSessionDialog.show();
+                    }
+                }
+            };
+
     @Inject
     public GuestResumeSessionReceiver(
+            @Main Executor mainExecutor,
             UserTracker userTracker,
             SecureSettings secureSettings,
-            BroadcastDispatcher broadcastDispatcher,
             GuestSessionNotification guestSessionNotification,
             ResetSessionDialog.Factory resetSessionDialogFactory) {
+        mMainExecutor = mainExecutor;
         mUserTracker = userTracker;
         mSecureSettings = secureSettings;
-        mBroadcastDispatcher = broadcastDispatcher;
         mGuestSessionNotification = guestSessionNotification;
         mResetSessionDialogFactory = resetSessionDialogFactory;
     }
@@ -77,49 +113,7 @@
      * Register this receiver with the {@link BroadcastDispatcher}
      */
     public void register() {
-        IntentFilter f = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        mBroadcastDispatcher.registerReceiver(this, f, null /* handler */, UserHandle.SYSTEM);
-    }
-
-    @Override
-    public void onReceive(Context context, Intent intent) {
-        String action = intent.getAction();
-
-        if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-            cancelDialog();
-
-            int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-            if (userId == UserHandle.USER_NULL) {
-                Log.e(TAG, intent + " sent to " + TAG + " without EXTRA_USER_HANDLE");
-                return;
-            }
-
-            UserInfo currentUser = mUserTracker.getUserInfo();
-            if (!currentUser.isGuest()) {
-                return;
-            }
-
-            int guestLoginState = mSecureSettings.getIntForUser(
-                    SETTING_GUEST_HAS_LOGGED_IN, 0, userId);
-
-            if (guestLoginState == 0) {
-                // set 1 to indicate, 1st login
-                guestLoginState = 1;
-                mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState, userId);
-            } else if (guestLoginState == 1) {
-                // set 2 to indicate, 2nd or later login
-                guestLoginState = 2;
-                mSecureSettings.putIntForUser(SETTING_GUEST_HAS_LOGGED_IN, guestLoginState, userId);
-            }
-
-            mGuestSessionNotification.createPersistentNotification(currentUser,
-                                                                   (guestLoginState <= 1));
-
-            if (guestLoginState > 1) {
-                mNewSessionDialog = mResetSessionDialogFactory.create(userId);
-                mNewSessionDialog.show();
-            }
-        }
+        mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
     }
 
     private void cancelDialog() {
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 7e3b1389..02a6d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -26,10 +26,7 @@
 import android.annotation.IdRes;
 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.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -45,7 +42,6 @@
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.util.DisplayUtils;
 import android.util.Log;
@@ -68,7 +64,6 @@
 
 import com.android.internal.util.Preconditions;
 import com.android.settingslib.Utils;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.decor.CutoutDecorProviderFactory;
@@ -128,7 +123,6 @@
     private DisplayManager mDisplayManager;
     @VisibleForTesting
     protected boolean mIsRegistered;
-    private final BroadcastDispatcher mBroadcastDispatcher;
     private final Context mContext;
     private final Executor mMainExecutor;
     private final TunerService mTunerService;
@@ -302,7 +296,6 @@
     public ScreenDecorations(Context context,
             @Main Executor mainExecutor,
             SecureSettings secureSettings,
-            BroadcastDispatcher broadcastDispatcher,
             TunerService tunerService,
             UserTracker userTracker,
             PrivacyDotViewController dotViewController,
@@ -312,7 +305,6 @@
         mContext = context;
         mMainExecutor = mainExecutor;
         mSecureSettings = secureSettings;
-        mBroadcastDispatcher = broadcastDispatcher;
         mTunerService = tunerService;
         mUserTracker = userTracker;
         mDotViewController = dotViewController;
@@ -598,10 +590,7 @@
             mColorInversionSetting.onChange(false);
             updateColorInversion(mColorInversionSetting.getValue());
 
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
-            mBroadcastDispatcher.registerReceiver(mUserSwitchIntentReceiver, filter,
-                    mExecutor, UserHandle.ALL);
+            mUserTracker.addCallback(mUserChangedCallback, mExecutor);
             mIsRegistered = true;
         } else {
             mMainExecutor.execute(() -> mTunerService.removeTunable(this));
@@ -610,7 +599,7 @@
                 mColorInversionSetting.setListening(false);
             }
 
-            mBroadcastDispatcher.unregisterReceiver(mUserSwitchIntentReceiver);
+            mUserTracker.removeCallback(mUserChangedCallback);
             mIsRegistered = false;
         }
     }
@@ -897,18 +886,18 @@
         }
     }
 
-    private final BroadcastReceiver mUserSwitchIntentReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            int newUserId = mUserTracker.getUserId();
-            if (DEBUG) {
-                Log.d(TAG, "UserSwitched newUserId=" + newUserId);
-            }
-            // update color inversion setting to the new user
-            mColorInversionSetting.setUserId(newUserId);
-            updateColorInversion(mColorInversionSetting.getValue());
-        }
-    };
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    if (DEBUG) {
+                        Log.d(TAG, "UserSwitched newUserId=" + newUser);
+                    }
+                    // update color inversion setting to the new user
+                    mColorInversionSetting.setUserId(newUser);
+                    updateColorInversion(mColorInversionSetting.getValue());
+                }
+            };
 
     private void updateColorInversion(int colorsInvertedValue) {
         mTintColor = colorsInvertedValue != 0 ? Color.WHITE : Color.BLACK;
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
index d60cc75..50449b0 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/SystemActions.java
@@ -52,6 +52,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.recents.Recents;
+import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
@@ -183,15 +184,18 @@
     private final AccessibilityManager mA11yManager;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
     private final NotificationShadeWindowController mNotificationShadeController;
+    private final ShadeController mShadeController;
     private final StatusBarWindowCallback mNotificationShadeCallback;
     private boolean mDismissNotificationShadeActionRegistered;
 
     @Inject
     public SystemActions(Context context,
             NotificationShadeWindowController notificationShadeController,
+            ShadeController shadeController,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             Optional<Recents> recentsOptional) {
         mContext = context;
+        mShadeController = shadeController;
         mRecentsOptional = recentsOptional;
         mReceiver = new SystemActionsBroadcastReceiver();
         mLocale = mContext.getResources().getConfiguration().getLocales().get(0);
@@ -529,9 +533,7 @@
     }
 
     private void handleAccessibilityDismissNotificationShade() {
-        mCentralSurfacesOptionalLazy.get().ifPresent(
-                centralSurfaces -> centralSurfaces.animateCollapsePanels(
-                        CommandQueue.FLAG_EXCLUDE_NONE, false /* force */));
+        mShadeController.animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE);
     }
 
     private void handleDpadUp() {
diff --git a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
index 5616a00..621b99d 100644
--- a/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
+++ b/packages/SystemUI/src/com/android/systemui/backup/BackupHelper.kt
@@ -29,13 +29,15 @@
 import android.util.Log
 import com.android.systemui.controls.controller.AuxiliaryPersistenceWrapper
 import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper
+import com.android.systemui.keyguard.domain.backup.KeyguardQuickAffordanceBackupHelper
 import com.android.systemui.people.widget.PeopleBackupHelper
 
 /**
  * Helper for backing up elements in SystemUI
  *
- * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI.
- * The helper can be used to back up any element that is stored in [Context.getFilesDir].
+ * This helper is invoked by BackupManager whenever a backup or restore is required in SystemUI. The
+ * helper can be used to back up any element that is stored in [Context.getFilesDir] or
+ * [Context.getSharedPreferences].
  *
  * After restoring is done, a [ACTION_RESTORE_FINISHED] intent will be send to SystemUI user 0,
  * indicating that restoring is finished for a given user.
@@ -47,9 +49,11 @@
         internal const val CONTROLS = ControlsFavoritePersistenceWrapper.FILE_NAME
         private const val NO_OVERWRITE_FILES_BACKUP_KEY = "systemui.files_no_overwrite"
         private const val PEOPLE_TILES_BACKUP_KEY = "systemui.people.shared_preferences"
+        private const val KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY =
+            "systemui.keyguard.quickaffordance.shared_preferences"
         val controlsDataLock = Any()
         const val ACTION_RESTORE_FINISHED = "com.android.systemui.backup.RESTORE_FINISHED"
-        private const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
+        const val PERMISSION_SELF = "com.android.systemui.permission.SELF"
     }
 
     override fun onCreate(userHandle: UserHandle, operationType: Int) {
@@ -67,17 +71,27 @@
         }
 
         val keys = PeopleBackupHelper.getFilesToBackup()
-        addHelper(PEOPLE_TILES_BACKUP_KEY, PeopleBackupHelper(
-                this, userHandle, keys.toTypedArray()))
+        addHelper(
+            PEOPLE_TILES_BACKUP_KEY,
+            PeopleBackupHelper(this, userHandle, keys.toTypedArray())
+        )
+        addHelper(
+            KEYGUARD_QUICK_AFFORDANCES_BACKUP_KEY,
+            KeyguardQuickAffordanceBackupHelper(
+                context = this,
+                userId = userHandle.identifier,
+            ),
+        )
     }
 
     override fun onRestoreFinished() {
         super.onRestoreFinished()
-        val intent = Intent(ACTION_RESTORE_FINISHED).apply {
-            `package` = packageName
-            putExtra(Intent.EXTRA_USER_ID, userId)
-            flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
-        }
+        val intent =
+            Intent(ACTION_RESTORE_FINISHED).apply {
+                `package` = packageName
+                putExtra(Intent.EXTRA_USER_ID, userId)
+                flags = Intent.FLAG_RECEIVER_REGISTERED_ONLY
+            }
         sendBroadcastAsUser(intent, UserHandle.SYSTEM, PERMISSION_SELF)
     }
 
@@ -90,7 +104,9 @@
      * @property lock a lock to hold while backing up and restoring the files.
      * @property context the context of the [BackupAgent]
      * @property fileNamesAndPostProcess a map from the filenames to back up and the post processing
+     * ```
      *                                   actions to take
+     * ```
      */
     private class NoOverwriteFileBackupHelper(
         val lock: Any,
@@ -115,23 +131,23 @@
             data: BackupDataOutput?,
             newState: ParcelFileDescriptor?
         ) {
-            synchronized(lock) {
-                super.performBackup(oldState, data, newState)
-            }
+            synchronized(lock) { super.performBackup(oldState, data, newState) }
         }
     }
 }
+
 private fun getPPControlsFile(context: Context): () -> Unit {
     return {
         val filesDir = context.filesDir
         val file = Environment.buildPath(filesDir, BackupHelper.CONTROLS)
         if (file.exists()) {
-            val dest = Environment.buildPath(filesDir,
-                AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
+            val dest =
+                Environment.buildPath(filesDir, AuxiliaryPersistenceWrapper.AUXILIARY_FILE_NAME)
             file.copyTo(dest)
             val jobScheduler = context.getSystemService(JobScheduler::class.java)
             jobScheduler?.schedule(
-                AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context))
+                AuxiliaryPersistenceWrapper.DeletionJobService.getJobForContext(context)
+            )
         }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index b2a2a67..b962cc4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -107,6 +107,8 @@
         if (shouldAnimateForTransition(lastState, newState)) {
             iconView.playAnimation()
             iconViewOverlay.playAnimation()
+        } else if (lastState == STATE_IDLE && newState == STATE_AUTHENTICATING_ANIMATING_IN) {
+            iconView.playAnimation()
         }
         LottieColorUtils.applyDynamicColors(context, iconView)
         LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index a7519cf..db2239b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -623,6 +623,10 @@
                     getFingerprintSensorLocationInNaturalOrientation(),
                     mCachedDisplayInfo);
         }
+
+        for (final Callback cb : mCallbacks) {
+            cb.onFingerprintLocationChanged();
+        }
     }
 
     /**
@@ -644,6 +648,10 @@
                     mCachedDisplayInfo
             );
         }
+
+        for (final Callback cb : mCallbacks) {
+            cb.onFaceSensorLocationChanged();
+        }
     }
 
     /**
@@ -1325,8 +1333,24 @@
         default void onBiometricPromptDismissed() {}
 
         /**
-         * The location in pixels can change due to resolution changes.
+         * Called when the location of the fingerprint sensor changes. The location in pixels can
+         * change due to resolution changes.
+         */
+        default void onFingerprintLocationChanged() {}
+
+        /**
+         * Called when the location of the under display fingerprint sensor changes. The location in
+         * pixels can change due to resolution changes.
+         *
+         * On devices with UDFPS, this is always called alongside
+         * {@link #onFingerprintLocationChanged}.
          */
         default void onUdfpsLocationChanged() {}
+
+        /**
+         * Called when the location of the face unlock sensor (typically the front facing camera)
+         * changes. The location in pixels can change due to resolution changes.
+         */
+        default void onFaceSensorLocationChanged() {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index fc5f447..d561cd7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -29,6 +29,8 @@
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.animation.Interpolators
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.CircleReveal
@@ -71,7 +73,8 @@
     private val biometricUnlockController: BiometricUnlockController,
     private val udfpsControllerProvider: Provider<UdfpsController>,
     private val statusBarStateController: StatusBarStateController,
-    rippleView: AuthRippleView?
+    private val featureFlags: FeatureFlags,
+        rippleView: AuthRippleView?
 ) : ViewController<AuthRippleView>(rippleView), KeyguardStateController.Callback,
     WakefulnessLifecycle.Observer {
 
@@ -116,9 +119,9 @@
         notificationShadeWindowController.setForcePluginOpen(false, this)
     }
 
-    fun showUnlockRipple(biometricSourceType: BiometricSourceType?) {
+    fun showUnlockRipple(biometricSourceType: BiometricSourceType) {
         if (!keyguardStateController.isShowing ||
-            keyguardUpdateMonitor.userNeedsStrongAuth()) {
+                !keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(biometricSourceType)) {
             return
         }
 
@@ -159,12 +162,17 @@
 
     private fun showUnlockedRipple() {
         notificationShadeWindowController.setForcePluginOpen(true, this)
-        val lightRevealScrim = centralSurfaces.lightRevealScrim
-        if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
-            circleReveal?.let {
-                lightRevealScrim?.revealAmount = 0f
-                lightRevealScrim?.revealEffect = it
-                startLightRevealScrimOnKeyguardFadingAway = true
+
+        // This code path is not used if the KeyguardTransitionRepository is managing the light
+        // reveal scrim.
+        if (!featureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+            val lightRevealScrim = centralSurfaces.lightRevealScrim
+            if (statusBarStateController.isDozing || biometricUnlockController.isWakeAndUnlock) {
+                circleReveal?.let {
+                    lightRevealScrim?.revealAmount = 0f
+                    lightRevealScrim?.revealEffect = it
+                    startLightRevealScrimOnKeyguardFadingAway = true
+                }
             }
         }
 
@@ -177,6 +185,10 @@
     }
 
     override fun onKeyguardFadingAwayChanged() {
+        if (featureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+            return
+        }
+
         if (keyguardStateController.isKeyguardFadingAway) {
             val lightRevealScrim = centralSurfaces.lightRevealScrim
             if (startLightRevealScrimOnKeyguardFadingAway && lightRevealScrim != null) {
@@ -246,7 +258,7 @@
         object : KeyguardUpdateMonitorCallback() {
             override fun onBiometricAuthenticated(
                 userId: Int,
-                biometricSourceType: BiometricSourceType?,
+                biometricSourceType: BiometricSourceType,
                 isStrongBiometric: Boolean
             ) {
                 if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
@@ -255,14 +267,14 @@
                 showUnlockRipple(biometricSourceType)
             }
 
-        override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType?) {
+        override fun onBiometricAuthFailed(biometricSourceType: BiometricSourceType) {
             if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                 mView.retractDwellRipple()
             }
         }
 
         override fun onBiometricAcquired(
-            biometricSourceType: BiometricSourceType?,
+            biometricSourceType: BiometricSourceType,
             acquireInfo: Int
         ) {
             if (biometricSourceType == BiometricSourceType.FINGERPRINT &&
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
index 1c3dd45..17ebdad 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/SideFpsController.kt
@@ -135,7 +135,7 @@
         WindowManager.LayoutParams(
                 WindowManager.LayoutParams.WRAP_CONTENT,
                 WindowManager.LayoutParams.WRAP_CONTENT,
-                WindowManager.LayoutParams.TYPE_SYSTEM_ERROR,
+                WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
                 Utils.FINGERPRINT_OVERLAY_LAYOUT_PARAM_FLAGS,
                 PixelFormat.TRANSLUCENT
             )
@@ -370,11 +370,15 @@
 private fun LottieAnimationView.addOverlayDynamicColor(context: Context) {
     fun update() {
         val c = context.getColor(R.color.biometric_dialog_accent)
+        val chevronFill = context.getColor(R.color.sfps_chevron_fill)
         for (key in listOf(".blue600", ".blue400")) {
             addValueCallback(KeyPath(key, "**"), LottieProperty.COLOR_FILTER) {
                 PorterDuffColorFilter(c, PorterDuff.Mode.SRC_ATOP)
             }
         }
+        addValueCallback(KeyPath(".black", "**"), LottieProperty.COLOR_FILTER) {
+            PorterDuffColorFilter(chevronFill, PorterDuff.Mode.SRC_ATOP)
+        }
     }
 
     if (composition != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 1d4281f..19b0548 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -62,6 +62,11 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.biometrics.dagger.BiometricsBackground;
+import com.android.systemui.biometrics.udfps.InteractionEvent;
+import com.android.systemui.biometrics.udfps.NormalizedTouchData;
+import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
+import com.android.systemui.biometrics.udfps.TouchProcessor;
+import com.android.systemui.biometrics.udfps.TouchProcessorResult;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.doze.DozeReceiver;
@@ -143,6 +148,7 @@
     @VisibleForTesting @NonNull final BiometricDisplayListener mOrientationListener;
     @NonNull private final ActivityLaunchAnimator mActivityLaunchAnimator;
     @NonNull private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    @Nullable private final TouchProcessor mTouchProcessor;
 
     // Currently the UdfpsController supports a single UDFPS sensor. If devices have multiple
     // sensors, this, in addition to a lot of the code here, will be updated.
@@ -166,7 +172,6 @@
 
     // The current request from FingerprintService. Null if no current request.
     @Nullable UdfpsControllerOverlay mOverlay;
-    @Nullable private UdfpsEllipseDetection mUdfpsEllipseDetection;
 
     // The fingerprint AOD trigger doesn't provide an ACTION_UP/ACTION_CANCEL event to tell us when
     // to turn off high brightness mode. To get around this limitation, the state of the AOD
@@ -355,10 +360,6 @@
         if (!mOverlayParams.equals(overlayParams)) {
             mOverlayParams = overlayParams;
 
-            if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
-                mUdfpsEllipseDetection.updateOverlayParams(overlayParams);
-            }
-
             final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateBouncer();
 
             // When the bounds change it's always necessary to re-create the overlay's window with
@@ -467,8 +468,99 @@
         return portraitTouch;
     }
 
+    private void tryDismissingKeyguard() {
+        if (!mOnFingerDown) {
+            playStartHaptic();
+        }
+        mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
+        mAttemptedToDismissKeyguard = true;
+    }
+
     @VisibleForTesting
     boolean onTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+        if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
+            return newOnTouch(requestId, event, fromUdfpsView);
+        } else {
+            return oldOnTouch(requestId, event, fromUdfpsView);
+        }
+    }
+
+    private boolean newOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
+        if (!fromUdfpsView) {
+            Log.e(TAG, "ignoring the touch injected from outside of UdfpsView");
+            return false;
+        }
+        if (mOverlay == null) {
+            Log.w(TAG, "ignoring onTouch with null overlay");
+            return false;
+        }
+        if (!mOverlay.matchesRequestId(requestId)) {
+            Log.w(TAG, "ignoring stale touch event: " + requestId + " current: "
+                    + mOverlay.getRequestId());
+            return false;
+        }
+
+        final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId,
+                mOverlayParams);
+        if (result instanceof TouchProcessorResult.Failure) {
+            Log.w(TAG, ((TouchProcessorResult.Failure) result).getReason());
+            return false;
+        }
+
+        final TouchProcessorResult.ProcessedTouch processedTouch =
+                (TouchProcessorResult.ProcessedTouch) result;
+        final NormalizedTouchData data = processedTouch.getTouchData();
+
+        mActivePointerId = processedTouch.getPointerOnSensorId();
+        switch (processedTouch.getEvent()) {
+            case DOWN:
+                if (shouldTryToDismissKeyguard()) {
+                    tryDismissingKeyguard();
+                }
+                onFingerDown(requestId,
+                        data.getPointerId(),
+                        data.getX(),
+                        data.getY(),
+                        data.getMinor(),
+                        data.getMajor(),
+                        data.getOrientation(),
+                        data.getTime(),
+                        data.getGestureStart(),
+                        mStatusBarStateController.isDozing());
+                break;
+
+            case UP:
+            case CANCEL:
+                if (InteractionEvent.CANCEL.equals(processedTouch.getEvent())) {
+                    Log.w(TAG, "This is a CANCEL event that's reported as an UP event!");
+                }
+                mAttemptedToDismissKeyguard = false;
+                onFingerUp(requestId,
+                        mOverlay.getOverlayView(),
+                        data.getPointerId(),
+                        data.getX(),
+                        data.getY(),
+                        data.getMinor(),
+                        data.getMajor(),
+                        data.getOrientation(),
+                        data.getTime(),
+                        data.getGestureStart(),
+                        mStatusBarStateController.isDozing());
+                mFalsingManager.isFalseTouch(UDFPS_AUTHENTICATION);
+                break;
+
+
+            default:
+                break;
+        }
+
+        // We should only consume touches that are within the sensor. By returning "false" for
+        // touches outside of the sensor, we let other UI components consume these events and act on
+        // them appropriately.
+        return processedTouch.getTouchData().isWithinSensor(mOverlayParams.getNativeSensorBounds());
+    }
+
+    private boolean oldOnTouch(long requestId, @NonNull MotionEvent event, boolean fromUdfpsView) {
         if (mOverlay == null) {
             Log.w(TAG, "ignoring onTouch with null overlay");
             return false;
@@ -498,23 +590,8 @@
                     mVelocityTracker.clear();
                 }
 
-                boolean withinSensorArea;
-                if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                    if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
-                        // Ellipse detection
-                        withinSensorArea = mUdfpsEllipseDetection.isGoodEllipseOverlap(event);
-                    } else {
-                        // Centroid with expanded overlay
-                        withinSensorArea =
-                            isWithinSensorArea(udfpsView, event.getRawX(),
-                                        event.getRawY(), fromUdfpsView);
-                    }
-                } else {
-                    // Centroid with sensor sized view
-                    withinSensorArea =
+                final boolean withinSensorArea =
                         isWithinSensorArea(udfpsView, event.getX(), event.getY(), fromUdfpsView);
-                }
-
                 if (withinSensorArea) {
                     Trace.beginAsyncSection("UdfpsController.e2e.onPointerDown", 0);
                     Log.v(TAG, "onTouch | action down");
@@ -528,11 +605,7 @@
                 }
                 if ((withinSensorArea || fromUdfpsView) && shouldTryToDismissKeyguard()) {
                     Log.v(TAG, "onTouch | dismiss keyguard ACTION_DOWN");
-                    if (!mOnFingerDown) {
-                        playStartHaptic();
-                    }
-                    mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
-                    mAttemptedToDismissKeyguard = true;
+                    tryDismissingKeyguard();
                 }
 
                 Trace.endSection();
@@ -545,33 +618,13 @@
                         ? event.getPointerId(0)
                         : event.findPointerIndex(mActivePointerId);
                 if (idx == event.getActionIndex()) {
-                    boolean actionMoveWithinSensorArea;
-                    if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
-                        if (mFeatureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
-                            // Ellipse detection
-                            actionMoveWithinSensorArea =
-                                    mUdfpsEllipseDetection.isGoodEllipseOverlap(event);
-                        } else {
-                            // Centroid with expanded overlay
-                            actionMoveWithinSensorArea =
-                                isWithinSensorArea(udfpsView, event.getRawX(idx),
-                                        event.getRawY(idx), fromUdfpsView);
-                        }
-                    } else {
-                        // Centroid with sensor sized view
-                        actionMoveWithinSensorArea =
-                            isWithinSensorArea(udfpsView, event.getX(idx),
-                                    event.getY(idx), fromUdfpsView);
-                    }
-
+                    final boolean actionMoveWithinSensorArea =
+                            isWithinSensorArea(udfpsView, event.getX(idx), event.getY(idx),
+                                    fromUdfpsView);
                     if ((fromUdfpsView || actionMoveWithinSensorArea)
                             && shouldTryToDismissKeyguard()) {
                         Log.v(TAG, "onTouch | dismiss keyguard ACTION_MOVE");
-                        if (!mOnFingerDown) {
-                            playStartHaptic();
-                        }
-                        mKeyguardViewManager.notifyKeyguardAuthenticated(false /* strongAuth */);
-                        mAttemptedToDismissKeyguard = true;
+                        tryDismissingKeyguard();
                         break;
                     }
                     // Map the touch to portrait mode if the device is in landscape mode.
@@ -696,7 +749,8 @@
             @NonNull ActivityLaunchAnimator activityLaunchAnimator,
             @NonNull Optional<AlternateUdfpsTouchProvider> alternateTouchProvider,
             @NonNull @BiometricsBackground Executor biometricsExecutor,
-            @NonNull PrimaryBouncerInteractor primaryBouncerInteractor) {
+            @NonNull PrimaryBouncerInteractor primaryBouncerInteractor,
+            @NonNull SinglePointerTouchProcessor singlePointerTouchProcessor) {
         mContext = context;
         mExecution = execution;
         mVibrator = vibrator;
@@ -737,6 +791,9 @@
         mBiometricExecutor = biometricsExecutor;
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
 
+        mTouchProcessor = mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)
+                ? singlePointerTouchProcessor : null;
+
         mDumpManager.registerDumpable(TAG, this);
 
         mOrientationListener = new BiometricDisplayListener(
@@ -761,10 +818,6 @@
 
         udfpsHapticsSimulator.setUdfpsController(this);
         udfpsShell.setUdfpsOverlayController(mUdfpsOverlayController);
-
-        if (featureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
-            mUdfpsEllipseDetection = new UdfpsEllipseDetection(mOverlayParams);
-        }
     }
 
     /**
@@ -946,7 +999,36 @@
         return mOnFingerDown;
     }
 
-    private void onFingerDown(long requestId, int x, int y, float minor, float major) {
+    private void onFingerDown(
+            long requestId,
+            int x,
+            int y,
+            float minor,
+            float major) {
+        onFingerDown(
+                requestId,
+                MotionEvent.INVALID_POINTER_ID /* pointerId */,
+                x,
+                y,
+                minor,
+                major,
+                0f /* orientation */,
+                0L /* time */,
+                0L /* gestureStart */,
+                false /* isAod */);
+    }
+
+    private void onFingerDown(
+            long requestId,
+            int pointerId,
+            float x,
+            float y,
+            float minor,
+            float major,
+            float orientation,
+            long time,
+            long gestureStart,
+            boolean isAod) {
         mExecution.assertIsMainThread();
 
         if (mOverlay == null) {
@@ -975,7 +1057,7 @@
         mOnFingerDown = true;
         if (mAlternateTouchProvider != null) {
             mBiometricExecutor.execute(() -> {
-                mAlternateTouchProvider.onPointerDown(requestId, x, y, minor, major);
+                mAlternateTouchProvider.onPointerDown(requestId, (int) x, (int) y, minor, major);
             });
             mFgExecutor.execute(() -> {
                 if (mKeyguardUpdateMonitor.isFingerprintDetectionRunning()) {
@@ -983,7 +1065,13 @@
                 }
             });
         } else {
-            mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, x, y, minor, major);
+            if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
+                mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, pointerId, x, y,
+                        minor, major, orientation, time, gestureStart, isAod);
+            } else {
+                mFingerprintManager.onPointerDown(requestId, mSensorProps.sensorId, (int) x,
+                        (int) y, minor, major);
+            }
         }
         Trace.endAsyncSection("UdfpsController.e2e.onPointerDown", 0);
         final UdfpsView view = mOverlay.getOverlayView();
@@ -1007,6 +1095,32 @@
     }
 
     private void onFingerUp(long requestId, @NonNull UdfpsView view) {
+        onFingerUp(
+                requestId,
+                view,
+                MotionEvent.INVALID_POINTER_ID /* pointerId */,
+                0f /* x */,
+                0f /* y */,
+                0f /* minor */,
+                0f /* major */,
+                0f /* orientation */,
+                0L /* time */,
+                0L /* gestureStart */,
+                false /* isAod */);
+    }
+
+    private void onFingerUp(
+            long requestId,
+            @NonNull UdfpsView view,
+            int pointerId,
+            float x,
+            float y,
+            float minor,
+            float major,
+            float orientation,
+            long time,
+            long gestureStart,
+            boolean isAod) {
         mExecution.assertIsMainThread();
         mActivePointerId = -1;
         mAcquiredReceived = false;
@@ -1021,7 +1135,12 @@
                     }
                 });
             } else {
-                mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
+                if (mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)) {
+                    mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x,
+                            y, minor, major, orientation, time, gestureStart, isAod);
+                } else {
+                    mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId);
+                }
             }
             for (Callback cb : mCallbacks) {
                 cb.onFingerUp();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt
deleted file mode 100644
index 8ae4775..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEllipseDetection.kt
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.biometrics
-
-import android.graphics.Point
-import android.graphics.Rect
-import android.util.RotationUtils
-import android.view.MotionEvent
-import kotlin.math.cos
-import kotlin.math.pow
-import kotlin.math.sin
-
-private const val TAG = "UdfpsEllipseDetection"
-
-private const val NEEDED_POINTS = 2
-
-class UdfpsEllipseDetection(overlayParams: UdfpsOverlayParams) {
-    var sensorRect = Rect()
-    var points: Array<Point> = emptyArray()
-
-    init {
-        sensorRect = Rect(overlayParams.sensorBounds)
-
-        points = calculateSensorPoints(sensorRect)
-    }
-
-    fun updateOverlayParams(params: UdfpsOverlayParams) {
-        sensorRect = Rect(params.sensorBounds)
-
-        val rot = params.rotation
-        RotationUtils.rotateBounds(
-            sensorRect,
-            params.naturalDisplayWidth,
-            params.naturalDisplayHeight,
-            rot
-        )
-
-        points = calculateSensorPoints(sensorRect)
-    }
-
-    fun isGoodEllipseOverlap(event: MotionEvent): Boolean {
-        return points.count { checkPoint(event, it) } >= NEEDED_POINTS
-    }
-
-    private fun checkPoint(event: MotionEvent, point: Point): Boolean {
-        // Calculate if sensor point is within ellipse
-        // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE -
-        // yS))^2 / b^2) <= 1
-        val a: Float = cos(event.orientation) * (point.x - event.rawX)
-        val b: Float = sin(event.orientation) * (point.y - event.rawY)
-        val c: Float = sin(event.orientation) * (point.x - event.rawX)
-        val d: Float = cos(event.orientation) * (point.y - event.rawY)
-        val result =
-            (a + b).pow(2) / (event.touchMinor / 2).pow(2) +
-                (c - d).pow(2) / (event.touchMajor / 2).pow(2)
-
-        return result <= 1
-    }
-}
-
-fun calculateSensorPoints(sensorRect: Rect): Array<Point> {
-    val sensorX = sensorRect.centerX()
-    val sensorY = sensorRect.centerY()
-    val cornerOffset: Int = sensorRect.width() / 4
-    val sideOffset: Int = sensorRect.width() / 3
-
-    return arrayOf(
-        Point(sensorX - cornerOffset, sensorY - cornerOffset),
-        Point(sensorX, sensorY - sideOffset),
-        Point(sensorX + cornerOffset, sensorY - cornerOffset),
-        Point(sensorX - sideOffset, sensorY),
-        Point(sensorX, sensorY),
-        Point(sensorX + sideOffset, sensorY),
-        Point(sensorX - cornerOffset, sensorY + cornerOffset),
-        Point(sensorX, sensorY + sideOffset),
-        Point(sensorX + cornerOffset, sensorY + cornerOffset)
-    )
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index 1e35958..3e1c4e5 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -20,6 +20,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.PointF;
@@ -28,6 +29,7 @@
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
+import android.util.AttributeSet;
 import android.view.animation.AccelerateDecelerateInterpolator;
 
 import androidx.annotation.NonNull;
@@ -68,25 +70,29 @@
     private boolean mShouldShowTipHint = false;
     private boolean mShouldShowEdgeHint = false;
 
-    UdfpsEnrollDrawable(@NonNull Context context) {
+    private int mEnrollIcon;
+    private int mMovingTargetFill;
+
+    UdfpsEnrollDrawable(@NonNull Context context, @Nullable AttributeSet attrs) {
         super(context);
 
+        loadResources(context, attrs);
         mSensorOutlinePaint = new Paint(0 /* flags */);
         mSensorOutlinePaint.setAntiAlias(true);
-        mSensorOutlinePaint.setColor(context.getColor(R.color.udfps_moving_target_fill));
+        mSensorOutlinePaint.setColor(mMovingTargetFill);
         mSensorOutlinePaint.setStyle(Paint.Style.FILL);
 
         mBlueFill = new Paint(0 /* flags */);
         mBlueFill.setAntiAlias(true);
-        mBlueFill.setColor(context.getColor(R.color.udfps_moving_target_fill));
+        mBlueFill.setColor(mMovingTargetFill);
         mBlueFill.setStyle(Paint.Style.FILL);
 
         mMovingTargetFpIcon = context.getResources()
                 .getDrawable(R.drawable.ic_kg_fingerprint, null);
-        mMovingTargetFpIcon.setTint(context.getColor(R.color.udfps_enroll_icon));
+        mMovingTargetFpIcon.setTint(mEnrollIcon);
         mMovingTargetFpIcon.mutate();
 
-        getFingerprintDrawable().setTint(context.getColor(R.color.udfps_enroll_icon));
+        getFingerprintDrawable().setTint(mEnrollIcon);
 
         mTargetAnimListener = new Animator.AnimatorListener() {
             @Override
@@ -105,6 +111,16 @@
         };
     }
 
+    void loadResources(Context context, @Nullable AttributeSet attrs) {
+        final TypedArray ta = context.obtainStyledAttributes(attrs,
+                R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
+                R.style.BiometricsEnrollStyle);
+        mEnrollIcon = ta.getColor(R.styleable.BiometricsEnrollView_biometricsEnrollIcon, 0);
+        mMovingTargetFill = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0);
+        ta.recycle();
+    }
+
     void setEnrollHelper(@NonNull UdfpsEnrollHelper helper) {
         mEnrollHelper = helper;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index af7e0b6..66a8424 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -18,6 +18,7 @@
 
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Paint;
@@ -26,6 +27,7 @@
 import android.os.VibrationAttributes;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
+import android.util.AttributeSet;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -93,17 +95,25 @@
     @Nullable private ValueAnimator mCheckmarkAnimator;
     @NonNull private final ValueAnimator.AnimatorUpdateListener mCheckmarkUpdateListener;
 
-    public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
+    private int mMovingTargetFill;
+    private int mMovingTargetFillError;
+    private int mEnrollProgress;
+    private int mEnrollProgressHelp;
+    private int mEnrollProgressHelpWithTalkback;
+
+    public UdfpsEnrollProgressBarDrawable(@NonNull Context context, @Nullable AttributeSet attrs) {
         mContext = context;
+
+        loadResources(context, attrs);
         mStrokeWidthPx = Utils.dpToPixels(context, STROKE_WIDTH_DP);
-        mProgressColor = context.getColor(R.color.udfps_enroll_progress);
+        mProgressColor = mEnrollProgress;
         final AccessibilityManager am = context.getSystemService(AccessibilityManager.class);
         mIsAccessibilityEnabled = am.isTouchExplorationEnabled();
-        mOnFirstBucketFailedColor = context.getColor(R.color.udfps_moving_target_fill_error);
+        mOnFirstBucketFailedColor = mMovingTargetFillError;
         if (!mIsAccessibilityEnabled) {
-            mHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
+            mHelpColor = mEnrollProgressHelp;
         } else {
-            mHelpColor = context.getColor(R.color.udfps_enroll_progress_help_with_talkback);
+            mHelpColor = mEnrollProgressHelpWithTalkback;
         }
         mCheckmarkDrawable = context.getDrawable(R.drawable.udfps_enroll_checkmark);
         mCheckmarkDrawable.mutate();
@@ -111,7 +121,7 @@
 
         mBackgroundPaint = new Paint();
         mBackgroundPaint.setStrokeWidth(mStrokeWidthPx);
-        mBackgroundPaint.setColor(context.getColor(R.color.udfps_moving_target_fill));
+        mBackgroundPaint.setColor(mMovingTargetFill);
         mBackgroundPaint.setAntiAlias(true);
         mBackgroundPaint.setStyle(Paint.Style.STROKE);
         mBackgroundPaint.setStrokeCap(Paint.Cap.ROUND);
@@ -147,6 +157,23 @@
         };
     }
 
+    void loadResources(Context context, @Nullable AttributeSet attrs) {
+        final TypedArray ta = context.obtainStyledAttributes(attrs,
+                R.styleable.BiometricsEnrollView, R.attr.biometricsEnrollStyle,
+                R.style.BiometricsEnrollStyle);
+        mMovingTargetFill = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsMovingTargetFill, 0);
+        mMovingTargetFillError = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsMovingTargetFillError, 0);
+        mEnrollProgress = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsEnrollProgress, 0);
+        mEnrollProgressHelp = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelp, 0);
+        mEnrollProgressHelpWithTalkback = ta.getColor(
+                R.styleable.BiometricsEnrollView_biometricsEnrollProgressHelpWithTalkback, 0);
+        ta.recycle();
+    }
+
     void onEnrollmentProgress(int remaining, int totalSteps) {
         mAfterFirstTouch = true;
         updateState(remaining, totalSteps, false /* showingHelp */);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 87be42c..1cc4141 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -47,8 +47,8 @@
 
     public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
-        mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
-        mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context);
+        mFingerprintDrawable = new UdfpsEnrollDrawable(mContext, attrs);
+        mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, attrs);
         mHandler = new Handler(Looper.getMainLooper());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
index c23b0f0..7f3846c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsOverlayParams.kt
@@ -7,17 +7,23 @@
 /**
  * Collection of parameters that define an under-display fingerprint sensor (UDFPS) overlay.
  *
- * @property sensorBounds coordinates of the bounding box around the sensor, in natural orientation,
- *     in pixels, for the current resolution.
- * @property naturalDisplayWidth width of the physical display, in natural orientation, in pixels,
- *     for the current resolution.
- * @property naturalDisplayHeight height of the physical display, in natural orientation, in pixels,
- *     for the current resolution.
- * @property scaleFactor ratio of a dimension in the current resolution to the corresponding
- *     dimension in the native resolution.
- * @property rotation current rotation of the display.
+ * [sensorBounds] coordinates of the bounding box around the sensor in natural orientation, in
+ * pixels, for the current resolution.
+ *
+ * [overlayBounds] coordinates of the UI overlay in natural orientation, in pixels, for the current
+ * resolution.
+ *
+ * [naturalDisplayWidth] width of the physical display in natural orientation, in pixels, for the
+ * current resolution.
+ *
+ * [naturalDisplayHeight] height of the physical display in natural orientation, in pixels, for the
+ * current resolution.
+ *
+ * [scaleFactor] ratio of a dimension in the current resolution to the corresponding dimension in
+ * the native resolution.
+ *
+ * [rotation] current rotation of the display.
  */
-
 data class UdfpsOverlayParams(
     val sensorBounds: Rect = Rect(),
     val overlayBounds: Rect = Rect(),
@@ -26,17 +32,21 @@
     val scaleFactor: Float = 1f,
     @Rotation val rotation: Int = Surface.ROTATION_0
 ) {
+
+    /** Same as [sensorBounds], but in native resolution. */
+    val nativeSensorBounds = Rect(sensorBounds).apply { scale(1f / scaleFactor) }
+
     /** See [android.view.DisplayInfo.logicalWidth] */
-    val logicalDisplayWidth
-        get() = if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+    val logicalDisplayWidth =
+        if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
             naturalDisplayHeight
         } else {
             naturalDisplayWidth
         }
 
     /** See [android.view.DisplayInfo.logicalHeight] */
-    val logicalDisplayHeight
-        get() = if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
+    val logicalDisplayHeight =
+        if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
             naturalDisplayWidth
         } else {
             naturalDisplayHeight
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt
new file mode 100644
index 0000000..001fed7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/dagger/UdfpsModule.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.dagger
+
+import com.android.systemui.biometrics.udfps.BoundingBoxOverlapDetector
+import com.android.systemui.biometrics.udfps.EllipseOverlapDetector
+import com.android.systemui.biometrics.udfps.OverlapDetector
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import dagger.Module
+import dagger.Provides
+
+/** Dagger module for all things UDFPS. TODO(b/260558624): Move to BiometricsModule. */
+@Module
+interface UdfpsModule {
+    companion object {
+
+        @Provides
+        @SysUISingleton
+        fun providesOverlapDetector(featureFlags: FeatureFlags): OverlapDetector {
+            return if (featureFlags.isEnabled(Flags.UDFPS_ELLIPSE_DETECTION)) {
+                EllipseOverlapDetector()
+            } else {
+                BoundingBoxOverlapDetector()
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt
new file mode 100644
index 0000000..79a0acb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetector.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+import com.android.systemui.dagger.SysUISingleton
+
+/** Returns whether the touch coordinates are within the sensor's bounding box. */
+@SysUISingleton
+class BoundingBoxOverlapDetector : OverlapDetector {
+    override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean =
+        touchData.isWithinSensor(nativeSensorBounds)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
new file mode 100644
index 0000000..8572242
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/EllipseOverlapDetector.kt
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Point
+import android.graphics.Rect
+import com.android.systemui.dagger.SysUISingleton
+import kotlin.math.cos
+import kotlin.math.pow
+import kotlin.math.sin
+
+/**
+ * Approximates the touch as an ellipse and determines whether the ellipse has a sufficient overlap
+ * with the sensor.
+ */
+@SysUISingleton
+class EllipseOverlapDetector(private val neededPoints: Int = 2) : OverlapDetector {
+
+    override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
+        val points = calculateSensorPoints(nativeSensorBounds)
+        return points.count { checkPoint(it, touchData) } >= neededPoints
+    }
+
+    private fun checkPoint(point: Point, touchData: NormalizedTouchData): Boolean {
+        // Calculate if sensor point is within ellipse
+        // Formula: ((cos(o)(xE - xS) + sin(o)(yE - yS))^2 / a^2) + ((sin(o)(xE - xS) + cos(o)(yE -
+        // yS))^2 / b^2) <= 1
+        val a: Float = cos(touchData.orientation) * (point.x - touchData.x)
+        val b: Float = sin(touchData.orientation) * (point.y - touchData.y)
+        val c: Float = sin(touchData.orientation) * (point.x - touchData.x)
+        val d: Float = cos(touchData.orientation) * (point.y - touchData.y)
+        val result =
+            (a + b).pow(2) / (touchData.minor / 2).pow(2) +
+                (c - d).pow(2) / (touchData.major / 2).pow(2)
+
+        return result <= 1
+    }
+
+    private fun calculateSensorPoints(sensorBounds: Rect): List<Point> {
+        val sensorX = sensorBounds.centerX()
+        val sensorY = sensorBounds.centerY()
+        val cornerOffset: Int = sensorBounds.width() / 4
+        val sideOffset: Int = sensorBounds.width() / 3
+
+        return listOf(
+            Point(sensorX - cornerOffset, sensorY - cornerOffset),
+            Point(sensorX, sensorY - sideOffset),
+            Point(sensorX + cornerOffset, sensorY - cornerOffset),
+            Point(sensorX - sideOffset, sensorY),
+            Point(sensorX, sensorY),
+            Point(sensorX + sideOffset, sensorY),
+            Point(sensorX - cornerOffset, sensorY + cornerOffset),
+            Point(sensorX, sensorY + sideOffset),
+            Point(sensorX + cornerOffset, sensorY + cornerOffset)
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/InteractionEvent.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/InteractionEvent.kt
new file mode 100644
index 0000000..6e47dad
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/InteractionEvent.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.view.MotionEvent
+
+/** Interaction event between a finger and the under-display fingerprint sensor (UDFPS). */
+enum class InteractionEvent {
+    /**
+     * A finger entered the sensor area. This can originate from either [MotionEvent.ACTION_DOWN] or
+     * [MotionEvent.ACTION_MOVE].
+     */
+    DOWN,
+
+    /**
+     * A finger left the sensor area. This can originate from either [MotionEvent.ACTION_UP] or
+     * [MotionEvent.ACTION_MOVE].
+     */
+    UP,
+
+    /**
+     * The touch reporting has stopped. This corresponds to [MotionEvent.ACTION_CANCEL]. This should
+     * not be confused with [UP]. If there was a finger on the sensor, it may or may not still be on
+     * the sensor.
+     */
+    CANCEL,
+
+    /**
+     * The interaction hasn't changed since the previous event. The can originate from any of
+     * [MotionEvent.ACTION_DOWN], [MotionEvent.ACTION_MOVE], or [MotionEvent.ACTION_UP] if one of
+     * these is true:
+     * - There was previously a finger on the sensor, and that finger is still on the sensor.
+     * - There was previously no finger on the sensor, and there still isn't.
+     */
+    UNCHANGED,
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt
new file mode 100644
index 0000000..62bedc6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/NormalizedTouchData.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+import android.view.MotionEvent
+
+/** Touch data in natural orientation and native resolution. */
+data class NormalizedTouchData(
+
+    /**
+     * Value obtained from [MotionEvent.getPointerId], or [MotionEvent.INVALID_POINTER_ID] if the ID
+     * is not available.
+     */
+    val pointerId: Int,
+
+    /** [MotionEvent.getRawX] mapped to natural orientation and native resolution. */
+    val x: Float,
+
+    /** [MotionEvent.getRawY] mapped to natural orientation and native resolution. */
+    val y: Float,
+
+    /** [MotionEvent.getTouchMinor] mapped to natural orientation and native resolution. */
+    val minor: Float,
+
+    /** [MotionEvent.getTouchMajor] mapped to natural orientation and native resolution. */
+    val major: Float,
+
+    /** [MotionEvent.getOrientation] mapped to natural orientation. */
+    val orientation: Float,
+
+    /** [MotionEvent.getEventTime]. */
+    val time: Long,
+
+    /** [MotionEvent.getDownTime]. */
+    val gestureStart: Long,
+) {
+
+    /**
+     * [nativeSensorBounds] contains the location and dimensions of the sensor area in native
+     * resolution and natural orientation.
+     *
+     * Returns whether the coordinates of the given pointer are within the sensor's bounding box.
+     */
+    fun isWithinSensor(nativeSensorBounds: Rect): Boolean {
+        return nativeSensorBounds.left <= x &&
+            nativeSensorBounds.right >= x &&
+            nativeSensorBounds.top <= y &&
+            nativeSensorBounds.bottom >= y
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt
new file mode 100644
index 0000000..0fec8ff
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/OverlapDetector.kt
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+
+/** Determines whether the touch has a sufficient overlap with the sensor. */
+interface OverlapDetector {
+    fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
new file mode 100644
index 0000000..338bf66
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessor.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.PointF
+import android.util.RotationUtils
+import android.view.MotionEvent
+import android.view.MotionEvent.INVALID_POINTER_ID
+import android.view.Surface
+import com.android.systemui.biometrics.UdfpsOverlayParams
+import com.android.systemui.biometrics.udfps.TouchProcessorResult.Failure
+import com.android.systemui.biometrics.udfps.TouchProcessorResult.ProcessedTouch
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+
+/**
+ * TODO(b/259140693): Consider using an object pool of TouchProcessorResult to avoid allocations.
+ */
+@SysUISingleton
+class SinglePointerTouchProcessor @Inject constructor(val overlapDetector: OverlapDetector) :
+    TouchProcessor {
+
+    override fun processTouch(
+        event: MotionEvent,
+        previousPointerOnSensorId: Int,
+        overlayParams: UdfpsOverlayParams,
+    ): TouchProcessorResult {
+
+        fun preprocess(): PreprocessedTouch {
+            // TODO(b/253085297): Add multitouch support. pointerIndex can be > 0 for ACTION_MOVE.
+            val pointerIndex = 0
+            val touchData = event.normalize(pointerIndex, overlayParams)
+            val isGoodOverlap =
+                overlapDetector.isGoodOverlap(touchData, overlayParams.nativeSensorBounds)
+            return PreprocessedTouch(touchData, previousPointerOnSensorId, isGoodOverlap)
+        }
+
+        return when (event.actionMasked) {
+            MotionEvent.ACTION_DOWN -> processActionDown(preprocess())
+            MotionEvent.ACTION_MOVE -> processActionMove(preprocess())
+            MotionEvent.ACTION_UP -> processActionUp(preprocess())
+            MotionEvent.ACTION_CANCEL ->
+                processActionCancel(event.normalize(pointerIndex = 0, overlayParams))
+            else ->
+                Failure("Unsupported MotionEvent." + MotionEvent.actionToString(event.actionMasked))
+        }
+    }
+}
+
+private data class PreprocessedTouch(
+    val data: NormalizedTouchData,
+    val previousPointerOnSensorId: Int,
+    val isGoodOverlap: Boolean,
+)
+
+private fun processActionDown(touch: PreprocessedTouch): TouchProcessorResult {
+    return if (touch.isGoodOverlap) {
+        ProcessedTouch(InteractionEvent.DOWN, pointerOnSensorId = touch.data.pointerId, touch.data)
+    } else {
+        val event =
+            if (touch.data.pointerId == touch.previousPointerOnSensorId) {
+                InteractionEvent.UP
+            } else {
+                InteractionEvent.UNCHANGED
+            }
+        ProcessedTouch(event, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
+    }
+}
+
+private fun processActionMove(touch: PreprocessedTouch): TouchProcessorResult {
+    val hadPointerOnSensor = touch.previousPointerOnSensorId != INVALID_POINTER_ID
+    val interactionEvent =
+        when {
+            touch.isGoodOverlap && !hadPointerOnSensor -> InteractionEvent.DOWN
+            !touch.isGoodOverlap && hadPointerOnSensor -> InteractionEvent.UP
+            else -> InteractionEvent.UNCHANGED
+        }
+    val pointerOnSensorId =
+        when (interactionEvent) {
+            InteractionEvent.UNCHANGED -> touch.previousPointerOnSensorId
+            InteractionEvent.DOWN -> touch.data.pointerId
+            else -> INVALID_POINTER_ID
+        }
+    return ProcessedTouch(interactionEvent, pointerOnSensorId, touch.data)
+}
+
+private fun processActionUp(touch: PreprocessedTouch): TouchProcessorResult {
+    return if (touch.isGoodOverlap) {
+        ProcessedTouch(InteractionEvent.UP, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
+    } else {
+        val event =
+            if (touch.previousPointerOnSensorId != INVALID_POINTER_ID) {
+                InteractionEvent.UP
+            } else {
+                InteractionEvent.UNCHANGED
+            }
+        ProcessedTouch(event, pointerOnSensorId = INVALID_POINTER_ID, touch.data)
+    }
+}
+
+private fun processActionCancel(data: NormalizedTouchData): TouchProcessorResult {
+    return ProcessedTouch(InteractionEvent.CANCEL, pointerOnSensorId = INVALID_POINTER_ID, data)
+}
+
+/**
+ * Returns the touch information from the given [MotionEvent] with the relevant fields mapped to
+ * natural orientation and native resolution.
+ */
+private fun MotionEvent.normalize(
+    pointerIndex: Int,
+    overlayParams: UdfpsOverlayParams
+): NormalizedTouchData {
+    val naturalTouch: PointF = rotateToNaturalOrientation(pointerIndex, overlayParams)
+    val nativeX = naturalTouch.x / overlayParams.scaleFactor
+    val nativeY = naturalTouch.y / overlayParams.scaleFactor
+    val nativeMinor: Float = getTouchMinor(pointerIndex) / overlayParams.scaleFactor
+    val nativeMajor: Float = getTouchMajor(pointerIndex) / overlayParams.scaleFactor
+    return NormalizedTouchData(
+        pointerId = getPointerId(pointerIndex),
+        x = nativeX,
+        y = nativeY,
+        minor = nativeMinor,
+        major = nativeMajor,
+        // TODO(b/259311354): touch orientation should be reported relative to Surface.ROTATION_O.
+        orientation = getOrientation(pointerIndex),
+        time = eventTime,
+        gestureStart = downTime,
+    )
+}
+
+/**
+ * Returns the [MotionEvent.getRawX] and [MotionEvent.getRawY] of the given pointer as if the device
+ * is in the [Surface.ROTATION_0] orientation.
+ */
+private fun MotionEvent.rotateToNaturalOrientation(
+    pointerIndex: Int,
+    overlayParams: UdfpsOverlayParams
+): PointF {
+    val touchPoint = PointF(getRawX(pointerIndex), getRawY(pointerIndex))
+    val rot = overlayParams.rotation
+    if (rot == Surface.ROTATION_90 || rot == Surface.ROTATION_270) {
+        RotationUtils.rotatePointF(
+            touchPoint,
+            RotationUtils.deltaRotation(rot, Surface.ROTATION_0),
+            overlayParams.logicalDisplayWidth.toFloat(),
+            overlayParams.logicalDisplayHeight.toFloat()
+        )
+    }
+    return touchPoint
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt
new file mode 100644
index 0000000..ffcebf9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessor.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.view.MotionEvent
+import com.android.systemui.biometrics.UdfpsOverlayParams
+
+/**
+ * Determines whether a finger entered or left the area of the under-display fingerprint sensor
+ * (UDFPS). Maps the touch information from a [MotionEvent] to the orientation and scale independent
+ * [NormalizedTouchData].
+ */
+interface TouchProcessor {
+
+    /**
+     * [event] touch event to be processed.
+     *
+     * [previousPointerOnSensorId] pointerId for the finger that was on the sensor prior to this
+     * event. See [MotionEvent.getPointerId]. If there was no finger on the sensor, this should be
+     * set to [MotionEvent.INVALID_POINTER_ID].
+     *
+     * [overlayParams] contains the location and dimensions of the sensor area, as well as the scale
+     * factor and orientation of the overlay. See [UdfpsOverlayParams].
+     *
+     * Returns [TouchProcessorResult.ProcessedTouch] on success, and [TouchProcessorResult.Failure]
+     * on failure.
+     */
+    fun processTouch(
+        event: MotionEvent,
+        previousPointerOnSensorId: Int,
+        overlayParams: UdfpsOverlayParams,
+    ): TouchProcessorResult
+}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessorResult.kt b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessorResult.kt
new file mode 100644
index 0000000..be75bb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/udfps/TouchProcessorResult.kt
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.view.MotionEvent
+
+/** Contains all the possible returns types for [TouchProcessor.processTouch] */
+sealed class TouchProcessorResult {
+
+    /**
+     * [event] whether a finger entered or left the sensor area. See [InteractionEvent].
+     *
+     * [pointerOnSensorId] pointerId fof the finger that's currently on the sensor. See
+     * [MotionEvent.getPointerId]. If there is no finger on the sensor, the value is set to
+     * [MotionEvent.INVALID_POINTER_ID].
+     *
+     * [touchData] relevant data from the MotionEvent, mapped to natural orientation and native
+     * resolution. See [NormalizedTouchData].
+     */
+    data class ProcessedTouch(
+        val event: InteractionEvent,
+        val pointerOnSensorId: Int,
+        val touchData: NormalizedTouchData
+    ) : TouchProcessorResult()
+
+    /** [reason] the reason for the failure. */
+    data class Failure(val reason: String = "") : TouchProcessorResult()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
index 537cbc5..a0a892d 100644
--- a/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/broadcast/BroadcastDispatcher.kt
@@ -64,8 +64,9 @@
  * from SystemUI. That way the number of calls to [BroadcastReceiver.onReceive] can be reduced for
  * a given broadcast.
  *
- * Use only for IntentFilters with actions and optionally categories. It does not support,
- * permissions, schemes, data types, data authorities or priority different than 0.
+ * Use only for IntentFilters with actions and optionally categories. It does not support schemes,
+ * data types, data authorities or priority different than 0.
+ *
  * Cannot be used for getting sticky broadcasts (either as return of registering or as re-delivery).
  * Broadcast handling may be asynchronous *without* calling goAsync(), as it's running within sysui
  * and doesn't need to worry about being killed.
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
index 4dfcd63..66e5d7c4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
@@ -30,6 +30,7 @@
 import android.service.controls.ControlsProviderService
 import androidx.annotation.WorkerThread
 import com.android.settingslib.applications.DefaultAppInfo
+import com.android.systemui.R
 import java.util.Objects
 
 class ControlsServiceInfo(
@@ -59,7 +60,8 @@
      * instead of using the controls rendered by SystemUI.
      *
      * The activity must be in the same package, exported, enabled and protected by the
-     * [Manifest.permission.BIND_CONTROLS] permission.
+     * [Manifest.permission.BIND_CONTROLS] permission. Additionally, only packages declared in
+     * [R.array.config_controlsPreferredPackages] can declare activities for use as a panel.
      */
     var panelActivity: ComponentName? = null
         private set
@@ -70,6 +72,9 @@
     fun resolvePanelActivity() {
         if (resolved) return
         resolved = true
+        val validPackages = context.resources
+                .getStringArray(R.array.config_controlsPreferredPackages)
+        if (componentName.packageName !in validPackages) return
         panelActivity = _panelActivity?.let {
             val resolveInfos = mPm.queryIntentActivitiesAsUser(
                     Intent().setComponent(it),
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepository.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepository.kt
new file mode 100644
index 0000000..3d10ab9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepository.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls
+
+import kotlinx.coroutines.flow.StateFlow
+
+/** Repository for Device controls related settings. */
+interface ControlsSettingsRepository {
+    /** Whether device controls activity can be shown above lockscreen for this user. */
+    val canShowControlsInLockscreen: StateFlow<Boolean>
+
+    /** Whether trivial controls can be actioned from the lockscreen for this user. */
+    val allowActionOnTrivialControlsInLockscreen: StateFlow<Boolean>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepositoryImpl.kt
new file mode 100644
index 0000000..9dc422a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsSettingsRepositoryImpl.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls
+
+import android.provider.Settings
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.qs.SettingObserver
+import com.android.systemui.user.data.repository.UserRepository
+import com.android.systemui.util.settings.SecureSettings
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.stateIn
+
+/**
+ * This implementation uses an `@Application` [CoroutineScope] to provide hot flows for the values
+ * of the tracked settings.
+ */
+@SysUISingleton
+class ControlsSettingsRepositoryImpl
+@Inject
+constructor(
+    @Application private val scope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+    private val userRepository: UserRepository,
+    private val secureSettings: SecureSettings
+) : ControlsSettingsRepository {
+
+    override val canShowControlsInLockscreen =
+        makeFlowForSetting(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS)
+
+    override val allowActionOnTrivialControlsInLockscreen =
+        makeFlowForSetting(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)
+
+    @OptIn(ExperimentalCoroutinesApi::class)
+    private fun makeFlowForSetting(setting: String): StateFlow<Boolean> {
+        return userRepository.selectedUserInfo
+            .distinctUntilChanged()
+            .flatMapLatest { userInfo ->
+                conflatedCallbackFlow {
+                        val observer =
+                            object : SettingObserver(secureSettings, null, setting, userInfo.id) {
+                                override fun handleValueChanged(
+                                    value: Int,
+                                    observedChange: Boolean
+                                ) {
+                                    trySend(value == 1)
+                                }
+                            }
+                        observer.isListening = true
+                        trySend(observer.value == 1)
+                        awaitClose { observer.isListening = false }
+                    }
+                    .flowOn(backgroundDispatcher)
+                    .distinctUntilChanged()
+            }
+            .stateIn(
+                scope,
+                started = SharingStarted.Eagerly,
+                // When the observer starts listening, the flow will emit the current value
+                // so the initialValue here is irrelevant.
+                initialValue = false,
+            )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
index 870649d..7b1c623 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -34,7 +34,6 @@
 import com.android.internal.notification.NotificationAccessConfirmationActivityContract.EXTRA_USER_ID
 import com.android.systemui.Dumpable
 import com.android.systemui.backup.BackupHelper
-import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.controls.ControlStatus
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.management.ControlsListingController
@@ -62,11 +61,10 @@
     private val uiController: ControlsUiController,
     private val bindingController: ControlsBindingController,
     private val listingController: ControlsListingController,
-    private val broadcastDispatcher: BroadcastDispatcher,
     private val userFileManager: UserFileManager,
+    private val userTracker: UserTracker,
     optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
     dumpManager: DumpManager,
-    userTracker: UserTracker
 ) : Dumpable, ControlsController {
 
     companion object {
@@ -123,18 +121,15 @@
         userChanging = false
     }
 
-    private val userSwitchReceiver = object : BroadcastReceiver() {
-        override fun onReceive(context: Context, intent: Intent) {
-            if (intent.action == Intent.ACTION_USER_SWITCHED) {
-                userChanging = true
-                val newUser =
-                        UserHandle.of(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, sendingUserId))
-                if (currentUser == newUser) {
-                    userChanging = false
-                    return
-                }
-                setValuesForUser(newUser)
+    private val userTrackerCallback = object : UserTracker.Callback {
+        override fun onUserChanged(newUser: Int, userContext: Context) {
+            userChanging = true
+            val newUserHandle = UserHandle.of(newUser)
+            if (currentUser == newUserHandle) {
+                userChanging = false
+                return
             }
+            setValuesForUser(newUserHandle)
         }
     }
 
@@ -236,12 +231,7 @@
         dumpManager.registerDumpable(javaClass.name, this)
         resetFavorites()
         userChanging = false
-        broadcastDispatcher.registerReceiver(
-                userSwitchReceiver,
-                IntentFilter(Intent.ACTION_USER_SWITCHED),
-                executor,
-                UserHandle.ALL
-        )
+        userTracker.addCallback(userTrackerCallback, executor)
         context.registerReceiver(
             restoreFinishedReceiver,
             IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
@@ -253,7 +243,7 @@
     }
 
     fun destroy() {
-        broadcastDispatcher.unregisterReceiver(userSwitchReceiver)
+        userTracker.removeCallback(userTrackerCallback)
         context.unregisterReceiver(restoreFinishedReceiver)
         listingController.removeCallback(listingCallback)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
index 9e4a364..77d0496e4 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt
@@ -16,13 +16,10 @@
 
 package com.android.systemui.controls.dagger
 
-import android.content.ContentResolver
 import android.content.Context
-import android.database.ContentObserver
-import android.os.UserHandle
-import android.provider.Settings
 import com.android.internal.widget.LockPatternUtils
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
+import com.android.systemui.controls.ControlsSettingsRepository
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
 import com.android.systemui.controls.controller.ControlsTileResourceConfigurationImpl
@@ -31,12 +28,10 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.settings.SecureSettings
 import dagger.Lazy
+import kotlinx.coroutines.flow.StateFlow
 import java.util.Optional
 import javax.inject.Inject
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.asStateFlow
 
 /**
  * Pseudo-component to inject into classes outside `com.android.systemui.controls`.
@@ -46,47 +41,26 @@
  */
 @SysUISingleton
 class ControlsComponent @Inject constructor(
-    @ControlsFeatureEnabled private val featureEnabled: Boolean,
-    private val context: Context,
-    private val lazyControlsController: Lazy<ControlsController>,
-    private val lazyControlsUiController: Lazy<ControlsUiController>,
-    private val lazyControlsListingController: Lazy<ControlsListingController>,
-    private val lockPatternUtils: LockPatternUtils,
-    private val keyguardStateController: KeyguardStateController,
-    private val userTracker: UserTracker,
-    private val secureSettings: SecureSettings,
-    private val optionalControlsTileResourceConfiguration:
-        Optional<ControlsTileResourceConfiguration>
+        @ControlsFeatureEnabled private val featureEnabled: Boolean,
+        private val context: Context,
+        private val lazyControlsController: Lazy<ControlsController>,
+        private val lazyControlsUiController: Lazy<ControlsUiController>,
+        private val lazyControlsListingController: Lazy<ControlsListingController>,
+        private val lockPatternUtils: LockPatternUtils,
+        private val keyguardStateController: KeyguardStateController,
+        private val userTracker: UserTracker,
+        controlsSettingsRepository: ControlsSettingsRepository,
+        optionalControlsTileResourceConfiguration: Optional<ControlsTileResourceConfiguration>
 ) {
-    private val contentResolver: ContentResolver
-        get() = context.contentResolver
 
-    private val _canShowWhileLockedSetting = MutableStateFlow(false)
-    val canShowWhileLockedSetting = _canShowWhileLockedSetting.asStateFlow()
+    val canShowWhileLockedSetting: StateFlow<Boolean> =
+            controlsSettingsRepository.canShowControlsInLockscreen
 
     private val controlsTileResourceConfiguration: ControlsTileResourceConfiguration =
         optionalControlsTileResourceConfiguration.orElse(
             ControlsTileResourceConfigurationImpl()
         )
 
-    val showWhileLockedObserver = object : ContentObserver(null) {
-        override fun onChange(selfChange: Boolean) {
-            updateShowWhileLocked()
-        }
-    }
-
-    init {
-        if (featureEnabled) {
-            secureSettings.registerContentObserverForUser(
-                Settings.Secure.getUriFor(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS),
-                false, /* notifyForDescendants */
-                showWhileLockedObserver,
-                UserHandle.USER_ALL
-            )
-            updateShowWhileLocked()
-        }
-    }
-
     fun getControlsController(): Optional<ControlsController> {
         return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty()
     }
@@ -127,11 +101,6 @@
         return Visibility.AVAILABLE
     }
 
-    private fun updateShowWhileLocked() {
-        _canShowWhileLockedSetting.value = secureSettings.getIntForUser(
-            Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
-    }
-
     enum class Visibility {
         AVAILABLE, AVAILABLE_AFTER_UNLOCK, UNAVAILABLE
     }
diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
index 6f58abd..9ae605e 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt
@@ -20,6 +20,8 @@
 import android.content.pm.PackageManager
 import com.android.systemui.controls.ControlsMetricsLogger
 import com.android.systemui.controls.ControlsMetricsLoggerImpl
+import com.android.systemui.controls.ControlsSettingsRepository
+import com.android.systemui.controls.ControlsSettingsRepositoryImpl
 import com.android.systemui.controls.controller.ControlsBindingController
 import com.android.systemui.controls.controller.ControlsBindingControllerImpl
 import com.android.systemui.controls.controller.ControlsController
@@ -83,6 +85,11 @@
     abstract fun provideUiController(controller: ControlsUiControllerImpl): ControlsUiController
 
     @Binds
+    abstract fun provideSettingsManager(
+            manager: ControlsSettingsRepositoryImpl
+    ): ControlsSettingsRepository
+
+    @Binds
     abstract fun provideMetricsLogger(logger: ControlsMetricsLoggerImpl): ControlsMetricsLogger
 
     @Binds
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
index 1f7021e..041ed1d 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinatorImpl.kt
@@ -25,9 +25,6 @@
 import android.content.Context
 import android.content.pm.PackageManager
 import android.content.pm.ResolveInfo
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
 import android.os.UserHandle
 import android.os.VibrationEffect
 import android.provider.Settings.Secure
@@ -41,6 +38,7 @@
 import com.android.systemui.R
 import com.android.systemui.broadcast.BroadcastSender
 import com.android.systemui.controls.ControlsMetricsLogger
+import com.android.systemui.controls.ControlsSettingsRepository
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.ActivityStarter
@@ -69,17 +67,17 @@
     private val vibrator: VibratorHelper,
     private val secureSettings: SecureSettings,
     private val userContextProvider: UserContextProvider,
-    @Main mainHandler: Handler
+    private val controlsSettingsRepository: ControlsSettingsRepository,
 ) : ControlActionCoordinator {
     private var dialog: Dialog? = null
     private var pendingAction: Action? = null
     private var actionsInProgress = mutableSetOf<String>()
     private val isLocked: Boolean
         get() = !keyguardStateController.isUnlocked()
-    private var mAllowTrivialControls: Boolean = secureSettings.getIntForUser(
-            Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
-    private var mShowDeviceControlsInLockscreen: Boolean = secureSettings.getIntForUser(
-            Secure.LOCKSCREEN_SHOW_CONTROLS, 0, UserHandle.USER_CURRENT) != 0
+    private val allowTrivialControls: Boolean
+        get() = controlsSettingsRepository.allowActionOnTrivialControlsInLockscreen.value
+    private val showDeviceControlsInLockscreen: Boolean
+        get() = controlsSettingsRepository.canShowControlsInLockscreen.value
     override lateinit var activityContext: Context
 
     companion object {
@@ -87,38 +85,6 @@
         private const val MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG = 2
     }
 
-    init {
-        val lockScreenShowControlsUri =
-            secureSettings.getUriFor(Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS)
-        val showControlsUri =
-                secureSettings.getUriFor(Secure.LOCKSCREEN_SHOW_CONTROLS)
-        val controlsContentObserver = object : ContentObserver(mainHandler) {
-            override fun onChange(selfChange: Boolean, uri: Uri?) {
-                super.onChange(selfChange, uri)
-                when (uri) {
-                    lockScreenShowControlsUri -> {
-                        mAllowTrivialControls = secureSettings.getIntForUser(
-                                Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
-                                0, UserHandle.USER_CURRENT) != 0
-                    }
-                    showControlsUri -> {
-                        mShowDeviceControlsInLockscreen = secureSettings
-                                .getIntForUser(Secure.LOCKSCREEN_SHOW_CONTROLS,
-                                        0, UserHandle.USER_CURRENT) != 0
-                    }
-                }
-            }
-        }
-        secureSettings.registerContentObserverForUser(
-            lockScreenShowControlsUri,
-            false /* notifyForDescendants */, controlsContentObserver, UserHandle.USER_ALL
-        )
-        secureSettings.registerContentObserverForUser(
-            showControlsUri,
-            false /* notifyForDescendants */, controlsContentObserver, UserHandle.USER_ALL
-        )
-    }
-
     override fun closeDialogs() {
         val isActivityFinishing =
             (activityContext as? Activity)?.let { it.isFinishing || it.isDestroyed }
@@ -233,7 +199,7 @@
     @AnyThread
     @VisibleForTesting
     fun bouncerOrRun(action: Action) {
-        val authRequired = action.authIsRequired || !mAllowTrivialControls
+        val authRequired = action.authIsRequired || !allowTrivialControls
 
         if (keyguardStateController.isShowing() && authRequired) {
             if (isLocked) {
@@ -291,7 +257,7 @@
                 PREFS_CONTROLS_FILE, Context.MODE_PRIVATE)
         val attempts = prefs.getInt(PREFS_SETTINGS_DIALOG_ATTEMPTS, 0)
         if (attempts >= MAX_NUMBER_ATTEMPTS_CONTROLS_DIALOG ||
-                (mShowDeviceControlsInLockscreen && mAllowTrivialControls)) {
+                (showDeviceControlsInLockscreen && allowTrivialControls)) {
             return
         }
         val builder = AlertDialog
@@ -313,7 +279,7 @@
                     true
                 }
 
-        if (mShowDeviceControlsInLockscreen) {
+        if (showDeviceControlsInLockscreen) {
             dialog = builder
                     .setTitle(R.string.controls_settings_trivial_controls_dialog_title)
                     .setMessage(R.string.controls_settings_trivial_controls_dialog_message)
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
index d60a222..3d8e4cb 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DefaultBroadcastReceiverBinder.java
@@ -19,7 +19,6 @@
 import android.content.BroadcastReceiver;
 
 import com.android.systemui.GuestResetOrExitSessionReceiver;
-import com.android.systemui.GuestResumeSessionReceiver;
 import com.android.systemui.media.dialog.MediaOutputDialogReceiver;
 import com.android.systemui.people.widget.PeopleSpaceWidgetPinnedReceiver;
 import com.android.systemui.people.widget.PeopleSpaceWidgetProvider;
@@ -106,15 +105,6 @@
      */
     @Binds
     @IntoMap
-    @ClassKey(GuestResumeSessionReceiver.class)
-    public abstract BroadcastReceiver bindGuestResumeSessionReceiver(
-            GuestResumeSessionReceiver broadcastReceiver);
-
-    /**
-     *
-     */
-    @Binds
-    @IntoMap
     @ClassKey(GuestResetOrExitSessionReceiver.class)
     public abstract BroadcastReceiver bindGuestResetOrExitSessionReceiver(
             GuestResetOrExitSessionReceiver broadcastReceiver);
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
index 705a110..8b4b30c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/FrameworkServicesModule.java
@@ -32,6 +32,7 @@
 import android.app.UiModeManager;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
+import android.app.job.JobScheduler;
 import android.app.role.RoleManager;
 import android.app.smartspace.SmartspaceManager;
 import android.app.trust.TrustManager;
@@ -286,6 +287,12 @@
 
     @Provides
     @Singleton
+    static JobScheduler provideJobScheduler(Context context) {
+        return context.getSystemService(JobScheduler.class);
+    }
+
+    @Provides
+    @Singleton
     static InteractionJankMonitor provideInteractionJankMonitor() {
         return InteractionJankMonitor.getInstance();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
index 09743ef..85ba68c 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUICoreStartableModule.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.media.taptotransfer.receiver.MediaTttChipControllerReceiver
 import com.android.systemui.media.taptotransfer.sender.MediaTttSenderCoordinator
 import com.android.systemui.power.PowerUI
+import com.android.systemui.reardisplay.RearDisplayDialogController
 import com.android.systemui.recents.Recents
 import com.android.systemui.settings.dagger.MultiUserUtilsModule
 import com.android.systemui.shortcut.ShortcutKeyDispatcher
@@ -250,4 +251,11 @@
     @IntoMap
     @ClassKey(ChipbarCoordinator::class)
     abstract fun bindChipbarController(sysui: ChipbarCoordinator): CoreStartable
+
+
+    /** Inject into RearDisplayDialogController) */
+    @Binds
+    @IntoMap
+    @ClassKey(RearDisplayDialogController::class)
+    abstract fun bindRearDisplayDialogController(sysui: RearDisplayDialogController): CoreStartable
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index bcf5e7a..3a59f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -33,6 +33,7 @@
 import com.android.systemui.biometrics.AlternateUdfpsTouchProvider;
 import com.android.systemui.biometrics.UdfpsDisplayModeProvider;
 import com.android.systemui.biometrics.dagger.BiometricsModule;
+import com.android.systemui.biometrics.dagger.UdfpsModule;
 import com.android.systemui.classifier.FalsingModule;
 import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule;
 import com.android.systemui.controls.dagger.ControlsModule;
@@ -154,6 +155,7 @@
             TelephonyRepositoryModule.class,
             TemporaryDisplayModule.class,
             TunerModule.class,
+            UdfpsModule.class,
             UserModule.class,
             UtilModule.class,
             NoteTaskModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 0b69b80..5daf1ce 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -29,12 +29,13 @@
 import android.content.IntentFilter;
 import android.hardware.display.AmbientDisplayConfiguration;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.text.format.Formatter;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.view.Display;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.InstanceId;
 import com.android.internal.logging.UiEvent;
@@ -100,6 +101,7 @@
     private final BroadcastDispatcher mBroadcastDispatcher;
     private final AuthController mAuthController;
     private final KeyguardStateController mKeyguardStateController;
+    private final UserTracker mUserTracker;
     private final UiEventLogger mUiEventLogger;
 
     private long mNotificationPulseTime;
@@ -110,6 +112,14 @@
     private boolean mWantTouchScreenSensors;
     private boolean mWantSensors;
 
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    mDozeSensors.onUserSwitched();
+                }
+            };
+
     @VisibleForTesting
     public enum DozingUpdateUiEvent implements UiEventLogger.UiEventEnum {
         @UiEvent(doc = "Dozing updated due to notification.")
@@ -210,6 +220,7 @@
         mAuthController = authController;
         mUiEventLogger = uiEventLogger;
         mKeyguardStateController = keyguardStateController;
+        mUserTracker = userTracker;
     }
 
     @Override
@@ -234,7 +245,7 @@
             return;
         }
         mNotificationPulseTime = SystemClock.elapsedRealtime();
-        if (!mConfig.pulseOnNotificationEnabled(UserHandle.USER_CURRENT)) {
+        if (!mConfig.pulseOnNotificationEnabled(mUserTracker.getUserId())) {
             runIfNotNull(onPulseSuppressedListener);
             mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
             return;
@@ -490,12 +501,14 @@
         mBroadcastReceiver.register(mBroadcastDispatcher);
         mDockManager.addListener(mDockEventListener);
         mDozeHost.addCallback(mHostCallback);
+        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
     }
 
     private void unregisterCallbacks() {
         mBroadcastReceiver.unregister(mBroadcastDispatcher);
         mDozeHost.removeCallback(mHostCallback);
         mDockManager.removeListener(mDockEventListener);
+        mUserTracker.removeCallback(mUserChangedCallback);
     }
 
     private void stopListeningToAllTriggers() {
@@ -620,9 +633,6 @@
                 requestPulse(DozeLog.PULSE_REASON_INTENT, false, /* performedProxCheck */
                         null /* onPulseSuppressedListener */);
             }
-            if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
-                mDozeSensors.onUserSwitched();
-            }
         }
 
         public void register(BroadcastDispatcher broadcastDispatcher) {
@@ -630,7 +640,6 @@
                 return;
             }
             IntentFilter filter = new IntentFilter(PULSE_ACTION);
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
             broadcastDispatcher.registerReceiver(this, filter);
             mRegistered = true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
index 48159ae..46ce7a9 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutEngine.java
@@ -192,9 +192,7 @@
                         break;
                 }
 
-                // Add margin if specified by the complication. Otherwise add default margin
-                // between complications.
-                if (mLayoutParams.isMarginSpecified() || !isRoot) {
+                if (!isRoot) {
                     final int margin = mLayoutParams.getMargin(mDefaultMargin);
                     switch(direction) {
                         case ComplicationLayoutParams.DIRECTION_DOWN:
@@ -213,6 +211,19 @@
                 }
             });
 
+            if (mLayoutParams.constraintSpecified()) {
+                switch (direction) {
+                    case ComplicationLayoutParams.DIRECTION_START:
+                    case ComplicationLayoutParams.DIRECTION_END:
+                        params.matchConstraintMaxWidth = mLayoutParams.getConstraint();
+                        break;
+                    case ComplicationLayoutParams.DIRECTION_UP:
+                    case ComplicationLayoutParams.DIRECTION_DOWN:
+                        params.matchConstraintMaxHeight = mLayoutParams.getConstraint();
+                        break;
+                }
+            }
+
             mView.setLayoutParams(params);
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
index 4fae68d..1755cb92 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/ComplicationLayoutParams.java
@@ -52,6 +52,7 @@
     private static final int LAST_POSITION = POSITION_END;
 
     private static final int MARGIN_UNSPECIFIED = 0xFFFFFFFF;
+    private static final int CONSTRAINT_UNSPECIFIED = 0xFFFFFFFF;
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(flag = true, prefix = { "DIRECTION_" }, value = {
@@ -81,6 +82,8 @@
 
     private final int mMargin;
 
+    private final int mConstraint;
+
     private final boolean mSnapToGuide;
 
     // Do not allow specifying opposite positions
@@ -110,7 +113,8 @@
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
             @Direction int direction, int weight) {
-        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, false);
+        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, CONSTRAINT_UNSPECIFIED,
+                false);
     }
 
     /**
@@ -127,7 +131,27 @@
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
             @Direction int direction, int weight, int margin) {
-        this(width, height, position, direction, weight, margin, false);
+        this(width, height, position, direction, weight, margin, CONSTRAINT_UNSPECIFIED, false);
+    }
+
+    /**
+     * Constructs a {@link ComplicationLayoutParams}.
+     * @param width The width {@link android.view.View.MeasureSpec} for the view.
+     * @param height The height {@link android.view.View.MeasureSpec} for the view.
+     * @param position The place within the parent container where the view should be positioned.
+     * @param direction The direction the view should be laid out from either the parent container
+     *                  or preceding view.
+     * @param weight The weight that should be considered for this view when compared to other
+     *               views. This has an impact on the placement of the view but not the rendering of
+     *               the view.
+     * @param margin The margin to apply between complications.
+     * @param constraint The max width or height the complication is allowed to spread, depending on
+     *                   its direction. For horizontal directions, this would be applied on width,
+     *                   and for vertical directions, height.
+     */
+    public ComplicationLayoutParams(int width, int height, @Position int position,
+            @Direction int direction, int weight, int margin, int constraint) {
+        this(width, height, position, direction, weight, margin, constraint, false);
     }
 
     /**
@@ -148,7 +172,8 @@
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
             @Direction int direction, int weight, boolean snapToGuide) {
-        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, snapToGuide);
+        this(width, height, position, direction, weight, MARGIN_UNSPECIFIED, CONSTRAINT_UNSPECIFIED,
+                snapToGuide);
     }
 
     /**
@@ -162,6 +187,9 @@
      *               views. This has an impact on the placement of the view but not the rendering of
      *               the view.
      * @param margin The margin to apply between complications.
+     * @param constraint The max width or height the complication is allowed to spread, depending on
+     *                   its direction. For horizontal directions, this would be applied on width,
+     *                   and for vertical directions, height.
      * @param snapToGuide When set to {@code true}, the dimension perpendicular to the direction
      *                    will be automatically set to align with a predetermined guide for that
      *                    side. For example, if the complication is aligned to the top end and
@@ -169,7 +197,7 @@
      *                    from the end of the parent to the guide.
      */
     public ComplicationLayoutParams(int width, int height, @Position int position,
-            @Direction int direction, int weight, int margin, boolean snapToGuide) {
+            @Direction int direction, int weight, int margin, int constraint, boolean snapToGuide) {
         super(width, height);
 
         if (!validatePosition(position)) {
@@ -187,6 +215,8 @@
 
         mMargin = margin;
 
+        mConstraint = constraint;
+
         mSnapToGuide = snapToGuide;
     }
 
@@ -199,6 +229,7 @@
         mDirection = source.mDirection;
         mWeight = source.mWeight;
         mMargin = source.mMargin;
+        mConstraint = source.mConstraint;
         mSnapToGuide = source.mSnapToGuide;
     }
 
@@ -261,13 +292,6 @@
     }
 
     /**
-     * Returns whether margin has been specified by the complication.
-     */
-    public boolean isMarginSpecified() {
-        return mMargin != MARGIN_UNSPECIFIED;
-    }
-
-    /**
      * Returns the margin to apply between complications, or the given default if no margin is
      * specified.
      */
@@ -276,6 +300,21 @@
     }
 
     /**
+     * Returns whether the horizontal or vertical constraint has been specified.
+     */
+    public boolean constraintSpecified() {
+        return mConstraint != CONSTRAINT_UNSPECIFIED;
+    }
+
+    /**
+     * Returns the horizontal or vertical constraint of the complication, depending its direction.
+     * For horizontal directions, this is the max width, and for vertical directions, max height.
+     */
+    public int getConstraint() {
+        return mConstraint;
+    }
+
+    /**
      * Returns whether the complication's dimension perpendicular to direction should be
      * automatically set.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
index c01cf43..ee00512 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/DreamHomeControlsComplication.java
@@ -32,6 +32,7 @@
 import com.android.internal.logging.UiEvent;
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.CoreStartable;
+import com.android.systemui.R;
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.controls.ControlsServiceInfo;
 import com.android.systemui.controls.dagger.ControlsComponent;
@@ -151,7 +152,7 @@
         @Inject
         DreamHomeControlsChipViewHolder(
                 DreamHomeControlsChipViewController dreamHomeControlsChipViewController,
-                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
+                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) View view,
                 @Named(DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS) ComplicationLayoutParams layoutParams
         ) {
             mView = view;
@@ -174,7 +175,7 @@
     /**
      * Controls behavior of the dream complication.
      */
-    static class DreamHomeControlsChipViewController extends ViewController<ImageView> {
+    static class DreamHomeControlsChipViewController extends ViewController<View> {
         private static final String TAG = "DreamHomeControlsCtrl";
         private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -203,7 +204,7 @@
 
         @Inject
         DreamHomeControlsChipViewController(
-                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) ImageView view,
+                @Named(DREAM_HOME_CONTROLS_CHIP_VIEW) View view,
                 ActivityStarter activityStarter,
                 Context context,
                 ControlsComponent controlsComponent,
@@ -218,9 +219,10 @@
 
         @Override
         protected void onViewAttached() {
-            mView.setImageResource(mControlsComponent.getTileImageId());
-            mView.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
-            mView.setOnClickListener(this::onClickHomeControls);
+            final ImageView chip = mView.findViewById(R.id.home_controls_chip);
+            chip.setImageResource(mControlsComponent.getTileImageId());
+            chip.setContentDescription(mContext.getString(mControlsComponent.getTileTitleId()));
+            chip.setOnClickListener(this::onClickHomeControls);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
index 7d9f105..5290e44 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamClockTimeComplicationModule.java
@@ -45,11 +45,12 @@
     @Provides
     @Named(DREAM_CLOCK_TIME_COMPLICATION_VIEW)
     static View provideComplicationView(LayoutInflater layoutInflater) {
-        final TextClock view = Preconditions.checkNotNull((TextClock)
+        final View view = Preconditions.checkNotNull(
                         layoutInflater.inflate(R.layout.dream_overlay_complication_clock_time,
                                 null, false),
                 "R.layout.dream_overlay_complication_clock_time did not properly inflated");
-        view.setFontVariationSettings(TAG_WEIGHT + WEIGHT);
+        ((TextClock) view.findViewById(R.id.time_view)).setFontVariationSettings(
+                TAG_WEIGHT + WEIGHT);
         return view;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
index cf05d2d..a7aa97f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/DreamHomeControlsComplicationComponent.java
@@ -19,7 +19,7 @@
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 
 import android.view.LayoutInflater;
-import android.widget.ImageView;
+import android.view.View;
 
 import com.android.systemui.R;
 import com.android.systemui.dreams.complication.DreamHomeControlsComplication;
@@ -74,8 +74,8 @@
         @Provides
         @DreamHomeControlsComplicationScope
         @Named(DREAM_HOME_CONTROLS_CHIP_VIEW)
-        static ImageView provideHomeControlsChipView(LayoutInflater layoutInflater) {
-            return (ImageView) layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
+        static View provideHomeControlsChipView(LayoutInflater layoutInflater) {
+            return layoutInflater.inflate(R.layout.dream_overlay_home_controls_chip,
                     null, false);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
index a514c47..9b954f5f 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/complication/dagger/RegisteredComplicationsModule.java
@@ -47,10 +47,10 @@
     String DREAM_MEDIA_ENTRY_LAYOUT_PARAMS = "media_entry_layout_params";
 
     int DREAM_CLOCK_TIME_COMPLICATION_WEIGHT = 1;
-    int DREAM_SMARTSPACE_COMPLICATION_WEIGHT = 0;
+    int DREAM_SMARTSPACE_COMPLICATION_WEIGHT = 2;
     int DREAM_MEDIA_COMPLICATION_WEIGHT = 0;
-    int DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT = 2;
-    int DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT = 1;
+    int DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT = 4;
+    int DREAM_MEDIA_ENTRY_COMPLICATION_WEIGHT = 3;
 
     /**
      * Provides layout parameters for the clock time complication.
@@ -72,17 +72,14 @@
      */
     @Provides
     @Named(DREAM_HOME_CONTROLS_CHIP_LAYOUT_PARAMS)
-    static ComplicationLayoutParams provideHomeControlsChipLayoutParams(@Main Resources res) {
+    static ComplicationLayoutParams provideHomeControlsChipLayoutParams() {
         return new ComplicationLayoutParams(
-                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width),
-                res.getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height),
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
                 ComplicationLayoutParams.POSITION_BOTTOM
                         | ComplicationLayoutParams.POSITION_START,
-                ComplicationLayoutParams.DIRECTION_UP,
-                DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT,
-                // Add margin to the bottom of home controls to horizontally align with smartspace.
-                res.getDimensionPixelSize(
-                        R.dimen.dream_overlay_complication_home_controls_padding));
+                ComplicationLayoutParams.DIRECTION_END,
+                DREAM_HOME_CONTROLS_CHIP_COMPLICATION_WEIGHT);
     }
 
     /**
@@ -106,12 +103,14 @@
     @Provides
     @Named(DREAM_SMARTSPACE_LAYOUT_PARAMS)
     static ComplicationLayoutParams provideSmartspaceLayoutParams(@Main Resources res) {
-        return new ComplicationLayoutParams(0,
+        return new ComplicationLayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
                 ComplicationLayoutParams.POSITION_BOTTOM
                         | ComplicationLayoutParams.POSITION_START,
                 ComplicationLayoutParams.DIRECTION_END,
                 DREAM_SMARTSPACE_COMPLICATION_WEIGHT,
-                res.getDimensionPixelSize(R.dimen.dream_overlay_complication_smartspace_padding));
+                res.getDimensionPixelSize(R.dimen.dream_overlay_complication_smartspace_padding),
+                res.getDimensionPixelSize(R.dimen.dream_overlay_complication_smartspace_max_width));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index e2f86bd..8019b56 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -164,6 +164,13 @@
     // TODO(b/256513609): Tracking Bug
     @JvmField val ACTIVE_UNLOCK_CHIPBAR = releasedFlag(217, "active_unlock_chipbar")
 
+    /**
+     * Migrates control of the LightRevealScrim's reveal effect and amount from legacy code to the
+     * new KeyguardTransitionRepository.
+     */
+    @JvmField
+    val LIGHT_REVEAL_MIGRATION = unreleasedFlag(218, "light_reveal_migration", teamfood = true)
+
     // 300 - power menu
     // TODO(b/254512600): Tracking Bug
     @JvmField val POWER_MENU_LITE = releasedFlag(300, "power_menu_lite")
@@ -205,15 +212,6 @@
     @JvmField val QS_SECONDARY_DATA_SUB_INFO = releasedFlag(508, "qs_secondary_data_sub_info")
 
     // 600- status bar
-    // TODO(b/254512623): Tracking Bug
-    @Deprecated("Replaced by mobile and wifi specific flags.")
-    val NEW_STATUS_BAR_PIPELINE_BACKEND =
-        unreleasedFlag(604, "new_status_bar_pipeline_backend", teamfood = false)
-
-    // TODO(b/254512660): Tracking Bug
-    @Deprecated("Replaced by mobile and wifi specific flags.")
-    val NEW_STATUS_BAR_PIPELINE_FRONTEND =
-        unreleasedFlag(605, "new_status_bar_pipeline_frontend", teamfood = false)
 
     // TODO(b/256614753): Tracking Bug
     val NEW_STATUS_BAR_MOBILE_ICONS = unreleasedFlag(606, "new_status_bar_mobile_icons")
@@ -231,6 +229,10 @@
     // TODO(b/256623670): Tracking Bug
     @JvmField val BATTERY_SHIELD_ICON = unreleasedFlag(610, "battery_shield_icon")
 
+    // TODO(b/260881289): Tracking Bug
+    val NEW_STATUS_BAR_ICONS_DEBUG_COLORING =
+        unreleasedFlag(611, "new_status_bar_icons_debug_coloring")
+
     // 700 - dialer/calls
     // TODO(b/254512734): Tracking Bug
     val ONGOING_CALL_STATUS_BAR_CHIP = releasedFlag(700, "ongoing_call_status_bar_chip")
@@ -346,6 +348,12 @@
     // TODO(b/256873975): Tracking Bug
     @JvmField @Keep val WM_BUBBLE_BAR = unreleasedFlag(1111, "wm_bubble_bar")
 
+    // TODO(b/260271148): Tracking bug
+    @Keep
+    @JvmField
+    val WM_DESKTOP_WINDOWING_2 =
+        sysPropBooleanFlag(1112, "persist.wm.debug.desktop_mode_2", default = false)
+
     // 1200 - predictive back
     @Keep
     @JvmField
@@ -366,6 +374,11 @@
     @JvmField
     val NEW_BACK_AFFORDANCE = unreleasedFlag(1203, "new_back_affordance", teamfood = false)
 
+    // TODO(b/255854141): Tracking Bug
+    @JvmField
+    val WM_ENABLE_PREDICTIVE_BACK_SYSUI =
+        unreleasedFlag(1204, "persist.wm.debug.predictive_back_sysui_enable", teamfood = true)
+
     // 1300 - screenshots
     // TODO(b/254512719): Tracking Bug
     @JvmField val SCREENSHOT_REQUEST_PROCESSOR = releasedFlag(1300, "screenshot_request_processor")
@@ -386,21 +399,19 @@
     // 1600 - accessibility
     @JvmField
     val A11Y_FLOATING_MENU_FLING_SPRING_ANIMATIONS =
-        unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations")
+        unreleasedFlag(1600, "a11y_floating_menu_fling_spring_animations", teamfood = true)
 
     // 1700 - clipboard
     @JvmField val CLIPBOARD_OVERLAY_REFACTOR = releasedFlag(1700, "clipboard_overlay_refactor")
-    @JvmField
-    val CLIPBOARD_REMOTE_BEHAVIOR =
-        unreleasedFlag(1701, "clipboard_remote_behavior", teamfood = true)
+    @JvmField val CLIPBOARD_REMOTE_BEHAVIOR = releasedFlag(1701, "clipboard_remote_behavior")
 
     // 1800 - shade container
     @JvmField
     val LEAVE_SHADE_OPEN_FOR_BUGREPORT =
         unreleasedFlag(1800, "leave_shade_open_for_bugreport", teamfood = true)
 
-    // 1900 - note task
-    @JvmField val NOTE_TASKS = sysPropBooleanFlag(1900, "persist.sysui.debug.note_tasks")
+    // 1900
+    @JvmField val NOTE_TASKS = unreleasedFlag(1900, "keycode_flag")
 
     // 2000 - device controls
     @Keep @JvmField val USE_APP_PANELS = unreleasedFlag(2000, "use_app_panels", teamfood = true)
@@ -417,6 +428,12 @@
     // 2300 - stylus
     @JvmField val TRACK_STYLUS_EVER_USED = unreleasedFlag(2300, "track_stylus_ever_used")
 
+    // 2400 - performance tools and debugging info
+    // TODO(b/238923086): Tracking Bug
+    @JvmField
+    val WARN_ON_BLOCKING_BINDER_TRANSACTIONS =
+        unreleasedFlag(2400, "warn_on_blocking_binder_transactions")
+
     // TODO(b259590361): Tracking bug
     val EXPERIMENTAL_FLAG = unreleasedFlag(2, "exp_flag_release")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt
index 29febb6..4ae37c5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProvider.kt
@@ -29,7 +29,7 @@
 import com.android.systemui.SystemUIAppComponentFactoryBase
 import com.android.systemui.SystemUIAppComponentFactoryBase.ContextAvailableCallback
 import com.android.systemui.keyguard.domain.interactor.KeyguardQuickAffordanceInteractor
-import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
 import javax.inject.Inject
 import kotlinx.coroutines.runBlocking
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 0214313..e631816 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -220,6 +220,7 @@
                                 synchronized (mFinishCallbacks) {
                                     if (mFinishCallbacks.remove(transition) == null) return;
                                 }
+                                info.releaseAllSurfaces();
                                 Slog.d(TAG, "Finish IRemoteAnimationRunner.");
                                 finishCallback.onTransitionFinished(null /* wct */, null /* t */);
                             }
@@ -235,6 +236,8 @@
                     synchronized (mFinishCallbacks) {
                         origFinishCB = mFinishCallbacks.remove(transition);
                     }
+                    info.releaseAllSurfaces();
+                    t.close();
                     if (origFinishCB == null) {
                         // already finished (or not started yet), so do nothing.
                         return;
@@ -423,12 +426,15 @@
             t.apply();
             mBinder.setOccluded(true /* isOccluded */, true /* animate */);
             finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+            info.releaseAllSurfaces();
         }
 
         @Override
         public void mergeAnimation(IBinder transition, TransitionInfo info,
                 SurfaceControl.Transaction t, IBinder mergeTarget,
                 IRemoteTransitionFinishedCallback finishCallback) {
+            t.close();
+            info.releaseAllSurfaces();
         }
     };
 
@@ -440,12 +446,15 @@
             t.apply();
             mBinder.setOccluded(false /* isOccluded */, true /* animate */);
             finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
+            info.releaseAllSurfaces();
         }
 
         @Override
         public void mergeAnimation(IBinder transition, TransitionInfo info,
                 SurfaceControl.Transaction t, IBinder mergeTarget,
                 IRemoteTransitionFinishedCallback finishCallback) {
+            t.close();
+            info.releaseAllSurfaces();
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 5ed3ba7..36c939d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -870,7 +870,7 @@
                 @Override
                 public void onLaunchAnimationEnd(boolean launchIsFullScreen) {
                     if (launchIsFullScreen) {
-                        mCentralSurfaces.instantCollapseNotificationPanel();
+                        mShadeController.get().instantCollapseShade();
                     }
 
                     mOccludeAnimationPlaying = false;
@@ -2209,6 +2209,9 @@
                 case START_KEYGUARD_EXIT_ANIM:
                     Trace.beginSection(
                             "KeyguardViewMediator#handleMessage START_KEYGUARD_EXIT_ANIM");
+                    synchronized (KeyguardViewMediator.this) {
+                        mHiding = true;
+                    }
                     StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
                     mNotificationShadeWindowControllerLazy.get().batchApplyWindowLayoutParams(
                             () -> {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
index f5220b8..73dbeab 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/BuiltInKeyguardQuickAffordanceKeys.kt
@@ -25,6 +25,7 @@
 object BuiltInKeyguardQuickAffordanceKeys {
     // Please keep alphabetical order of const names to simplify future maintenance.
     const val CAMERA = "camera"
+    const val FLASHLIGHT = "flashlight"
     const val HOME_CONTROLS = "home"
     const val QR_CODE_SCANNER = "qr_code_scanner"
     const val QUICK_ACCESS_WALLET = "wallet"
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
index 3c09aab..dbc376e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfig.kt
@@ -26,14 +26,17 @@
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
+import dagger.Lazy
+import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.flowOf
-import javax.inject.Inject
 
 @SysUISingleton
-class CameraQuickAffordanceConfig @Inject constructor(
-        @Application private val context: Context,
-        private val cameraGestureHelper: CameraGestureHelper,
+class CameraQuickAffordanceConfig
+@Inject
+constructor(
+    @Application private val context: Context,
+    private val cameraGestureHelper: Lazy<CameraGestureHelper>,
 ) : KeyguardQuickAffordanceConfig {
 
     override val key: String
@@ -46,17 +49,23 @@
         get() = com.android.internal.R.drawable.perm_group_camera
 
     override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState>
-        get() = flowOf(
-            KeyguardQuickAffordanceConfig.LockScreenState.Visible(
-                    icon = Icon.Resource(
+        get() =
+            flowOf(
+                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+                    icon =
+                        Icon.Resource(
                             com.android.internal.R.drawable.perm_group_camera,
                             ContentDescription.Resource(R.string.accessibility_camera_button)
-                    )
+                        )
+                )
             )
-        )
 
-    override fun onTriggered(expandable: Expandable?): KeyguardQuickAffordanceConfig.OnTriggeredResult {
-        cameraGestureHelper.launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
+    override fun onTriggered(
+        expandable: Expandable?
+    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+        cameraGestureHelper
+            .get()
+            .launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
         return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
new file mode 100644
index 0000000..62fe80a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfig.kt
@@ -0,0 +1,146 @@
+/*
+ *  Copyright (C) 2022 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.Context
+import com.android.systemui.R
+import com.android.systemui.animation.Expandable
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.common.shared.model.ContentDescription
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
+import com.android.systemui.statusbar.policy.FlashlightController
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+@SysUISingleton
+class FlashlightQuickAffordanceConfig
+@Inject
+constructor(
+    @Application private val context: Context,
+    private val flashlightController: FlashlightController,
+) : KeyguardQuickAffordanceConfig {
+
+    private sealed class FlashlightState {
+
+        abstract fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState
+
+        object On : FlashlightState() {
+            override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState =
+                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+                    Icon.Resource(
+                        R.drawable.qs_flashlight_icon_on,
+                        ContentDescription.Resource(R.string.quick_settings_flashlight_label)
+                    ),
+                    ActivationState.Active
+                )
+        }
+
+        object OffAvailable : FlashlightState() {
+            override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState =
+                KeyguardQuickAffordanceConfig.LockScreenState.Visible(
+                    Icon.Resource(
+                        R.drawable.qs_flashlight_icon_off,
+                        ContentDescription.Resource(R.string.quick_settings_flashlight_label)
+                    ),
+                    ActivationState.Inactive
+                )
+        }
+
+        object Unavailable : FlashlightState() {
+            override fun toLockScreenState(): KeyguardQuickAffordanceConfig.LockScreenState =
+                KeyguardQuickAffordanceConfig.LockScreenState.Hidden
+        }
+    }
+
+    override val key: String
+        get() = BuiltInKeyguardQuickAffordanceKeys.FLASHLIGHT
+
+    override val pickerName: String
+        get() = context.getString(R.string.quick_settings_flashlight_label)
+
+    override val pickerIconResourceId: Int
+        get() = R.drawable.ic_flashlight_off
+
+    override val lockScreenState: Flow<KeyguardQuickAffordanceConfig.LockScreenState> =
+        conflatedCallbackFlow {
+            val flashlightCallback =
+                object : FlashlightController.FlashlightListener {
+                    override fun onFlashlightChanged(enabled: Boolean) {
+                        trySendWithFailureLogging(
+                            if (enabled) {
+                                FlashlightState.On.toLockScreenState()
+                            } else {
+                                FlashlightState.OffAvailable.toLockScreenState()
+                            },
+                            TAG
+                        )
+                    }
+
+                    override fun onFlashlightError() {
+                        trySendWithFailureLogging(
+                            FlashlightState.OffAvailable.toLockScreenState(),
+                            TAG
+                        )
+                    }
+
+                    override fun onFlashlightAvailabilityChanged(available: Boolean) {
+                        trySendWithFailureLogging(
+                            if (!available) {
+                                FlashlightState.Unavailable.toLockScreenState()
+                            } else {
+                                if (flashlightController.isEnabled) {
+                                    FlashlightState.On.toLockScreenState()
+                                } else {
+                                    FlashlightState.OffAvailable.toLockScreenState()
+                                }
+                            },
+                            TAG
+                        )
+                    }
+                }
+
+            flashlightController.addCallback(flashlightCallback)
+
+            awaitClose { flashlightController.removeCallback(flashlightCallback) }
+        }
+
+    override fun onTriggered(
+        expandable: Expandable?
+    ): KeyguardQuickAffordanceConfig.OnTriggeredResult {
+        flashlightController.setFlashlight(
+            flashlightController.isAvailable && !flashlightController.isEnabled
+        )
+        return KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled
+    }
+
+    override suspend fun getPickerScreenState(): KeyguardQuickAffordanceConfig.PickerScreenState =
+        if (flashlightController.isAvailable) {
+            KeyguardQuickAffordanceConfig.PickerScreenState.Default
+        } else {
+            KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice
+        }
+
+    companion object {
+        private const val TAG = "FlashlightQuickAffordanceConfig"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
index f7225a2..072cfb1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardDataQuickAffordanceModule.kt
@@ -17,25 +17,35 @@
 
 package com.android.systemui.keyguard.data.quickaffordance
 
+import dagger.Binds
 import dagger.Module
 import dagger.Provides
 import dagger.multibindings.ElementsIntoSet
 
 @Module
-object KeyguardDataQuickAffordanceModule {
-    @Provides
-    @ElementsIntoSet
-    fun quickAffordanceConfigs(
-        home: HomeControlsKeyguardQuickAffordanceConfig,
-        quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
-        qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
-        camera: CameraQuickAffordanceConfig,
-    ): Set<KeyguardQuickAffordanceConfig> {
-        return setOf(
-            camera,
-            home,
-            quickAccessWallet,
-            qrCodeScanner,
-        )
+interface KeyguardDataQuickAffordanceModule {
+    @Binds
+    fun providerClientFactory(
+        impl: KeyguardQuickAffordanceProviderClientFactoryImpl,
+    ): KeyguardQuickAffordanceProviderClientFactory
+
+    companion object {
+        @Provides
+        @ElementsIntoSet
+        fun quickAffordanceConfigs(
+            flashlight: FlashlightQuickAffordanceConfig,
+            home: HomeControlsKeyguardQuickAffordanceConfig,
+            quickAccessWallet: QuickAccessWalletKeyguardQuickAffordanceConfig,
+            qrCodeScanner: QrCodeScannerKeyguardQuickAffordanceConfig,
+            camera: CameraQuickAffordanceConfig,
+        ): Set<KeyguardQuickAffordanceConfig> {
+            return setOf(
+                camera,
+                flashlight,
+                home,
+                quickAccessWallet,
+                qrCodeScanner,
+            )
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
index 4477310..98b1a73 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceConfig.kt
@@ -21,7 +21,7 @@
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
-import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
 import kotlinx.coroutines.flow.Flow
 
 /** Defines interface that can act as data source for a single quick affordance model. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt
index 766096f..72747f6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncer.kt
@@ -67,7 +67,7 @@
     @Application private val scope: CoroutineScope,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
     private val secureSettings: SecureSettings,
-    private val selectionsManager: KeyguardQuickAffordanceSelectionManager,
+    private val selectionsManager: KeyguardQuickAffordanceLocalUserSelectionManager,
 ) {
     companion object {
         private val BINDINGS =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
new file mode 100644
index 0000000..0066785
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManager.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.Context
+import android.content.IntentFilter
+import android.content.SharedPreferences
+import com.android.systemui.R
+import com.android.systemui.backup.BackupHelper
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.settings.UserTracker
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.onStart
+
+/**
+ * Manages and provides access to the current "selections" of keyguard quick affordances, answering
+ * the question "which affordances should the keyguard show?" for the user associated with the
+ * System UI process.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class KeyguardQuickAffordanceLocalUserSelectionManager
+@Inject
+constructor(
+    @Application context: Context,
+    private val userFileManager: UserFileManager,
+    private val userTracker: UserTracker,
+    broadcastDispatcher: BroadcastDispatcher,
+) : KeyguardQuickAffordanceSelectionManager {
+
+    private var sharedPrefs: SharedPreferences = instantiateSharedPrefs()
+
+    private val userId: Flow<Int> = conflatedCallbackFlow {
+        val callback =
+            object : UserTracker.Callback {
+                override fun onUserChanged(newUser: Int, userContext: Context) {
+                    trySendWithFailureLogging(newUser, TAG)
+                }
+            }
+
+        userTracker.addCallback(callback) { it.run() }
+        trySendWithFailureLogging(userTracker.userId, TAG)
+
+        awaitClose { userTracker.removeCallback(callback) }
+    }
+
+    private val defaults: Map<String, List<String>> by lazy {
+        context.resources
+            .getStringArray(R.array.config_keyguardQuickAffordanceDefaults)
+            .associate { item ->
+                val splitUp = item.split(SLOT_AFFORDANCES_DELIMITER)
+                check(splitUp.size == 2)
+                val slotId = splitUp[0]
+                val affordanceIds = splitUp[1].split(AFFORDANCE_DELIMITER)
+                slotId to affordanceIds
+            }
+    }
+
+    /**
+     * Emits an event each time a Backup & Restore restoration job is completed. Does not emit an
+     * initial value.
+     */
+    private val backupRestorationEvents: Flow<Unit> =
+        broadcastDispatcher.broadcastFlow(
+            filter = IntentFilter(BackupHelper.ACTION_RESTORE_FINISHED),
+            flags = Context.RECEIVER_NOT_EXPORTED,
+            permission = BackupHelper.PERMISSION_SELF,
+        )
+
+    override val selections: Flow<Map<String, List<String>>> =
+        combine(
+                userId,
+                backupRestorationEvents.onStart {
+                    // We emit an initial event to make sure that the combine emits at least once,
+                    // even if we never get a Backup & Restore restoration event (which is the most
+                    // common case anyway as restoration really only happens on initial device
+                    // setup).
+                    emit(Unit)
+                }
+            ) { _, _ -> }
+            .flatMapLatest {
+                conflatedCallbackFlow {
+                    // We want to instantiate a new SharedPreferences instance each time either the
+                    // user ID changes or we have a backup & restore restoration event. The reason
+                    // is that our sharedPrefs instance needs to be replaced with a new one as it
+                    // depends on the user ID and when the B&R job completes, the backing file is
+                    // replaced but the existing instance still has a stale in-memory cache.
+                    sharedPrefs = instantiateSharedPrefs()
+
+                    val listener =
+                        SharedPreferences.OnSharedPreferenceChangeListener { _, _ ->
+                            trySend(getSelections())
+                        }
+
+                    sharedPrefs.registerOnSharedPreferenceChangeListener(listener)
+                    send(getSelections())
+
+                    awaitClose { sharedPrefs.unregisterOnSharedPreferenceChangeListener(listener) }
+                }
+            }
+
+    override fun getSelections(): Map<String, List<String>> {
+        val slotKeys = sharedPrefs.all.keys.filter { it.startsWith(KEY_PREFIX_SLOT) }
+        val result =
+            slotKeys
+                .associate { key ->
+                    val slotId = key.substring(KEY_PREFIX_SLOT.length)
+                    val value = sharedPrefs.getString(key, null)
+                    val affordanceIds =
+                        if (!value.isNullOrEmpty()) {
+                            value.split(AFFORDANCE_DELIMITER)
+                        } else {
+                            emptyList()
+                        }
+                    slotId to affordanceIds
+                }
+                .toMutableMap()
+
+        // If the result map is missing keys, it means that the system has never set anything for
+        // those slots. This is where we need examine our defaults and see if there should be a
+        // default value for the affordances in the slot IDs that are missing from the result.
+        //
+        // Once the user makes any selection for a slot, even when they select "None", this class
+        // will persist a key for that slot ID. In the case of "None", it will have a value of the
+        // empty string. This is why this system works.
+        defaults.forEach { (slotId, affordanceIds) ->
+            if (!result.containsKey(slotId)) {
+                result[slotId] = affordanceIds
+            }
+        }
+
+        return result
+    }
+
+    override fun setSelections(
+        slotId: String,
+        affordanceIds: List<String>,
+    ) {
+        val key = "$KEY_PREFIX_SLOT$slotId"
+        val value = affordanceIds.joinToString(AFFORDANCE_DELIMITER)
+        sharedPrefs.edit().putString(key, value).apply()
+    }
+
+    private fun instantiateSharedPrefs(): SharedPreferences {
+        return userFileManager.getSharedPreferences(
+            FILE_NAME,
+            Context.MODE_PRIVATE,
+            userTracker.userId,
+        )
+    }
+
+    companion object {
+        private const val TAG = "KeyguardQuickAffordancePrimaryUserSelectionManager"
+        const val FILE_NAME = "quick_affordance_selections"
+        private const val KEY_PREFIX_SLOT = "slot_"
+        private const val SLOT_AFFORDANCES_DELIMITER = ":"
+        private const val AFFORDANCE_DELIMITER = ","
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceProviderClientFactory.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceProviderClientFactory.kt
new file mode 100644
index 0000000..727a813
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceProviderClientFactory.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClientImpl
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+
+interface KeyguardQuickAffordanceProviderClientFactory {
+    fun create(): KeyguardQuickAffordanceProviderClient
+}
+
+class KeyguardQuickAffordanceProviderClientFactoryImpl
+@Inject
+constructor(
+    private val userTracker: UserTracker,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) : KeyguardQuickAffordanceProviderClientFactory {
+    override fun create(): KeyguardQuickAffordanceProviderClient {
+        return KeyguardQuickAffordanceProviderClientImpl(
+            context = userTracker.userContext,
+            backgroundDispatcher = backgroundDispatcher,
+        )
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
new file mode 100644
index 0000000..8ffef25
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManager.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.Context
+import android.os.UserHandle
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.emptyFlow
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.launch
+
+/**
+ * Manages and provides access to the current "selections" of keyguard quick affordances, answering
+ * the question "which affordances should the keyguard show?" for users associated with other System
+ * UI processes.
+ */
+@OptIn(ExperimentalCoroutinesApi::class)
+@SysUISingleton
+class KeyguardQuickAffordanceRemoteUserSelectionManager
+@Inject
+constructor(
+    @Application private val scope: CoroutineScope,
+    private val userTracker: UserTracker,
+    private val clientFactory: KeyguardQuickAffordanceProviderClientFactory,
+    private val userHandle: UserHandle,
+) : KeyguardQuickAffordanceSelectionManager {
+
+    private val userId: Flow<Int> = conflatedCallbackFlow {
+        val callback =
+            object : UserTracker.Callback {
+                override fun onUserChanged(newUser: Int, userContext: Context) {
+                    trySendWithFailureLogging(newUser, TAG)
+                }
+            }
+
+        userTracker.addCallback(callback) { it.run() }
+        trySendWithFailureLogging(userTracker.userId, TAG)
+
+        awaitClose { userTracker.removeCallback(callback) }
+    }
+
+    private val clientOrNull: StateFlow<KeyguardQuickAffordanceProviderClient?> =
+        userId
+            .distinctUntilChanged()
+            .map { selectedUserId ->
+                if (userHandle.isSystem && userHandle.identifier != selectedUserId) {
+                    clientFactory.create()
+                } else {
+                    null
+                }
+            }
+            .stateIn(
+                scope = scope,
+                started = SharingStarted.Eagerly,
+                initialValue = null,
+            )
+
+    private val _selections: StateFlow<Map<String, List<String>>> =
+        clientOrNull
+            .flatMapLatest { client ->
+                client?.observeSelections()?.map { selections ->
+                    buildMap<String, List<String>> {
+                        selections.forEach { selection ->
+                            val slotId = selection.slotId
+                            val affordanceIds = (get(slotId) ?: emptyList()).toMutableList()
+                            affordanceIds.add(selection.affordanceId)
+                            put(slotId, affordanceIds)
+                        }
+                    }
+                }
+                    ?: emptyFlow()
+            }
+            .stateIn(
+                scope = scope,
+                started = SharingStarted.Eagerly,
+                initialValue = emptyMap(),
+            )
+
+    override val selections: Flow<Map<String, List<String>>> = _selections
+
+    override fun getSelections(): Map<String, List<String>> {
+        return _selections.value
+    }
+
+    override fun setSelections(slotId: String, affordanceIds: List<String>) {
+        clientOrNull.value?.let { client ->
+            scope.launch {
+                client.deleteAllSelections(slotId = slotId)
+                affordanceIds.forEach { affordanceId ->
+                    client.insertSelection(slotId = slotId, affordanceId = affordanceId)
+                }
+            }
+        }
+    }
+
+    companion object {
+        private const val TAG = "KeyguardQuickAffordanceMultiUserSelectionManager"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt
index b29cf45..21fffed 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManager.kt
@@ -17,119 +17,22 @@
 
 package com.android.systemui.keyguard.data.quickaffordance
 
-import android.content.Context
-import android.content.SharedPreferences
-import androidx.annotation.VisibleForTesting
-import com.android.systemui.R
-import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
-import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.settings.UserFileManager
-import com.android.systemui.settings.UserTracker
-import javax.inject.Inject
-import kotlinx.coroutines.channels.awaitClose
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.flatMapLatest
 
 /**
- * Manages and provides access to the current "selections" of keyguard quick affordances, answering
- * the question "which affordances should the keyguard show?".
+ * Defines interface for classes that manage and provide access to the current "selections" of
+ * keyguard quick affordances, answering the question "which affordances should the keyguard show?".
  */
-@SysUISingleton
-class KeyguardQuickAffordanceSelectionManager
-@Inject
-constructor(
-    @Application context: Context,
-    private val userFileManager: UserFileManager,
-    private val userTracker: UserTracker,
-) {
-
-    private val sharedPrefs: SharedPreferences
-        get() =
-            userFileManager.getSharedPreferences(
-                FILE_NAME,
-                Context.MODE_PRIVATE,
-                userTracker.userId,
-            )
-
-    private val userId: Flow<Int> = conflatedCallbackFlow {
-        val callback =
-            object : UserTracker.Callback {
-                override fun onUserChanged(newUser: Int, userContext: Context) {
-                    trySendWithFailureLogging(newUser, TAG)
-                }
-            }
-
-        userTracker.addCallback(callback) { it.run() }
-        trySendWithFailureLogging(userTracker.userId, TAG)
-
-        awaitClose { userTracker.removeCallback(callback) }
-    }
-    private val defaults: Map<String, List<String>> by lazy {
-        context.resources
-            .getStringArray(R.array.config_keyguardQuickAffordanceDefaults)
-            .associate { item ->
-                val splitUp = item.split(SLOT_AFFORDANCES_DELIMITER)
-                check(splitUp.size == 2)
-                val slotId = splitUp[0]
-                val affordanceIds = splitUp[1].split(AFFORDANCE_DELIMITER)
-                slotId to affordanceIds
-            }
-    }
+interface KeyguardQuickAffordanceSelectionManager {
 
     /** IDs of affordances to show, indexed by slot ID, and sorted in descending priority order. */
-    val selections: Flow<Map<String, List<String>>> =
-        userId.flatMapLatest {
-            conflatedCallbackFlow {
-                val listener =
-                    SharedPreferences.OnSharedPreferenceChangeListener { _, _ ->
-                        trySend(getSelections())
-                    }
-
-                sharedPrefs.registerOnSharedPreferenceChangeListener(listener)
-                send(getSelections())
-
-                awaitClose { sharedPrefs.unregisterOnSharedPreferenceChangeListener(listener) }
-            }
-        }
+    val selections: Flow<Map<String, List<String>>>
 
     /**
      * Returns a snapshot of the IDs of affordances to show, indexed by slot ID, and sorted in
      * descending priority order.
      */
-    fun getSelections(): Map<String, List<String>> {
-        val slotKeys = sharedPrefs.all.keys.filter { it.startsWith(KEY_PREFIX_SLOT) }
-        val result =
-            slotKeys
-                .associate { key ->
-                    val slotId = key.substring(KEY_PREFIX_SLOT.length)
-                    val value = sharedPrefs.getString(key, null)
-                    val affordanceIds =
-                        if (!value.isNullOrEmpty()) {
-                            value.split(AFFORDANCE_DELIMITER)
-                        } else {
-                            emptyList()
-                        }
-                    slotId to affordanceIds
-                }
-                .toMutableMap()
-
-        // If the result map is missing keys, it means that the system has never set anything for
-        // those slots. This is where we need examine our defaults and see if there should be a
-        // default value for the affordances in the slot IDs that are missing from the result.
-        //
-        // Once the user makes any selection for a slot, even when they select "None", this class
-        // will persist a key for that slot ID. In the case of "None", it will have a value of the
-        // empty string. This is why this system works.
-        defaults.forEach { (slotId, affordanceIds) ->
-            if (!result.containsKey(slotId)) {
-                result[slotId] = affordanceIds
-            }
-        }
-
-        return result
-    }
+    fun getSelections(): Map<String, List<String>>
 
     /**
      * Updates the IDs of affordances to show at the slot with the given ID. The order of affordance
@@ -138,17 +41,9 @@
     fun setSelections(
         slotId: String,
         affordanceIds: List<String>,
-    ) {
-        val key = "$KEY_PREFIX_SLOT$slotId"
-        val value = affordanceIds.joinToString(AFFORDANCE_DELIMITER)
-        sharedPrefs.edit().putString(key, value).apply()
-    }
+    )
 
     companion object {
-        private const val TAG = "KeyguardQuickAffordanceSelectionManager"
-        @VisibleForTesting const val FILE_NAME = "quick_affordance_selections"
-        private const val KEY_PREFIX_SLOT = "slot_"
-        private const val SLOT_AFFORDANCES_DELIMITER = ":"
-        private const val AFFORDANCE_DELIMITER = ","
+        const val FILE_NAME = "quick_affordance_selections"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
index d95a1a7..e3f5e90 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepository.kt
@@ -18,45 +18,93 @@
 package com.android.systemui.keyguard.data.repository
 
 import android.content.Context
+import android.os.UserHandle
 import com.android.systemui.Dumpable
 import com.android.systemui.R
+import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
 import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
 import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
+import com.android.systemui.settings.UserTracker
 import java.io.PrintWriter
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
 /** Abstracts access to application state related to keyguard quick affordances. */
+@OptIn(ExperimentalCoroutinesApi::class)
 @SysUISingleton
 class KeyguardQuickAffordanceRepository
 @Inject
 constructor(
     @Application private val appContext: Context,
     @Application private val scope: CoroutineScope,
-    private val selectionManager: KeyguardQuickAffordanceSelectionManager,
+    private val localUserSelectionManager: KeyguardQuickAffordanceLocalUserSelectionManager,
+    private val remoteUserSelectionManager: KeyguardQuickAffordanceRemoteUserSelectionManager,
+    private val userTracker: UserTracker,
     legacySettingSyncer: KeyguardQuickAffordanceLegacySettingSyncer,
     private val configs: Set<@JvmSuppressWildcards KeyguardQuickAffordanceConfig>,
     dumpManager: DumpManager,
+    userHandle: UserHandle,
 ) {
+    private val userId: Flow<Int> =
+        ConflatedCallbackFlow.conflatedCallbackFlow {
+            val callback =
+                object : UserTracker.Callback {
+                    override fun onUserChanged(newUser: Int, userContext: Context) {
+                        trySendWithFailureLogging(newUser, TAG)
+                    }
+                }
+
+            userTracker.addCallback(callback) { it.run() }
+            trySendWithFailureLogging(userTracker.userId, TAG)
+
+            awaitClose { userTracker.removeCallback(callback) }
+        }
+
+    private val selectionManager: StateFlow<KeyguardQuickAffordanceSelectionManager> =
+        userId
+            .distinctUntilChanged()
+            .map { selectedUserId ->
+                if (userHandle.identifier == selectedUserId) {
+                    localUserSelectionManager
+                } else {
+                    remoteUserSelectionManager
+                }
+            }
+            .stateIn(
+                scope = scope,
+                started = SharingStarted.Eagerly,
+                initialValue = localUserSelectionManager,
+            )
+
     /**
      * List of [KeyguardQuickAffordanceConfig] instances of the affordances at the slot with the
      * given ID. The configs are sorted in descending priority order.
      */
     val selections: StateFlow<Map<String, List<KeyguardQuickAffordanceConfig>>> =
-        selectionManager.selections
-            .map { selectionsBySlotId ->
-                selectionsBySlotId.mapValues { (_, selections) ->
-                    configs.filter { selections.contains(it.key) }
+        selectionManager
+            .flatMapLatest { selectionManager ->
+                selectionManager.selections.map { selectionsBySlotId ->
+                    selectionsBySlotId.mapValues { (_, selections) ->
+                        configs.filter { selections.contains(it.key) }
+                    }
                 }
             }
             .stateIn(
@@ -99,7 +147,7 @@
      * slot with the given ID. The configs are sorted in descending priority order.
      */
     fun getSelections(slotId: String): List<KeyguardQuickAffordanceConfig> {
-        val selections = selectionManager.getSelections().getOrDefault(slotId, emptyList())
+        val selections = selectionManager.value.getSelections().getOrDefault(slotId, emptyList())
         return configs.filter { selections.contains(it.key) }
     }
 
@@ -108,7 +156,7 @@
      * are sorted in descending priority order.
      */
     fun getSelections(): Map<String, List<String>> {
-        return selectionManager.getSelections()
+        return selectionManager.value.getSelections()
     }
 
     /**
@@ -119,7 +167,7 @@
         slotId: String,
         affordanceIds: List<String>,
     ) {
-        selectionManager.setSelections(
+        selectionManager.value.setSelections(
             slotId = slotId,
             affordanceIds = affordanceIds,
         )
@@ -188,6 +236,7 @@
     }
 
     companion object {
+        private const val TAG = "KeyguardQuickAffordanceRepository"
         private const val SLOT_CONFIG_DELIMITER = ":"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index 796f2b4..148792b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -16,8 +16,11 @@
 
 package com.android.systemui.keyguard.data.repository
 
+import android.graphics.Point
+import android.hardware.biometrics.BiometricSourceType
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.systemui.biometrics.AuthController
 import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.Position
@@ -27,8 +30,8 @@
 import com.android.systemui.doze.DozeTransitionCallback
 import com.android.systemui.doze.DozeTransitionListener
 import com.android.systemui.keyguard.WakefulnessLifecycle
-import com.android.systemui.keyguard.WakefulnessLifecycle.Wakefulness
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
 import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -88,8 +91,8 @@
      * enter to conserve battery when the device is locked and inactive.
      *
      * Note that it is possible for the system to be transitioning into doze while this flow still
-     * returns `false`. In order to account for that, observers should also use the [dozeAmount]
-     * flow to check if it's greater than `0`
+     * returns `false`. In order to account for that, observers should also use the
+     * [linearDozeAmount] flow to check if it's greater than `0`
      */
     val isDozing: Flow<Boolean>
 
@@ -111,7 +114,7 @@
      * happens during an animation/transition into doze mode. An observer would be wise to account
      * for both flows if needed.
      */
-    val dozeAmount: Flow<Float>
+    val linearDozeAmount: Flow<Float>
 
     /** Doze state information, as it transitions */
     val dozeTransitionModel: Flow<DozeTransitionModel>
@@ -120,11 +123,20 @@
     val statusBarState: Flow<StatusBarState>
 
     /** Observable for device wake/sleep state */
-    val wakefulnessState: Flow<WakefulnessModel>
+    val wakefulness: Flow<WakefulnessModel>
 
     /** Observable for biometric unlock modes */
     val biometricUnlockState: Flow<BiometricUnlockModel>
 
+    /** Approximate location on the screen of the fingerprint sensor. */
+    val fingerprintSensorLocation: Flow<Point?>
+
+    /** Approximate location on the screen of the face unlock sensor/front facing camera. */
+    val faceSensorLocation: Flow<Point?>
+
+    /** Source of the most recent biometric unlock, such as fingerprint or face. */
+    val biometricUnlockSource: Flow<BiometricUnlockSource?>
+
     /**
      * Returns `true` if the keyguard is showing; `false` otherwise.
      *
@@ -163,6 +175,7 @@
     private val keyguardStateController: KeyguardStateController,
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val dozeTransitionListener: DozeTransitionListener,
+    private val authController: AuthController,
 ) : KeyguardRepository {
     private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
     override val animateBottomAreaDozingTransitions =
@@ -281,11 +294,11 @@
             }
             .distinctUntilChanged()
 
-    override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
+    override val linearDozeAmount: Flow<Float> = conflatedCallbackFlow {
         val callback =
             object : StatusBarStateController.StateListener {
                 override fun onDozeAmountChanged(linear: Float, eased: Float) {
-                    trySendWithFailureLogging(eased, TAG, "updated dozeAmount")
+                    trySendWithFailureLogging(linear, TAG, "updated dozeAmount")
                 }
             }
 
@@ -348,58 +361,139 @@
         awaitClose { statusBarStateController.removeCallback(callback) }
     }
 
-    override val wakefulnessState: Flow<WakefulnessModel> = conflatedCallbackFlow {
-        val callback =
-            object : WakefulnessLifecycle.Observer {
-                override fun onStartedWakingUp() {
-                    trySendWithFailureLogging(
-                        WakefulnessModel.STARTING_TO_WAKE,
-                        TAG,
-                        "Wakefulness: starting to wake"
-                    )
-                }
-                override fun onFinishedWakingUp() {
-                    trySendWithFailureLogging(WakefulnessModel.AWAKE, TAG, "Wakefulness: awake")
-                }
-                override fun onStartedGoingToSleep() {
-                    trySendWithFailureLogging(
-                        WakefulnessModel.STARTING_TO_SLEEP,
-                        TAG,
-                        "Wakefulness: starting to sleep"
-                    )
-                }
-                override fun onFinishedGoingToSleep() {
-                    trySendWithFailureLogging(WakefulnessModel.ASLEEP, TAG, "Wakefulness: asleep")
-                }
-            }
-        wakefulnessLifecycle.addObserver(callback)
-        trySendWithFailureLogging(
-            wakefulnessIntToObject(wakefulnessLifecycle.getWakefulness()),
-            TAG,
-            "initial wakefulness state"
-        )
-
-        awaitClose { wakefulnessLifecycle.removeObserver(callback) }
-    }
-
     override val biometricUnlockState: Flow<BiometricUnlockModel> = conflatedCallbackFlow {
+        fun dispatchUpdate() {
+            trySendWithFailureLogging(
+                biometricModeIntToObject(biometricUnlockController.mode),
+                TAG,
+                "biometric mode"
+            )
+        }
+
         val callback =
             object : BiometricUnlockController.BiometricModeListener {
                 override fun onModeChanged(@WakeAndUnlockMode mode: Int) {
-                    trySendWithFailureLogging(biometricModeIntToObject(mode), TAG, "biometric mode")
+                    dispatchUpdate()
+                }
+
+                override fun onResetMode() {
+                    dispatchUpdate()
                 }
             }
 
         biometricUnlockController.addBiometricModeListener(callback)
-        trySendWithFailureLogging(
-            biometricModeIntToObject(biometricUnlockController.getMode()),
-            TAG,
-            "initial biometric mode"
-        )
+        dispatchUpdate()
 
         awaitClose { biometricUnlockController.removeBiometricModeListener(callback) }
     }
 
+    override val wakefulness: Flow<WakefulnessModel> = conflatedCallbackFlow {
+        val observer =
+            object : WakefulnessLifecycle.Observer {
+                override fun onStartedWakingUp() {
+                    dispatchNewState()
+                }
+
+                override fun onFinishedWakingUp() {
+                    dispatchNewState()
+                }
+
+                override fun onPostFinishedWakingUp() {
+                    dispatchNewState()
+                }
+
+                override fun onStartedGoingToSleep() {
+                    dispatchNewState()
+                }
+
+                override fun onFinishedGoingToSleep() {
+                    dispatchNewState()
+                }
+
+                private fun dispatchNewState() {
+                    trySendWithFailureLogging(
+                        WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
+                        TAG,
+                        "updated wakefulness state"
+                    )
+                }
+            }
+
+        wakefulnessLifecycle.addObserver(observer)
+        trySendWithFailureLogging(
+            WakefulnessModel.fromWakefulnessLifecycle(wakefulnessLifecycle),
+            TAG,
+            "initial wakefulness state"
+        )
+
+        awaitClose { wakefulnessLifecycle.removeObserver(observer) }
+    }
+
+    override val fingerprintSensorLocation: Flow<Point?> = conflatedCallbackFlow {
+        fun sendFpLocation() {
+            trySendWithFailureLogging(
+                authController.fingerprintSensorLocation,
+                TAG,
+                "AuthController.Callback#onFingerprintLocationChanged"
+            )
+        }
+
+        val callback =
+            object : AuthController.Callback {
+                override fun onFingerprintLocationChanged() {
+                    sendFpLocation()
+                }
+            }
+
+        authController.addCallback(callback)
+        sendFpLocation()
+
+        awaitClose { authController.removeCallback(callback) }
+    }
+
+    override val faceSensorLocation: Flow<Point?> = conflatedCallbackFlow {
+        fun sendSensorLocation() {
+            trySendWithFailureLogging(
+                authController.faceSensorLocation,
+                TAG,
+                "AuthController.Callback#onFingerprintLocationChanged"
+            )
+        }
+
+        val callback =
+            object : AuthController.Callback {
+                override fun onFaceSensorLocationChanged() {
+                    sendSensorLocation()
+                }
+            }
+
+        authController.addCallback(callback)
+        sendSensorLocation()
+
+        awaitClose { authController.removeCallback(callback) }
+    }
+
+    override val biometricUnlockSource: Flow<BiometricUnlockSource?> = conflatedCallbackFlow {
+        val callback =
+            object : KeyguardUpdateMonitorCallback() {
+                override fun onBiometricAuthenticated(
+                    userId: Int,
+                    biometricSourceType: BiometricSourceType?,
+                    isStrongBiometric: Boolean
+                ) {
+                    trySendWithFailureLogging(
+                        BiometricUnlockSource.fromBiometricSourceType(biometricSourceType),
+                        TAG,
+                        "onBiometricAuthenticated"
+                    )
+                }
+            }
+
+        keyguardUpdateMonitor.registerCallback(callback)
+        trySendWithFailureLogging(null, TAG, "initial value")
+        awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+    }
+
     override fun setAnimateDozingTransitions(animate: Boolean) {
         _animateBottomAreaDozingTransitions.value = animate
     }
@@ -423,16 +517,6 @@
         }
     }
 
-    private fun wakefulnessIntToObject(@Wakefulness value: Int): WakefulnessModel {
-        return when (value) {
-            0 -> WakefulnessModel.ASLEEP
-            1 -> WakefulnessModel.STARTING_TO_WAKE
-            2 -> WakefulnessModel.AWAKE
-            3 -> WakefulnessModel.STARTING_TO_SLEEP
-            else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
-        }
-    }
-
     private fun biometricModeIntToObject(@WakeAndUnlockMode value: Int): BiometricUnlockModel {
         return when (value) {
             0 -> BiometricUnlockModel.NONE
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
index 0c72520..26f853f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryModule.kt
@@ -27,4 +27,7 @@
     fun keyguardTransitionRepository(
         impl: KeyguardTransitionRepositoryImpl
     ): KeyguardTransitionRepository
+
+    @Binds
+    fun lightRevealScrimRepository(impl: LightRevealScrimRepositoryImpl): LightRevealScrimRepository
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
index bce7d92..5bb586e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt
@@ -116,6 +116,7 @@
                 KeyguardState.LOCKSCREEN,
                 0f,
                 TransitionState.STARTED,
+                KeyguardTransitionRepositoryImpl::class.simpleName!!,
             )
         )
         emitTransition(
@@ -124,6 +125,7 @@
                 KeyguardState.LOCKSCREEN,
                 1f,
                 TransitionState.FINISHED,
+                KeyguardTransitionRepositoryImpl::class.simpleName!!,
             )
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
new file mode 100644
index 0000000..a17481a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepository.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.keyguard.data.repository
+
+import android.content.Context
+import android.graphics.Point
+import com.android.systemui.R
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
+import com.android.systemui.statusbar.CircleReveal
+import com.android.systemui.statusbar.LiftReveal
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.statusbar.PowerButtonReveal
+import javax.inject.Inject
+import kotlin.math.max
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+
+val DEFAULT_REVEAL_EFFECT = LiftReveal
+
+/**
+ * Encapsulates state relevant to the light reveal scrim, the view used to reveal/hide screen
+ * contents during transitions between AOD and lockscreen/unlocked.
+ */
+interface LightRevealScrimRepository {
+
+    /**
+     * The reveal effect that should be used for the next lock/unlock. We switch between either the
+     * biometric unlock effect (if wake and unlocking) or the non-biometric effect, and position it
+     * at the current screen position of the appropriate sensor.
+     */
+    val revealEffect: Flow<LightRevealEffect>
+}
+
+@SysUISingleton
+class LightRevealScrimRepositoryImpl
+@Inject
+constructor(
+    keyguardRepository: KeyguardRepository,
+    val context: Context,
+) : LightRevealScrimRepository {
+
+    /** The reveal effect used if the device was locked/unlocked via the power button. */
+    private val powerButtonReveal =
+        PowerButtonReveal(
+            context.resources
+                .getDimensionPixelSize(R.dimen.physical_power_button_center_screen_location_y)
+                .toFloat()
+        )
+
+    /**
+     * Reveal effect to use for a fingerprint unlock. This is reconstructed if the fingerprint
+     * sensor location on the screen (in pixels) changes due to configuration changes.
+     */
+    private val fingerprintRevealEffect: Flow<LightRevealEffect?> =
+        keyguardRepository.fingerprintSensorLocation.map {
+            it?.let { constructCircleRevealFromPoint(it) }
+        }
+
+    /**
+     * Reveal effect to use for a face unlock. This is reconstructed if the face sensor/front camera
+     * location on the screen (in pixels) changes due to configuration changes.
+     */
+    private val faceRevealEffect: Flow<LightRevealEffect?> =
+        keyguardRepository.faceSensorLocation.map { it?.let { constructCircleRevealFromPoint(it) } }
+
+    /**
+     * The reveal effect we'll use for the next biometric unlock animation. We switch between the
+     * fingerprint/face unlock effect flows depending on the biometric unlock source.
+     */
+    private val biometricRevealEffect: Flow<LightRevealEffect?> =
+        keyguardRepository.biometricUnlockSource.flatMapLatest { source ->
+            when (source) {
+                BiometricUnlockSource.FINGERPRINT_SENSOR -> fingerprintRevealEffect
+                BiometricUnlockSource.FACE_SENSOR -> faceRevealEffect
+                else -> flowOf(null)
+            }
+        }
+
+    /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */
+    private val nonBiometricRevealEffect: Flow<LightRevealEffect?> =
+        keyguardRepository.wakefulness.map { wakefulnessModel ->
+            val wakingUpFromPowerButton =
+                wakefulnessModel.isWakingUpOrAwake &&
+                    wakefulnessModel.lastWakeReason == WakeSleepReason.POWER_BUTTON
+            val sleepingFromPowerButton =
+                !wakefulnessModel.isWakingUpOrAwake &&
+                    wakefulnessModel.lastSleepReason == WakeSleepReason.POWER_BUTTON
+
+            if (wakingUpFromPowerButton || sleepingFromPowerButton) {
+                powerButtonReveal
+            } else {
+                LiftReveal
+            }
+        }
+
+    override val revealEffect =
+        combine(
+                keyguardRepository.biometricUnlockState,
+                biometricRevealEffect,
+                nonBiometricRevealEffect
+            ) { biometricUnlockState, biometricReveal, nonBiometricReveal ->
+
+                // Use the biometric reveal for any flavor of wake and unlocking.
+                when (biometricUnlockState) {
+                    BiometricUnlockModel.WAKE_AND_UNLOCK,
+                    BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING,
+                    BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM -> biometricReveal
+                    else -> nonBiometricReveal
+                }
+                    ?: DEFAULT_REVEAL_EFFECT
+            }
+            .distinctUntilChanged()
+
+    private fun constructCircleRevealFromPoint(point: Point): LightRevealEffect {
+        return with(point) {
+            CircleReveal(
+                x,
+                y,
+                startRadius = 0,
+                endRadius =
+                    max(max(x, context.display.width - x), max(y, context.display.height - y)),
+            )
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
new file mode 100644
index 0000000..0e865ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/backup/KeyguardQuickAffordanceBackupHelper.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.domain.backup
+
+import android.app.backup.SharedPreferencesBackupHelper
+import android.content.Context
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.settings.UserFileManagerImpl
+
+/** Handles backup & restore for keyguard quick affordances. */
+class KeyguardQuickAffordanceBackupHelper(
+    context: Context,
+    userId: Int,
+) :
+    SharedPreferencesBackupHelper(
+        context,
+        if (UserFileManagerImpl.isPrimaryUser(userId)) {
+            KeyguardQuickAffordanceSelectionManager.FILE_NAME
+        } else {
+            UserFileManagerImpl.secondaryUserFile(
+                    context = context,
+                    fileName = KeyguardQuickAffordanceSelectionManager.FILE_NAME,
+                    directoryName = UserFileManagerImpl.SHARED_PREFS,
+                    userId = userId,
+                )
+                .also { UserFileManagerImpl.ensureParentDirExists(it) }
+                .toString()
+        }
+    )
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
index 2dbacd5..f3d2905 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodLockscreenTransitionInteractor.kt
@@ -27,7 +27,6 @@
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -42,17 +41,14 @@
 
     override fun start() {
         listenForTransitionToAodFromLockscreen()
-        listenForTransitionToLockscreenFromAod()
+        listenForTransitionToLockscreenFromDozeStates()
     }
 
     private fun listenForTransitionToAodFromLockscreen() {
         scope.launch {
             keyguardInteractor
                 .dozeTransitionTo(DozeStateModel.DOZE_AOD)
-                .sample(
-                    keyguardTransitionInteractor.startedKeyguardTransitionStep,
-                    { a, b -> Pair(a, b) }
-                )
+                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
                     val (dozeToAod, lastStartedStep) = pair
                     if (lastStartedStep.to == KeyguardState.LOCKSCREEN) {
@@ -69,21 +65,19 @@
         }
     }
 
-    private fun listenForTransitionToLockscreenFromAod() {
+    private fun listenForTransitionToLockscreenFromDozeStates() {
+        val canGoToLockscreen = setOf(KeyguardState.AOD, KeyguardState.DOZING)
         scope.launch {
             keyguardInteractor
                 .dozeTransitionTo(DozeStateModel.FINISH)
-                .sample(
-                    keyguardTransitionInteractor.startedKeyguardTransitionStep,
-                    { a, b -> Pair(a, b) }
-                )
+                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
                     val (dozeToAod, lastStartedStep) = pair
-                    if (lastStartedStep.to == KeyguardState.AOD) {
+                    if (canGoToLockscreen.contains(lastStartedStep.to)) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
                                 name,
-                                KeyguardState.AOD,
+                                lastStartedStep.to,
                                 KeyguardState.LOCKSCREEN,
                                 getAnimator(),
                             )
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodToGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodToGoneTransitionInteractor.kt
index 2a220fc..dad166f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodToGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/AodToGoneTransitionInteractor.kt
@@ -21,9 +21,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.WAKE_AND_UNLOCK
-import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
-import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionInfo
 import com.android.systemui.util.kotlin.sample
@@ -42,9 +40,6 @@
     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
 ) : TransitionInteractor(AodToGoneTransitionInteractor::class.simpleName!!) {
 
-    private val wakeAndUnlockModes =
-        setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING)
-
     override fun start() {
         scope.launch {
             keyguardInteractor.biometricUnlockState
@@ -52,8 +47,7 @@
                 .collect { pair ->
                     val (biometricUnlockState, keyguardState) = pair
                     if (
-                        keyguardState == KeyguardState.AOD &&
-                            wakeAndUnlockModes.contains(biometricUnlockState)
+                        keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)
                     ) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt
deleted file mode 100644
index 9cbf9ea..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingLockscreenTransitionInteractor.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.keyguard.domain.interactor
-
-import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.DozeStateModel
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
-import com.android.systemui.util.kotlin.sample
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.launch
-
-@SysUISingleton
-class DreamingLockscreenTransitionInteractor
-@Inject
-constructor(
-    @Application private val scope: CoroutineScope,
-    private val keyguardInteractor: KeyguardInteractor,
-    private val keyguardTransitionRepository: KeyguardTransitionRepository,
-    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(DreamingLockscreenTransitionInteractor::class.simpleName!!) {
-
-    override fun start() {
-        scope.launch {
-            keyguardInteractor.isDreaming
-                .sample(
-                    combine(
-                        keyguardInteractor.dozeTransitionModel,
-                        keyguardTransitionInteractor.finishedKeyguardState
-                    ) { a, b -> Pair(a, b) },
-                    { a, bc -> Triple(a, bc.first, bc.second) }
-                )
-                .collect { triple ->
-                    val (isDreaming, dozeTransitionModel, keyguardState) = triple
-                    // Dozing/AOD and dreaming have overlapping events. If the state remains in
-                    // FINISH, it means that doze mode is not running and DREAMING is ok to
-                    // commence.
-                    if (dozeTransitionModel.to == DozeStateModel.FINISH) {
-                        if (isDreaming && keyguardState == KeyguardState.LOCKSCREEN) {
-                            keyguardTransitionRepository.startTransition(
-                                TransitionInfo(
-                                    name,
-                                    KeyguardState.LOCKSCREEN,
-                                    KeyguardState.DREAMING,
-                                    getAnimator(),
-                                )
-                            )
-                        } else if (!isDreaming && keyguardState == KeyguardState.DREAMING) {
-                            keyguardTransitionRepository.startTransition(
-                                TransitionInfo(
-                                    name,
-                                    KeyguardState.DREAMING,
-                                    KeyguardState.LOCKSCREEN,
-                                    getAnimator(),
-                                )
-                            )
-                        }
-                    }
-                }
-        }
-    }
-
-    private fun getAnimator(): ValueAnimator {
-        return ValueAnimator().apply {
-            setInterpolator(Interpolators.LINEAR)
-            setDuration(TRANSITION_DURATION_MS)
-        }
-    }
-
-    companion object {
-        private const val TRANSITION_DURATION_MS = 500L
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
deleted file mode 100644
index 9e2b724..0000000
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingToAodTransitionInteractor.kt
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.keyguard.domain.interactor
-
-import android.animation.ValueAnimator
-import com.android.systemui.animation.Interpolators
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
-import com.android.systemui.keyguard.shared.model.KeyguardState
-import com.android.systemui.keyguard.shared.model.TransitionInfo
-import com.android.systemui.keyguard.shared.model.WakefulnessModel.Companion.isSleepingOrStartingToSleep
-import com.android.systemui.util.kotlin.sample
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
-import kotlinx.coroutines.launch
-
-@SysUISingleton
-class DreamingToAodTransitionInteractor
-@Inject
-constructor(
-    @Application private val scope: CoroutineScope,
-    private val keyguardInteractor: KeyguardInteractor,
-    private val keyguardTransitionRepository: KeyguardTransitionRepository,
-    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor("DREAMING->AOD") {
-
-    override fun start() {
-        scope.launch {
-            keyguardInteractor.wakefulnessState
-                .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
-                .collect { pair ->
-                    val (wakefulnessState, keyguardState) = pair
-                    if (
-                        isSleepingOrStartingToSleep(wakefulnessState) &&
-                            keyguardState == KeyguardState.DREAMING
-                    ) {
-                        keyguardTransitionRepository.startTransition(
-                            TransitionInfo(
-                                name,
-                                KeyguardState.DREAMING,
-                                KeyguardState.AOD,
-                                getAnimator(),
-                            )
-                        )
-                    }
-                }
-        }
-    }
-
-    private fun getAnimator(): ValueAnimator {
-        return ValueAnimator().apply {
-            setInterpolator(Interpolators.LINEAR)
-            setDuration(TRANSITION_DURATION_MS)
-        }
-    }
-
-    companion object {
-        private const val TRANSITION_DURATION_MS = 300L
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingTransitionInteractor.kt
new file mode 100644
index 0000000..b73ce9e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DreamingTransitionInteractor.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.domain.interactor
+
+import android.animation.ValueAnimator
+import com.android.systemui.animation.Interpolators
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
+import com.android.systemui.keyguard.shared.model.DozeStateModel
+import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionInfo
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.launch
+
+@SysUISingleton
+class DreamingTransitionInteractor
+@Inject
+constructor(
+    @Application private val scope: CoroutineScope,
+    private val keyguardInteractor: KeyguardInteractor,
+    private val keyguardTransitionRepository: KeyguardTransitionRepository,
+    private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
+) : TransitionInteractor(DreamingTransitionInteractor::class.simpleName!!) {
+
+    private val canDreamFrom =
+        setOf(KeyguardState.LOCKSCREEN, KeyguardState.GONE, KeyguardState.DOZING)
+
+    override fun start() {
+        listenForEntryToDreaming()
+        listenForDreamingToLockscreen()
+        listenForDreamingToGone()
+        listenForDreamingToDozing()
+    }
+
+    private fun listenForEntryToDreaming() {
+        scope.launch {
+            keyguardInteractor.isDreaming
+                .sample(
+                    combine(
+                        keyguardInteractor.dozeTransitionModel,
+                        keyguardTransitionInteractor.finishedKeyguardState,
+                        ::Pair
+                    ),
+                    ::toTriple
+                )
+                .collect { triple ->
+                    val (isDreaming, dozeTransitionModel, keyguardState) = triple
+                    // Dozing/AOD and dreaming have overlapping events. If the state remains in
+                    // FINISH, it means that doze mode is not running and DREAMING is ok to
+                    // commence.
+                    if (
+                        isDozeOff(dozeTransitionModel.to) &&
+                            isDreaming &&
+                            canDreamFrom.contains(keyguardState)
+                    ) {
+                        keyguardTransitionRepository.startTransition(
+                            TransitionInfo(
+                                name,
+                                keyguardState,
+                                KeyguardState.DREAMING,
+                                getAnimator(),
+                            )
+                        )
+                    }
+                }
+        }
+    }
+
+    private fun listenForDreamingToLockscreen() {
+        scope.launch {
+            keyguardInteractor.isDreaming
+                .sample(
+                    combine(
+                        keyguardInteractor.dozeTransitionModel,
+                        keyguardTransitionInteractor.startedKeyguardTransitionStep,
+                        ::Pair,
+                    ),
+                    ::toTriple
+                )
+                .collect { triple ->
+                    val (isDreaming, dozeTransitionModel, lastStartedTransition) = triple
+                    if (
+                        isDozeOff(dozeTransitionModel.to) &&
+                            !isDreaming &&
+                            lastStartedTransition.to == KeyguardState.DREAMING
+                    ) {
+                        keyguardTransitionRepository.startTransition(
+                            TransitionInfo(
+                                name,
+                                KeyguardState.DREAMING,
+                                KeyguardState.LOCKSCREEN,
+                                getAnimator(),
+                            )
+                        )
+                    }
+                }
+        }
+    }
+
+    private fun listenForDreamingToGone() {
+        scope.launch {
+            keyguardInteractor.biometricUnlockState
+                .sample(keyguardTransitionInteractor.finishedKeyguardState, ::Pair)
+                .collect { pair ->
+                    val (biometricUnlockState, keyguardState) = pair
+                    if (
+                        keyguardState == KeyguardState.DREAMING &&
+                            isWakeAndUnlock(biometricUnlockState)
+                    ) {
+                        keyguardTransitionRepository.startTransition(
+                            TransitionInfo(
+                                name,
+                                KeyguardState.DREAMING,
+                                KeyguardState.GONE,
+                                getAnimator(),
+                            )
+                        )
+                    }
+                }
+        }
+    }
+
+    private fun listenForDreamingToDozing() {
+        scope.launch {
+            combine(
+                    keyguardInteractor.dozeTransitionModel,
+                    keyguardTransitionInteractor.finishedKeyguardState,
+                    ::Pair
+                )
+                .collect { pair ->
+                    val (dozeTransitionModel, keyguardState) = pair
+                    if (
+                        dozeTransitionModel.to == DozeStateModel.DOZE &&
+                            keyguardState == KeyguardState.DREAMING
+                    ) {
+                        keyguardTransitionRepository.startTransition(
+                            TransitionInfo(
+                                name,
+                                KeyguardState.DREAMING,
+                                KeyguardState.DOZING,
+                                getAnimator(),
+                            )
+                        )
+                    }
+                }
+        }
+    }
+
+    private fun getAnimator(): ValueAnimator {
+        return ValueAnimator().apply {
+            setInterpolator(Interpolators.LINEAR)
+            setDuration(TRANSITION_DURATION_MS)
+        }
+    }
+
+    companion object {
+        private const val TRANSITION_DURATION_MS = 500L
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
index 0e2a54c..a50e759 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/GoneAodTransitionInteractor.kt
@@ -23,11 +23,10 @@
 import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.keyguard.shared.model.TransitionInfo
-import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.util.kotlin.sample
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.launch
 
 @SysUISingleton
@@ -38,17 +37,17 @@
     private val keyguardInteractor: KeyguardInteractor,
     private val keyguardTransitionRepository: KeyguardTransitionRepository,
     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor("GONE->AOD") {
+) : TransitionInteractor(GoneAodTransitionInteractor::class.simpleName!!) {
 
     override fun start() {
         scope.launch {
-            keyguardInteractor.wakefulnessState
+            keyguardInteractor.wakefulnessModel
                 .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
                 .collect { pair ->
                     val (wakefulnessState, keyguardState) = pair
                     if (
                         keyguardState == KeyguardState.GONE &&
-                            wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP
+                            wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP
                     ) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index 7cfd117..6912e1d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import android.graphics.Point
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.keyguard.data.repository.KeyguardRepository
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
@@ -41,7 +42,7 @@
      * The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
      * all.
      */
-    val dozeAmount: Flow<Float> = repository.dozeAmount
+    val dozeAmount: Flow<Float> = repository.linearDozeAmount
     /** Whether the system is in doze mode. */
     val isDozing: Flow<Boolean> = repository.isDozing
     /** Doze transition information. */
@@ -58,7 +59,7 @@
     /** Whether the bouncer is showing or not. */
     val isBouncerShowing: Flow<Boolean> = repository.isBouncerShowing
     /** The device wake/sleep state */
-    val wakefulnessState: Flow<WakefulnessModel> = repository.wakefulnessState
+    val wakefulnessModel: Flow<WakefulnessModel> = repository.wakefulness
     /** Observable for the [StatusBarState] */
     val statusBarState: Flow<StatusBarState> = repository.statusBarState
     /**
@@ -67,10 +68,15 @@
      */
     val biometricUnlockState: Flow<BiometricUnlockModel> = repository.biometricUnlockState
 
+    /** The approximate location on the screen of the fingerprint sensor, if one is available. */
+    val fingerprintSensorLocation: Flow<Point?> = repository.fingerprintSensorLocation
+
+    /** The approximate location on the screen of the face unlock sensor, if one is available. */
+    val faceSensorLocation: Flow<Point?> = repository.faceSensorLocation
+
     fun dozeTransitionTo(state: DozeStateModel): Flow<DozeTransitionModel> {
         return dozeTransitionModel.filter { it.to == state }
     }
-
     fun isKeyguardShowing(): Boolean {
         return repository.isKeyguardShowing()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 2d94d76..748c6e8 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -34,8 +34,8 @@
 import com.android.systemui.keyguard.shared.quickaffordance.KeyguardQuickAffordancePosition
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import dagger.Lazy
 import javax.inject.Inject
@@ -190,8 +190,6 @@
 
     /** Returns affordance IDs indexed by slot ID, for all known slots. */
     suspend fun getSelections(): Map<String, List<KeyguardQuickAffordancePickerRepresentation>> {
-        check(isUsingRepository)
-
         val slots = repository.get().getSlotPickerRepresentations()
         val selections = repository.get().getSelections()
         val affordanceById =
@@ -312,8 +310,6 @@
 
     suspend fun getAffordancePickerRepresentations():
         List<KeyguardQuickAffordancePickerRepresentation> {
-        check(isUsingRepository)
-
         return repository.get().getAffordancePickerRepresentations()
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
index 58a8093..a2661d7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionAuditLogger.kt
@@ -37,7 +37,7 @@
 
     fun start() {
         scope.launch {
-            keyguardInteractor.wakefulnessState.collect { logger.v("WakefulnessState", it) }
+            keyguardInteractor.wakefulnessModel.collect { logger.v("WakefulnessModel", it) }
         }
 
         scope.launch {
@@ -46,6 +46,8 @@
 
         scope.launch { keyguardInteractor.isDozing.collect { logger.v("isDozing", it) } }
 
+        scope.launch { keyguardInteractor.isDreaming.collect { logger.v("isDreaming", it) } }
+
         scope.launch {
             interactor.finishedKeyguardTransitionStep.collect {
                 logger.i("Finished transition", it)
@@ -61,5 +63,9 @@
         scope.launch {
             interactor.startedKeyguardTransitionStep.collect { logger.i("Started transition", it) }
         }
+
+        scope.launch {
+            keyguardInteractor.dozeTransitionModel.collect { logger.i("Doze transition", it) }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
index 43dd358e..bb8b79a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionCoreStartable.kt
@@ -43,8 +43,7 @@
                     is LockscreenGoneTransitionInteractor -> Log.d(TAG, "Started $it")
                     is AodToGoneTransitionInteractor -> Log.d(TAG, "Started $it")
                     is BouncerToGoneTransitionInteractor -> Log.d(TAG, "Started $it")
-                    is DreamingLockscreenTransitionInteractor -> Log.d(TAG, "Started $it")
-                    is DreamingToAodTransitionInteractor -> Log.d(TAG, "Started $it")
+                    is DreamingTransitionInteractor -> Log.d(TAG, "Started $it")
                 }
             it.start()
         }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
new file mode 100644
index 0000000..6e25200
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractor.kt
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.util.kotlin.sample
+import javax.inject.Inject
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+
+@ExperimentalCoroutinesApi
+@SysUISingleton
+class LightRevealScrimInteractor
+@Inject
+constructor(
+    transitionRepository: KeyguardTransitionRepository,
+    transitionInteractor: KeyguardTransitionInteractor,
+    lightRevealScrimRepository: LightRevealScrimRepository,
+) {
+
+    /**
+     * Whenever a keyguard transition starts, sample the latest reveal effect from the repository
+     * and use that for the starting transition.
+     *
+     * We can't simply use the nextRevealEffect since the effect may change midway through a
+     * transition, but we don't want to change effects part way through. For example, if we're using
+     * a CircleReveal to animate a biometric unlock, but the biometric unlock mode changes to NONE
+     * from WAKE_AND_UNLOCK before the unlock animation ends, we don't want to end up switching to a
+     * LiftReveal.
+     */
+    val lightRevealEffect: Flow<LightRevealEffect> =
+        transitionInteractor.startedKeyguardTransitionStep.sample(
+            lightRevealScrimRepository.revealEffect
+        )
+
+    /**
+     * The reveal amount to use for the light reveal scrim, which is derived from the keyguard
+     * transition steps.
+     */
+    val revealAmount: Flow<Float> =
+        transitionRepository.transitions
+            // Only listen to transitions that change the reveal amount.
+            .filter { willTransitionAffectRevealAmount(it) }
+            // Use the transition amount as the reveal amount, inverting it if we're transitioning
+            // to a non-revealed (hidden) state.
+            .map { step -> if (willBeRevealedInState(step.to)) step.value else 1f - step.value }
+
+    companion object {
+
+        /**
+         * Whether the transition requires a change in the reveal amount of the light reveal scrim.
+         * If not, we don't care about the transition and don't need to listen to it.
+         */
+        fun willTransitionAffectRevealAmount(transition: TransitionStep): Boolean {
+            return willBeRevealedInState(transition.from) != willBeRevealedInState(transition.to)
+        }
+
+        /**
+         * Whether the light reveal scrim will be fully revealed (revealAmount = 1.0f) in the given
+         * state after the transition is complete. If false, scrim will be fully hidden.
+         */
+        fun willBeRevealedInState(state: KeyguardState): Boolean {
+            return when (state) {
+                KeyguardState.OFF -> false
+                KeyguardState.DOZING -> false
+                KeyguardState.AOD -> false
+                KeyguardState.DREAMING -> true
+                KeyguardState.BOUNCER -> true
+                KeyguardState.LOCKSCREEN -> true
+                KeyguardState.GONE -> true
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
index 3bb8241..3218f96 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenBouncerTransitionInteractor.kt
@@ -25,7 +25,7 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
 import com.android.systemui.keyguard.shared.model.TransitionInfo
 import com.android.systemui.keyguard.shared.model.TransitionState
-import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.util.kotlin.sample
 import java.util.UUID
@@ -58,22 +58,26 @@
             keyguardInteractor.isBouncerShowing
                 .sample(
                     combine(
-                        keyguardInteractor.wakefulnessState,
+                        keyguardInteractor.wakefulnessModel,
                         keyguardTransitionInteractor.startedKeyguardTransitionStep,
-                    ) { a, b ->
-                        Pair(a, b)
-                    },
-                    { a, bc -> Triple(a, bc.first, bc.second) }
-                )
-                .collect { triple ->
-                    val (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) = triple
+                    ) { wakefulnessModel, transitionStep ->
+                        Pair(wakefulnessModel, transitionStep)
+                    }
+                ) { bouncerShowing, wakefulnessAndTransition ->
+                    Triple(
+                        bouncerShowing,
+                        wakefulnessAndTransition.first,
+                        wakefulnessAndTransition.second
+                    )
+                }
+                .collect { (isBouncerShowing, wakefulnessState, lastStartedTransitionStep) ->
                     if (
                         !isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.BOUNCER
                     ) {
                         val to =
                             if (
-                                wakefulnessState == WakefulnessModel.STARTING_TO_SLEEP ||
-                                    wakefulnessState == WakefulnessModel.ASLEEP
+                                wakefulnessState.state == WakefulnessState.STARTING_TO_SLEEP ||
+                                    wakefulnessState.state == WakefulnessState.ASLEEP
                             ) {
                                 KeyguardState.AOD
                             } else {
@@ -100,14 +104,17 @@
                     combine(
                         keyguardTransitionInteractor.finishedKeyguardState,
                         keyguardInteractor.statusBarState,
-                    ) { a, b ->
-                        Pair(a, b)
-                    },
-                    { a, bc -> Triple(a, bc.first, bc.second) }
-                )
-                .collect { triple ->
-                    val (shadeModel, keyguardState, statusBarState) = triple
-
+                    ) { finishedKeyguardState, statusBarState ->
+                        Pair(finishedKeyguardState, statusBarState)
+                    }
+                ) { shadeModel, keyguardStateAndStatusBarState ->
+                    Triple(
+                        shadeModel,
+                        keyguardStateAndStatusBarState.first,
+                        keyguardStateAndStatusBarState.second
+                    )
+                }
+                .collect { (shadeModel, keyguardState, statusBarState) ->
                     val id = transitionId
                     if (id != null) {
                         // An existing `id` means a transition is started, and calls to
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
index 4100f7a..95d9602 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/LockscreenGoneTransitionInteractor.kt
@@ -37,15 +37,15 @@
     private val keyguardInteractor: KeyguardInteractor,
     private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
     private val keyguardTransitionRepository: KeyguardTransitionRepository,
-) : TransitionInteractor("LOCKSCREEN->GONE") {
+) : TransitionInteractor(LockscreenGoneTransitionInteractor::class.simpleName!!) {
 
     override fun start() {
         scope.launch {
             keyguardInteractor.isKeyguardGoingAway
-                .sample(keyguardTransitionInteractor.finishedKeyguardState, { a, b -> Pair(a, b) })
+                .sample(keyguardTransitionInteractor.startedKeyguardTransitionStep, ::Pair)
                 .collect { pair ->
-                    val (isKeyguardGoingAway, keyguardState) = pair
-                    if (!isKeyguardGoingAway && keyguardState == KeyguardState.LOCKSCREEN) {
+                    val (isKeyguardGoingAway, lastStartedStep) = pair
+                    if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
                         keyguardTransitionRepository.startTransition(
                             TransitionInfo(
                                 name,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
index 84a8074..2cf5fb9 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/PrimaryBouncerInteractor.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.content.res.ColorStateList
+import android.hardware.biometrics.BiometricSourceType
 import android.os.Handler
 import android.os.Trace
 import android.os.UserHandle
@@ -71,7 +72,7 @@
                 KeyguardUpdateMonitor.getCurrentUser()
             ) &&
             !needsFullscreenBouncer() &&
-            !keyguardUpdateMonitor.userNeedsStrongAuth() &&
+            keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE) &&
             !keyguardBypassController.bypassEnabled
 
     /** Runnable to show the primary bouncer. */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
index dbffeab..5f63ae7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/StartKeyguardTransitionModule.kt
@@ -52,13 +52,5 @@
     @IntoSet
     abstract fun lockscreenGone(impl: LockscreenGoneTransitionInteractor): TransitionInteractor
 
-    @Binds
-    @IntoSet
-    abstract fun dreamingLockscreen(
-        impl: DreamingLockscreenTransitionInteractor
-    ): TransitionInteractor
-
-    @Binds
-    @IntoSet
-    abstract fun dreamingToAod(impl: DreamingToAodTransitionInteractor): TransitionInteractor
+    @Binds @IntoSet abstract fun dreaming(impl: DreamingTransitionInteractor): TransitionInteractor
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index a2a46d9..08ad3d5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -29,4 +29,6 @@
 sealed class TransitionInteractor(val name: String) {
 
     abstract fun start()
+
+    fun <A, B, C> toTriple(a: A, bc: Pair<B, C>) = Triple(a, bc.first, bc.second)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockModel.kt
index db709b4..8fe6309f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockModel.kt
@@ -46,5 +46,14 @@
     /** When bouncer is visible and will be dismissed. */
     DISMISS_BOUNCER,
     /** Mode in which fingerprint wakes and unlocks the device from a dream. */
-    WAKE_AND_UNLOCK_FROM_DREAM,
+    WAKE_AND_UNLOCK_FROM_DREAM;
+
+    companion object {
+        private val wakeAndUnlockModes =
+            setOf(WAKE_AND_UNLOCK, WAKE_AND_UNLOCK_FROM_DREAM, WAKE_AND_UNLOCK_PULSING)
+
+        fun isWakeAndUnlock(model: BiometricUnlockModel): Boolean {
+            return wakeAndUnlockModes.contains(model)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt
new file mode 100644
index 0000000..b403416
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/BiometricUnlockSource.kt
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.shared.model
+
+import android.hardware.biometrics.BiometricSourceType
+
+/** Biometric unlock sensor sources, which we use to play sensor-specific animations. */
+enum class BiometricUnlockSource {
+    /** The unlock was initiated by a fingerprint sensor authentication. */
+    FINGERPRINT_SENSOR,
+
+    /** The unlock was initiated by the front-facing camera or a nearby sensor. */
+    FACE_SENSOR;
+
+    companion object {
+        fun fromBiometricSourceType(type: BiometricSourceType?): BiometricUnlockSource? {
+            return when (type) {
+                BiometricSourceType.FINGERPRINT -> FINGERPRINT_SENSOR
+                BiometricSourceType.FACE -> FACE_SENSOR
+                BiometricSourceType.IRIS -> FACE_SENSOR
+                else -> null
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DozeStateModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DozeStateModel.kt
index 7039188..65b7cf7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DozeStateModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/DozeStateModel.kt
@@ -42,5 +42,11 @@
     /** AOD, prox is near, transitions to DOZE_AOD_PAUSED after a timeout. */
     DOZE_AOD_PAUSING,
     /** Always-on doze. Device is awake, showing docking UI and listening for pulse triggers. */
-    DOZE_AOD_DOCKED
+    DOZE_AOD_DOCKED;
+
+    companion object {
+        fun isDozeOff(model: DozeStateModel): Boolean {
+            return model == UNINITIALIZED || model == FINISH
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
new file mode 100644
index 0000000..b32597d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakeSleepReason.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.shared.model
+
+import android.os.PowerManager
+
+/** The reason we're waking up or going to sleep, such as pressing the power button. */
+enum class WakeSleepReason {
+    /** The physical power button was pressed to wake up or sleep the device. */
+    POWER_BUTTON,
+
+    /** Something else happened to wake up or sleep the device. */
+    OTHER;
+
+    companion object {
+        fun fromPowerManagerWakeReason(reason: Int): WakeSleepReason {
+            return when (reason) {
+                PowerManager.WAKE_REASON_POWER_BUTTON -> POWER_BUTTON
+                else -> OTHER
+            }
+        }
+
+        fun fromPowerManagerSleepReason(reason: Int): WakeSleepReason {
+            return when (reason) {
+                PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON -> POWER_BUTTON
+                else -> OTHER
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
index 92040f4..03dee00 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessModel.kt
@@ -15,24 +15,34 @@
  */
 package com.android.systemui.keyguard.shared.model
 
-/** Model device wakefulness states. */
-enum class WakefulnessModel {
-    /** The device is asleep and not interactive. */
-    ASLEEP,
-    /** Received a signal that the device is beginning to wake up. */
-    STARTING_TO_WAKE,
-    /** Device is now fully awake and interactive. */
-    AWAKE,
-    /** Signal that the device is now going to sleep. */
-    STARTING_TO_SLEEP;
+import com.android.systemui.keyguard.WakefulnessLifecycle
 
+/** Model device wakefulness states. */
+data class WakefulnessModel(
+    val state: WakefulnessState,
+    val isWakingUpOrAwake: Boolean,
+    val lastWakeReason: WakeSleepReason,
+    val lastSleepReason: WakeSleepReason,
+) {
     companion object {
         fun isSleepingOrStartingToSleep(model: WakefulnessModel): Boolean {
-            return model == ASLEEP || model == STARTING_TO_SLEEP
+            return model.state == WakefulnessState.ASLEEP ||
+                model.state == WakefulnessState.STARTING_TO_SLEEP
         }
 
         fun isWakingOrStartingToWake(model: WakefulnessModel): Boolean {
-            return model == AWAKE || model == STARTING_TO_WAKE
+            return model.state == WakefulnessState.AWAKE ||
+                model.state == WakefulnessState.STARTING_TO_WAKE
+        }
+
+        fun fromWakefulnessLifecycle(wakefulnessLifecycle: WakefulnessLifecycle): WakefulnessModel {
+            return WakefulnessModel(
+                WakefulnessState.fromWakefulnessLifecycleInt(wakefulnessLifecycle.wakefulness),
+                wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_WAKING ||
+                    wakefulnessLifecycle.wakefulness == WakefulnessLifecycle.WAKEFULNESS_AWAKE,
+                WakeSleepReason.fromPowerManagerWakeReason(wakefulnessLifecycle.lastWakeReason),
+                WakeSleepReason.fromPowerManagerSleepReason(wakefulnessLifecycle.lastSleepReason),
+            )
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt
new file mode 100644
index 0000000..6791d88
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/shared/model/WakefulnessState.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.shared.model
+
+import com.android.systemui.keyguard.WakefulnessLifecycle
+
+enum class WakefulnessState {
+    /** The device is asleep and not interactive. */
+    ASLEEP,
+    /** Received a signal that the device is beginning to wake up. */
+    STARTING_TO_WAKE,
+    /** Device is now fully awake and interactive. */
+    AWAKE,
+    /** Signal that the device is now going to sleep. */
+    STARTING_TO_SLEEP;
+
+    companion object {
+        fun fromWakefulnessLifecycleInt(
+            @WakefulnessLifecycle.Wakefulness value: Int
+        ): WakefulnessState {
+            return when (value) {
+                WakefulnessLifecycle.WAKEFULNESS_ASLEEP -> ASLEEP
+                WakefulnessLifecycle.WAKEFULNESS_WAKING -> STARTING_TO_WAKE
+                WakefulnessLifecycle.WAKEFULNESS_AWAKE -> AWAKE
+                WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP -> STARTING_TO_SLEEP
+                else -> throw IllegalArgumentException("Invalid Wakefulness value: $value")
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
index 3276b6d..cbe512f 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/KeyguardBottomAreaViewBinder.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard.ui.binder
 
+import android.graphics.drawable.Animatable2
 import android.util.Size
 import android.util.TypedValue
 import android.view.View
@@ -27,12 +28,11 @@
 import androidx.core.view.updateLayoutParams
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.repeatOnLifecycle
-import com.android.keyguard.KeyguardUpdateMonitor
-import com.android.keyguard.LockIconViewController
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.animation.Expandable
 import com.android.systemui.animation.Interpolators
+import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
 import com.android.systemui.keyguard.ui.viewmodel.KeyguardQuickAffordanceViewModel
@@ -73,7 +73,8 @@
         fun onConfigurationChanged()
 
         /**
-         * Returns whether the keyguard bottom area should be constrained to the top of the lock icon
+         * Returns whether the keyguard bottom area should be constrained to the top of the lock
+         * icon
          */
         fun shouldConstrainToTopOfLockIcon(): Boolean
     }
@@ -217,7 +218,7 @@
             }
 
             override fun shouldConstrainToTopOfLockIcon(): Boolean =
-                    viewModel.shouldConstrainToTopOfLockIcon()
+                viewModel.shouldConstrainToTopOfLockIcon()
         }
     }
 
@@ -248,6 +249,27 @@
 
         IconViewBinder.bind(viewModel.icon, view)
 
+        (view.drawable as? Animatable2)?.let { animatable ->
+            (viewModel.icon as? Icon.Resource)?.res?.let { iconResourceId ->
+                // Always start the animation (we do call stop() below, if we need to skip it).
+                animatable.start()
+
+                if (view.tag != iconResourceId) {
+                    // Here when we haven't run the animation on a previous update.
+                    //
+                    // Save the resource ID for next time, so we know not to re-animate the same
+                    // animation again.
+                    view.tag = iconResourceId
+                } else {
+                    // Here when we've already done this animation on a previous update and want to
+                    // skip directly to the final frame of the animation to avoid running it.
+                    //
+                    // By calling stop after start, we go to the final frame of the animation.
+                    animatable.stop()
+                }
+            }
+        }
+
         view.isActivated = viewModel.isActivated
         view.drawable.setTint(
             Utils.getColorAttrDefaultColor(
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
new file mode 100644
index 0000000..f1da882
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/LightRevealScrimViewBinder.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.ui.binder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.statusbar.LightRevealScrim
+import kotlinx.coroutines.launch
+
+object LightRevealScrimViewBinder {
+    @JvmStatic
+    fun bind(revealScrim: LightRevealScrim, viewModel: LightRevealScrimViewModel) {
+        revealScrim.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.CREATED) {
+                launch {
+                    viewModel.revealAmount.collect { amount -> revealScrim.revealAmount = amount }
+                }
+
+                launch {
+                    viewModel.lightRevealEffect.collect { effect ->
+                        revealScrim.revealEffect = effect
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt
new file mode 100644
index 0000000..a46d441
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LightRevealScrimViewModel.kt
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.ui.viewmodel
+
+import com.android.systemui.keyguard.domain.interactor.LightRevealScrimInteractor
+import com.android.systemui.statusbar.LightRevealEffect
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Models UI state for the light reveal scrim, which is used during screen on and off animations to
+ * draw a gradient that reveals/hides the contents of the screen.
+ */
+class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) {
+    val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect
+    val revealAmount: Flow<Float> = interactor.revealAmount
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
index f9e341c..d6e29e0 100644
--- a/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferFactory.kt
@@ -16,9 +16,9 @@
 
 package com.android.systemui.log
 
-import android.app.ActivityManager
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
 import com.android.systemui.plugins.log.LogBuffer
 import com.android.systemui.plugins.log.LogcatEchoTracker
 
@@ -29,15 +29,6 @@
     private val dumpManager: DumpManager,
     private val logcatEchoTracker: LogcatEchoTracker
 ) {
-    /* limitiometricMessageDeferralLogger the size of maxPoolSize for low ram (Go) devices */
-    private fun adjustMaxSize(requestedMaxSize: Int): Int {
-        return if (ActivityManager.isLowRamDeviceStatic()) {
-            minOf(requestedMaxSize, 20) /* low ram max log size*/
-        } else {
-            requestedMaxSize
-        }
-    }
-
     @JvmOverloads
     fun create(
         name: String,
diff --git a/packages/SystemUI/src/com/android/systemui/log/LogBufferHelper.kt b/packages/SystemUI/src/com/android/systemui/log/LogBufferHelper.kt
new file mode 100644
index 0000000..619eac1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/LogBufferHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log
+
+import android.app.ActivityManager
+
+class LogBufferHelper {
+    companion object {
+        /** If necessary, returns a limited maximum size for low ram (Go) devices */
+        fun adjustMaxSize(requestedMaxSize: Int): Int {
+            return if (ActivityManager.isLowRamDeviceStatic()) {
+                minOf(requestedMaxSize, 20) /* low ram max log size*/
+            } else {
+                requestedMaxSize
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
new file mode 100644
index 0000000..bb04b6b4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+import com.android.systemui.util.kotlin.pairwiseBy
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * An interface that enables logging the difference between values in table format.
+ *
+ * Many objects that we want to log are data-y objects with a collection of fields. When logging
+ * these objects, we want to log each field separately. This allows ABT (Android Bug Tool) to easily
+ * highlight changes in individual fields.
+ *
+ * See [TableLogBuffer].
+ */
+interface Diffable<T> {
+    /**
+     * Finds the differences between [prevVal] and this object and logs those diffs to [row].
+     *
+     * Each implementer should determine which individual fields have changed between [prevVal] and
+     * this object, and only log the fields that have actually changed. This helps save buffer
+     * space.
+     *
+     * For example, if:
+     * - prevVal = Object(val1=100, val2=200, val3=300)
+     * - this = Object(val1=100, val2=200, val3=333)
+     *
+     * Then only the val3 change should be logged.
+     */
+    fun logDiffs(prevVal: T, row: TableRowLogger)
+
+    /**
+     * Logs all the relevant fields of this object to [row].
+     *
+     * As opposed to [logDiffs], this method should log *all* fields.
+     *
+     * Implementation is optional. This method will only be used with [logDiffsForTable] in order to
+     * fully log the initial value of the flow.
+     */
+    fun logFull(row: TableRowLogger) {}
+}
+
+/**
+ * Each time the flow is updated with a new value, logs the differences between the previous value
+ * and the new value to the given [tableLogBuffer].
+ *
+ * The new value's [Diffable.logDiffs] method will be used to log the differences to the table.
+ *
+ * @param columnPrefix a prefix that will be applied to every column name that gets logged.
+ */
+fun <T : Diffable<T>> Flow<T>.logDiffsForTable(
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String,
+    initialValue: T,
+): Flow<T> {
+    // Fully log the initial value to the table.
+    val getInitialValue = {
+        tableLogBuffer.logChange(columnPrefix) { row -> initialValue.logFull(row) }
+        initialValue
+    }
+    return this.pairwiseBy(getInitialValue) { prevVal: T, newVal: T ->
+        tableLogBuffer.logDiffs(columnPrefix, prevVal, newVal)
+        newVal
+    }
+}
+
+/**
+ * Each time the boolean flow is updated with a new value that's different from the previous value,
+ * logs the new value to the given [tableLogBuffer].
+ */
+fun Flow<Boolean>.logDiffsForTable(
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String,
+    columnName: String,
+    initialValue: Boolean,
+): Flow<Boolean> {
+    val initialValueFun = {
+        tableLogBuffer.logChange(columnPrefix, columnName, initialValue)
+        initialValue
+    }
+    return this.pairwiseBy(initialValueFun) { prevVal, newVal: Boolean ->
+        if (prevVal != newVal) {
+            tableLogBuffer.logChange(columnPrefix, columnName, newVal)
+        }
+        newVal
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
new file mode 100644
index 0000000..68c297f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableChange.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+/**
+ * A object used with [TableLogBuffer] to store changes in variables over time. Is recyclable.
+ *
+ * Each message represents a change to exactly 1 type, specified by [DataType].
+ */
+data class TableChange(
+    var timestamp: Long = 0,
+    var columnPrefix: String = "",
+    var columnName: String = "",
+    var type: DataType = DataType.EMPTY,
+    var bool: Boolean = false,
+    var int: Int = 0,
+    var str: String? = null,
+) {
+    /** Resets to default values so that the object can be recycled. */
+    fun reset(timestamp: Long, columnPrefix: String, columnName: String) {
+        this.timestamp = timestamp
+        this.columnPrefix = columnPrefix
+        this.columnName = columnName
+        this.type = DataType.EMPTY
+        this.bool = false
+        this.int = 0
+        this.str = null
+    }
+
+    /** Sets this to store a string change. */
+    fun set(value: String?) {
+        type = DataType.STRING
+        str = value
+    }
+
+    /** Sets this to store a boolean change. */
+    fun set(value: Boolean) {
+        type = DataType.BOOLEAN
+        bool = value
+    }
+
+    /** Sets this to store an int change. */
+    fun set(value: Int) {
+        type = DataType.INT
+        int = value
+    }
+
+    /** Returns true if this object has a change. */
+    fun hasData(): Boolean {
+        return columnName.isNotBlank() && type != DataType.EMPTY
+    }
+
+    fun getName(): String {
+        return if (columnPrefix.isNotBlank()) {
+            "$columnPrefix.$columnName"
+        } else {
+            columnName
+        }
+    }
+
+    fun getVal(): String {
+        return when (type) {
+            DataType.EMPTY -> null
+            DataType.STRING -> str
+            DataType.INT -> int
+            DataType.BOOLEAN -> bool
+        }.toString()
+    }
+
+    enum class DataType {
+        STRING,
+        BOOLEAN,
+        INT,
+        EMPTY,
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
new file mode 100644
index 0000000..9d0b833
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBuffer.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+import com.android.systemui.Dumpable
+import com.android.systemui.plugins.util.RingBuffer
+import com.android.systemui.util.time.SystemClock
+import java.io.PrintWriter
+import java.text.SimpleDateFormat
+import java.util.Locale
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * A logger that logs changes in table format.
+ *
+ * Some parts of System UI maintain a lot of pieces of state at once.
+ * [com.android.systemui.plugins.log.LogBuffer] allows us to easily log change events:
+ *
+ * - 10-10 10:10:10.456: state2 updated to newVal2
+ * - 10-10 10:11:00.000: stateN updated to StateN(val1=true, val2=1)
+ * - 10-10 10:11:02.123: stateN updated to StateN(val1=true, val2=2)
+ * - 10-10 10:11:05.123: state1 updated to newVal1
+ * - 10-10 10:11:06.000: stateN updated to StateN(val1=false, val2=3)
+ *
+ * However, it can sometimes be more useful to view the state changes in table format:
+ *
+ * - timestamp--------- | state1- | state2- | ... | stateN.val1 | stateN.val2
+ * - -------------------------------------------------------------------------
+ * - 10-10 10:10:10.123 | val1--- | val2--- | ... | false------ | 0-----------
+ * - 10-10 10:10:10.456 | val1--- | newVal2 | ... | false------ | 0-----------
+ * - 10-10 10:11:00.000 | val1--- | newVal2 | ... | true------- | 1-----------
+ * - 10-10 10:11:02.123 | val1--- | newVal2 | ... | true------- | 2-----------
+ * - 10-10 10:11:05.123 | newVal1 | newVal2 | ... | true------- | 2-----------
+ * - 10-10 10:11:06.000 | newVal1 | newVal2 | ... | false------ | 3-----------
+ *
+ * This class enables easy logging of the state changes in both change event format and table
+ * format.
+ *
+ * This class also enables easy logging of states that are a collection of fields. For example,
+ * stateN in the above example consists of two fields -- val1 and val2. It's useful to put each
+ * field into its own column so that ABT (Android Bug Tool) can easily highlight changes to
+ * individual fields.
+ *
+ * How it works:
+ *
+ * 1) Create an instance of this buffer via [TableLogBufferFactory].
+ *
+ * 2) For any states being logged, implement [Diffable]. Implementing [Diffable] allows the state to
+ * only log the fields that have *changed* since the previous update, instead of always logging all
+ * fields.
+ *
+ * 3) Each time a change in a state happens, call [logDiffs]. If your state is emitted using a
+ * [Flow], you should use the [logDiffsForTable] extension function to automatically log diffs any
+ * time your flow emits a new value.
+ *
+ * When a dump occurs, there will be two dumps:
+ *
+ * 1) The change events under the dumpable name "$name-changes".
+ *
+ * 2) This class will coalesce all the diffs into a table format and log them under the dumpable
+ * name "$name-table".
+ *
+ * @param maxSize the maximum size of the buffer. Must be > 0.
+ */
+class TableLogBuffer(
+    maxSize: Int,
+    private val name: String,
+    private val systemClock: SystemClock,
+) : Dumpable {
+    init {
+        if (maxSize <= 0) {
+            throw IllegalArgumentException("maxSize must be > 0")
+        }
+    }
+
+    private val buffer = RingBuffer(maxSize) { TableChange() }
+
+    // A [TableRowLogger] object, re-used each time [logDiffs] is called.
+    // (Re-used to avoid object allocation.)
+    private val tempRow = TableRowLoggerImpl(0, columnPrefix = "", this)
+
+    /**
+     * Log the differences between [prevVal] and [newVal].
+     *
+     * The [newVal] object's method [Diffable.logDiffs] will be used to fetch the diffs.
+     *
+     * @param columnPrefix a prefix that will be applied to every column name that gets logged. This
+     * ensures that all the columns related to the same state object will be grouped together in the
+     * table.
+     *
+     * @throws IllegalArgumentException if [columnPrefix] or column name contain "|". "|" is used as
+     * the separator token for parsing, so it can't be present in any part of the column name.
+     */
+    @Synchronized
+    fun <T : Diffable<T>> logDiffs(columnPrefix: String, prevVal: T, newVal: T) {
+        val row = tempRow
+        row.timestamp = systemClock.currentTimeMillis()
+        row.columnPrefix = columnPrefix
+        newVal.logDiffs(prevVal, row)
+    }
+
+    /**
+     * Logs change(s) to the buffer using [rowInitializer].
+     *
+     * @param rowInitializer a function that will be called immediately to store relevant data on
+     * the row.
+     */
+    @Synchronized
+    fun logChange(columnPrefix: String, rowInitializer: (TableRowLogger) -> Unit) {
+        val row = tempRow
+        row.timestamp = systemClock.currentTimeMillis()
+        row.columnPrefix = columnPrefix
+        rowInitializer(row)
+    }
+
+    /** Logs a boolean change. */
+    fun logChange(prefix: String, columnName: String, value: Boolean) {
+        logChange(systemClock.currentTimeMillis(), prefix, columnName, value)
+    }
+
+    // Keep these individual [logChange] methods private (don't let clients give us their own
+    // timestamps.)
+
+    private fun logChange(timestamp: Long, prefix: String, columnName: String, value: String?) {
+        val change = obtain(timestamp, prefix, columnName)
+        change.set(value)
+    }
+
+    private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Boolean) {
+        val change = obtain(timestamp, prefix, columnName)
+        change.set(value)
+    }
+
+    private fun logChange(timestamp: Long, prefix: String, columnName: String, value: Int) {
+        val change = obtain(timestamp, prefix, columnName)
+        change.set(value)
+    }
+
+    // TODO(b/259454430): Add additional change types here.
+
+    @Synchronized
+    private fun obtain(timestamp: Long, prefix: String, columnName: String): TableChange {
+        verifyValidName(prefix, columnName)
+        val tableChange = buffer.advance()
+        tableChange.reset(timestamp, prefix, columnName)
+        return tableChange
+    }
+
+    private fun verifyValidName(prefix: String, columnName: String) {
+        if (prefix.contains(SEPARATOR)) {
+            throw IllegalArgumentException("columnPrefix cannot contain $SEPARATOR but was $prefix")
+        }
+        if (columnName.contains(SEPARATOR)) {
+            throw IllegalArgumentException(
+                "columnName cannot contain $SEPARATOR but was $columnName"
+            )
+        }
+    }
+
+    @Synchronized
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println(HEADER_PREFIX + name)
+        pw.println("version $VERSION")
+        for (i in 0 until buffer.size) {
+            buffer[i].dump(pw)
+        }
+        pw.println(FOOTER_PREFIX + name)
+    }
+
+    /** Dumps an individual [TableChange]. */
+    private fun TableChange.dump(pw: PrintWriter) {
+        if (!this.hasData()) {
+            return
+        }
+        val formattedTimestamp = TABLE_LOG_DATE_FORMAT.format(timestamp)
+        pw.print(formattedTimestamp)
+        pw.print(SEPARATOR)
+        pw.print(this.getName())
+        pw.print(SEPARATOR)
+        pw.print(this.getVal())
+        pw.println()
+    }
+
+    /**
+     * A private implementation of [TableRowLogger].
+     *
+     * Used so that external clients can't modify [timestamp].
+     */
+    private class TableRowLoggerImpl(
+        var timestamp: Long,
+        var columnPrefix: String,
+        val tableLogBuffer: TableLogBuffer,
+    ) : TableRowLogger {
+        /** Logs a change to a string value. */
+        override fun logChange(columnName: String, value: String?) {
+            tableLogBuffer.logChange(timestamp, columnPrefix, columnName, value)
+        }
+
+        /** Logs a change to a boolean value. */
+        override fun logChange(columnName: String, value: Boolean) {
+            tableLogBuffer.logChange(timestamp, columnPrefix, columnName, value)
+        }
+
+        /** Logs a change to an int value. */
+        override fun logChange(columnName: String, value: Int) {
+            tableLogBuffer.logChange(timestamp, columnPrefix, columnName, value)
+        }
+    }
+}
+
+val TABLE_LOG_DATE_FORMAT = SimpleDateFormat("MM-dd HH:mm:ss.SSS", Locale.US)
+
+private const val HEADER_PREFIX = "SystemUI StateChangeTableSection START: "
+private const val FOOTER_PREFIX = "SystemUI StateChangeTableSection END: "
+private const val SEPARATOR = "|"
+private const val VERSION = "1"
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
new file mode 100644
index 0000000..7a90a74
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableLogBufferFactory.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.log.LogBufferHelper.Companion.adjustMaxSize
+import com.android.systemui.util.time.SystemClock
+import javax.inject.Inject
+
+@SysUISingleton
+class TableLogBufferFactory
+@Inject
+constructor(
+    private val dumpManager: DumpManager,
+    private val systemClock: SystemClock,
+) {
+    fun create(
+        name: String,
+        maxSize: Int,
+    ): TableLogBuffer {
+        val tableBuffer = TableLogBuffer(adjustMaxSize(maxSize), name, systemClock)
+        dumpManager.registerNormalDumpable(name, tableBuffer)
+        return tableBuffer
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/TableRowLogger.kt b/packages/SystemUI/src/com/android/systemui/log/table/TableRowLogger.kt
new file mode 100644
index 0000000..a7ba13b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/table/TableRowLogger.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+/**
+ * A class that logs a row to [TableLogBuffer].
+ *
+ * Objects that implement [Diffable] will receive an instance of this class, and can log any changes
+ * to individual fields using the [logChange] methods. All logged changes will be associated with
+ * the same timestamp.
+ */
+interface TableRowLogger {
+    /** Logs a change to a string value. */
+    fun logChange(columnName: String, value: String?)
+
+    /** Logs a change to a boolean value. */
+    fun logChange(columnName: String, value: Boolean)
+
+    /** Logs a change to an int value. */
+    fun logChange(columnName: String, value: Int)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 22f91f3..bfa67a8 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -109,7 +109,6 @@
         CharSequence dialogTitle = null;
         String appName = null;
         if (Utils.isHeadlessRemoteDisplayProvider(packageManager, mPackageName)) {
-            // TODO(b/253438807): handle special app name
             dialogText = getString(R.string.media_projection_dialog_service_text);
             dialogTitle = getString(R.string.media_projection_dialog_service_title);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
index 4891297..2d10b82 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/resume/MediaResumeListener.kt
@@ -32,10 +32,12 @@
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.media.controls.models.player.MediaData
 import com.android.systemui.media.controls.pipeline.MediaDataManager
 import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.Utils
 import com.android.systemui.util.time.SystemClock
@@ -55,6 +57,8 @@
 constructor(
     private val context: Context,
     private val broadcastDispatcher: BroadcastDispatcher,
+    private val userTracker: UserTracker,
+    @Main private val mainExecutor: Executor,
     @Background private val backgroundExecutor: Executor,
     private val tunerService: TunerService,
     private val mediaBrowserFactory: ResumeMediaBrowserFactory,
@@ -77,18 +81,26 @@
     private var currentUserId: Int = context.userId
 
     @VisibleForTesting
-    val userChangeReceiver =
+    val userUnlockReceiver =
         object : BroadcastReceiver() {
             override fun onReceive(context: Context, intent: Intent) {
                 if (Intent.ACTION_USER_UNLOCKED == intent.action) {
-                    loadMediaResumptionControls()
-                } else if (Intent.ACTION_USER_SWITCHED == intent.action) {
-                    currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
-                    loadSavedComponents()
+                    val userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1)
+                    if (userId == currentUserId) {
+                        loadMediaResumptionControls()
+                    }
                 }
             }
         }
 
+    private val userTrackerCallback =
+        object : UserTracker.Callback {
+            override fun onUserChanged(newUser: Int, userContext: Context) {
+                currentUserId = newUser
+                loadSavedComponents()
+            }
+        }
+
     private val mediaBrowserCallback =
         object : ResumeMediaBrowser.Callback() {
             override fun addTrack(
@@ -126,13 +138,13 @@
             dumpManager.registerDumpable(TAG, this)
             val unlockFilter = IntentFilter()
             unlockFilter.addAction(Intent.ACTION_USER_UNLOCKED)
-            unlockFilter.addAction(Intent.ACTION_USER_SWITCHED)
             broadcastDispatcher.registerReceiver(
-                userChangeReceiver,
+                userUnlockReceiver,
                 unlockFilter,
                 null,
                 UserHandle.ALL
             )
+            userTracker.addCallback(userTrackerCallback, mainExecutor)
             loadSavedComponents()
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
index 8aaee81..1fdbc99 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaCarouselController.kt
@@ -184,6 +184,7 @@
 
     private val configListener =
         object : ConfigurationController.ConfigurationListener {
+
             override fun onDensityOrFontScaleChanged() {
                 // System font changes should only happen when UMO is offscreen or a flicker may
                 // occur
@@ -199,6 +200,7 @@
             override fun onConfigChanged(newConfig: Configuration?) {
                 if (newConfig == null) return
                 isRtl = newConfig.layoutDirection == View.LAYOUT_DIRECTION_RTL
+                updatePlayers(recreateMedia = true)
             }
 
             override fun onUiModeChanged() {
@@ -635,7 +637,7 @@
             val existingSmartspaceMediaKey = MediaPlayerData.smartspaceMediaKey()
             existingSmartspaceMediaKey?.let {
                 val removedPlayer =
-                    MediaPlayerData.removeMediaPlayer(existingSmartspaceMediaKey, true)
+                    removePlayer(existingSmartspaceMediaKey, dismissMediaData = false)
                 removedPlayer?.run {
                     debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey)
                 }
@@ -685,7 +687,7 @@
         key: String,
         dismissMediaData: Boolean = true,
         dismissRecommendation: Boolean = true
-    ) {
+    ): MediaControlPanel? {
         if (key == MediaPlayerData.smartspaceMediaKey()) {
             MediaPlayerData.smartspaceMediaData?.let {
                 logger.logRecommendationRemoved(it.packageName, it.instanceId)
@@ -693,7 +695,7 @@
         }
         val removed =
             MediaPlayerData.removeMediaPlayer(key, dismissMediaData || dismissRecommendation)
-        removed?.apply {
+        return removed?.apply {
             mediaCarouselScrollHandler.onPrePlayerRemoved(removed)
             mediaContent.removeView(removed.mediaViewHolder?.player)
             mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 21e64e2..827ac78 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -458,7 +458,9 @@
         if (mMediaViewHolder == null) {
             return;
         }
-        Trace.beginSection("MediaControlPanel#bindPlayer<" + key + ">");
+        if (Trace.isEnabled()) {
+            Trace.traceBegin(Trace.TRACE_TAG_APP, "MediaControlPanel#bindPlayer<" + key + ">");
+        }
         mKey = key;
         mMediaData = data;
         MediaSession.Token token = data.getToken();
@@ -1179,8 +1181,10 @@
             return;
         }
 
-        Trace.beginSection(
-                "MediaControlPanel#bindRecommendation<" + data.getPackageName() + ">");
+        if (Trace.isEnabled()) {
+            Trace.traceBegin(Trace.TRACE_TAG_APP,
+                    "MediaControlPanel#bindRecommendation<" + data.getPackageName() + ">");
+        }
 
         mRecommendationData = data;
         mSmartspaceId = SmallHash.hash(data.getTargetId());
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index cbb670e..f7a9bc7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -799,6 +799,16 @@
         }
 
         if (
+            desiredLocation == LOCATION_QS &&
+                previousLocation == LOCATION_LOCKSCREEN &&
+                statusbarState == StatusBarState.SHADE
+        ) {
+            // This is an invalid transition, can happen when tapping on home control and the UMO
+            // while being on landscape orientation in tablet.
+            return false
+        }
+
+        if (
             statusbarState == StatusBarState.KEYGUARD &&
                 (currentLocation == LOCATION_LOCKSCREEN || previousLocation == LOCATION_LOCKSCREEN)
         ) {
@@ -1043,18 +1053,9 @@
                     rootOverlay!!.add(mediaFrame)
                 } else {
                     val targetHost = getHost(newLocation)!!.hostView
-                    // When adding back to the host, let's make sure to reset the bounds.
-                    // Usually adding the view will trigger a layout that does this automatically,
-                    // but we sometimes suppress this.
+                    // This will either do a full layout pass and remeasure, or it will bypass
+                    // that and directly set the mediaFrame's bounds within the premeasured host.
                     targetHost.addView(mediaFrame)
-                    val left = targetHost.paddingLeft
-                    val top = targetHost.paddingTop
-                    mediaFrame.setLeftTopRightBottom(
-                        left,
-                        top,
-                        left + currentBounds.width(),
-                        top + currentBounds.height()
-                    )
 
                     if (mediaFrame.childCount > 0) {
                         val child = mediaFrame.getChildAt(0)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
index 4bf3031..4feb984 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaViewController.kt
@@ -420,7 +420,9 @@
      */
     fun getMeasurementsForState(hostState: MediaHostState): MeasurementOutput? =
         traceSection("MediaViewController#getMeasurementsForState") {
-            val viewState = obtainViewState(hostState) ?: return null
+            // measurements should never factor in the squish fraction
+            val viewState =
+                obtainViewState(hostState.copy().also { it.squishFraction = 1.0f }) ?: return null
             measurement.measuredWidth = viewState.width
             measurement.measuredHeight = viewState.height
             return measurement
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
index 33021e3..2c0745b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavBarHelper.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.navigationbar;
 
+import static android.app.StatusBarManager.WINDOW_NAVIGATION_BAR;
+import static android.app.StatusBarManager.WindowVisibleState;
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.view.WindowInsetsController.APPEARANCE_LOW_PROFILE_BARS;
 import static android.view.WindowInsetsController.APPEARANCE_OPAQUE_NAVIGATION_BARS;
@@ -58,6 +60,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.system.QuickStepContract;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.BarTransitions.TransitionMode;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -86,7 +89,7 @@
         AccessibilityButtonModeObserver.ModeChangedListener,
         AccessibilityButtonTargetsObserver.TargetsChangedListener,
         OverviewProxyService.OverviewProxyListener, NavigationModeController.ModeChangedListener,
-        Dumpable {
+        Dumpable, CommandQueue.Callbacks {
     private final AccessibilityManager mAccessibilityManager;
     private final Lazy<AssistManager> mAssistManagerLazy;
     private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
@@ -97,13 +100,18 @@
     private final AccessibilityButtonTargetsObserver mAccessibilityButtonTargetsObserver;
     private final List<NavbarTaskbarStateUpdater> mA11yEventListeners = new ArrayList<>();
     private final Context mContext;
-    private ContentResolver mContentResolver;
+    private final CommandQueue mCommandQueue;
+    private final ContentResolver mContentResolver;
     private boolean mAssistantAvailable;
     private boolean mLongPressHomeEnabled;
     private boolean mAssistantTouchGestureEnabled;
     private int mNavBarMode;
     private int mA11yButtonState;
 
+    // Attributes used in NavBarHelper.CurrentSysuiState
+    private int mWindowStateDisplayId;
+    private @WindowVisibleState int mWindowState;
+
     private final ContentObserver mAssistContentObserver = new ContentObserver(
             new Handler(Looper.getMainLooper())) {
         @Override
@@ -128,8 +136,10 @@
             KeyguardStateController keyguardStateController,
             NavigationModeController navigationModeController,
             UserTracker userTracker,
-            DumpManager dumpManager) {
+            DumpManager dumpManager,
+            CommandQueue commandQueue) {
         mContext = context;
+        mCommandQueue = commandQueue;
         mContentResolver = mContext.getContentResolver();
         mAccessibilityManager = accessibilityManager;
         mAssistManagerLazy = assistManagerLazy;
@@ -160,10 +170,13 @@
                 false, mAssistContentObserver, UserHandle.USER_ALL);
         updateAssistantAvailability();
         updateA11yState();
+        mCommandQueue.addCallback(this);
+
     }
 
     public void destroy() {
         mContentResolver.unregisterContentObserver(mAssistContentObserver);
+        mCommandQueue.removeCallback(this);
     }
 
     /**
@@ -333,6 +346,20 @@
                 || (!isKeyguardShowing && (vis & InputMethodService.IME_VISIBLE) != 0);
     }
 
+    @Override
+    public void setWindowState(int displayId, int window, int state) {
+        CommandQueue.Callbacks.super.setWindowState(displayId, window, state);
+        if (window != WINDOW_NAVIGATION_BAR) {
+            return;
+        }
+        mWindowStateDisplayId = displayId;
+        mWindowState = state;
+    }
+
+    public CurrentSysuiState getCurrentSysuiState() {
+        return new CurrentSysuiState();
+    }
+
     /**
      * Callbacks will get fired once immediately after registering via
      * {@link #registerNavTaskStateUpdater(NavbarTaskbarStateUpdater)}
@@ -342,6 +369,17 @@
         void updateAssistantAvailable(boolean available);
     }
 
+    /** Data class to help Taskbar/Navbar initiate state correctly when switching between the two.*/
+    public class CurrentSysuiState {
+        public final int mWindowStateDisplayId;
+        public final @WindowVisibleState int mWindowState;
+
+        public CurrentSysuiState() {
+            mWindowStateDisplayId = NavBarHelper.this.mWindowStateDisplayId;
+            mWindowState = NavBarHelper.this.mWindowState;
+        }
+    }
+
     static @TransitionMode int transitionMode(boolean isTransient, int appearance) {
         final int lightsOutOpaque = APPEARANCE_LOW_PROFILE_BARS | APPEARANCE_OPAQUE_NAVIGATION_BARS;
         if (isTransient) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index b9f5859..5202562 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -57,13 +57,12 @@
 import static com.android.systemui.util.Utils.isGesturalModeOnDefaultDisplay;
 
 import android.annotation.IdRes;
+import android.annotation.NonNull;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
 import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
@@ -120,7 +119,6 @@
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.qualifiers.Background;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -138,6 +136,7 @@
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 import com.android.systemui.shared.recents.utilities.Utilities;
@@ -208,7 +207,7 @@
     private final NotificationRemoteInputManager mNotificationRemoteInputManager;
     private final OverviewProxyService mOverviewProxyService;
     private final NavigationModeController mNavigationModeController;
-    private final BroadcastDispatcher mBroadcastDispatcher;
+    private final UserTracker mUserTracker;
     private final CommandQueue mCommandQueue;
     private final Optional<Pip> mPipOptional;
     private final Optional<Recents> mRecentsOptional;
@@ -516,7 +515,7 @@
             StatusBarStateController statusBarStateController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
             SysUiState sysUiFlagsContainer,
-            BroadcastDispatcher broadcastDispatcher,
+            UserTracker userTracker,
             CommandQueue commandQueue,
             Optional<Pip> pipOptional,
             Optional<Recents> recentsOptional,
@@ -559,7 +558,7 @@
         mNotificationRemoteInputManager = notificationRemoteInputManager;
         mOverviewProxyService = overviewProxyService;
         mNavigationModeController = navigationModeController;
-        mBroadcastDispatcher = broadcastDispatcher;
+        mUserTracker = userTracker;
         mCommandQueue = commandQueue;
         mPipOptional = pipOptional;
         mRecentsOptional = recentsOptional;
@@ -666,6 +665,9 @@
         mDisplayId = mContext.getDisplayId();
         mIsOnDefaultDisplay = mDisplayId == DEFAULT_DISPLAY;
 
+        // Ensure we try to get currentSysuiState from navBarHelper before command queue callbacks
+        // start firing, since the latter is source of truth
+        parseCurrentSysuiState();
         mCommandQueue.addCallback(this);
         mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
         mNavBarHelper.init();
@@ -742,9 +744,7 @@
         prepareNavigationBarView();
         checkNavBarModes();
 
-        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-        mBroadcastDispatcher.registerReceiverWithHandler(mBroadcastReceiver, filter,
-                Handler.getMain(), UserHandle.ALL);
+        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
         notifyNavigationBarScreenOn();
 
@@ -795,7 +795,7 @@
         mView.setUpdateActiveTouchRegionsCallback(null);
         getBarTransitions().destroy();
         mOverviewProxyService.removeCallback(mOverviewProxyListener);
-        mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
+        mUserTracker.removeCallback(mUserChangedCallback);
         mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
         if (mOrientationHandle != null) {
             resetSecondaryHandle();
@@ -952,6 +952,13 @@
         setOrientedHandleSamplingRegion(null);
     }
 
+    private void parseCurrentSysuiState() {
+        NavBarHelper.CurrentSysuiState state = mNavBarHelper.getCurrentSysuiState();
+        if (state.mWindowStateDisplayId == mDisplayId) {
+            mNavigationBarWindowState = state.mWindowState;
+        }
+    }
+
     private void reconfigureHomeLongClick() {
         if (mView.getHomeButton().getCurrentView() == null) {
             return;
@@ -1733,21 +1740,14 @@
         }
     };
 
-    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            // TODO(193941146): Currently unregistering a receiver through BroadcastDispatcher is
-            // async, but we've already cleared the fields. Just return early in this case.
-            if (mView == null) {
-                return;
-            }
-            String action = intent.getAction();
-            if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                // The accessibility settings may be different for the new user
-                updateAccessibilityStateFlags();
-            }
-        }
-    };
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    // The accessibility settings may be different for the new user
+                    updateAccessibilityStateFlags();
+                }
+            };
 
     @VisibleForTesting
     int getNavigationIconHints() {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index eb87ff0..ac7c70b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -214,6 +214,7 @@
             return;
         }
         mDisplayId = displayId;
+        parseCurrentSysuiState();
         mCommandQueue.addCallback(this);
         mOverviewProxyService.addCallback(this);
         mEdgeBackGestureHandler.onNavigationModeChanged(
@@ -271,6 +272,13 @@
         return mInitialized;
     }
 
+    private void parseCurrentSysuiState() {
+        NavBarHelper.CurrentSysuiState state = mNavBarHelper.getCurrentSysuiState();
+        if (state.mWindowStateDisplayId == mDisplayId) {
+            mTaskBarWindowState = state.mWindowState;
+        }
+    }
+
     private void updateSysuiFlags() {
         int a11yFlags = mNavBarHelper.getA11yButtonState();
         boolean clickable = (a11yFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1da866e..5a1ad96 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -39,6 +39,8 @@
 import android.util.Log;
 import android.util.Slog;
 
+import androidx.annotation.NonNull;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settingslib.fuelgauge.Estimate;
 import com.android.settingslib.utils.ThreadUtils;
@@ -47,6 +49,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 
@@ -80,6 +83,7 @@
     private final PowerManager mPowerManager;
     private final WarningsUI mWarnings;
     private final WakefulnessLifecycle mWakefulnessLifecycle;
+    private final UserTracker mUserTracker;
     private InattentiveSleepWarningView mOverlayView;
     private final Configuration mLastConfiguration = new Configuration();
     private int mPlugType = 0;
@@ -122,12 +126,21 @@
                 }
             };
 
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    mWarnings.userSwitched();
+                }
+            };
+
     @Inject
     public PowerUI(Context context, BroadcastDispatcher broadcastDispatcher,
             CommandQueue commandQueue, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             WarningsUI warningsUI, EnhancedEstimates enhancedEstimates,
             WakefulnessLifecycle wakefulnessLifecycle,
-            PowerManager powerManager) {
+            PowerManager powerManager,
+            UserTracker userTracker) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mCommandQueue = commandQueue;
@@ -136,6 +149,7 @@
         mEnhancedEstimates = enhancedEstimates;
         mPowerManager = powerManager;
         mWakefulnessLifecycle = wakefulnessLifecycle;
+        mUserTracker = userTracker;
     }
 
     public void start() {
@@ -154,6 +168,7 @@
                 false, obs, UserHandle.USER_ALL);
         updateBatteryWarningLevels();
         mReceiver.init();
+        mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
         mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
 
         // Check to see if we need to let the user know that the phone previously shut down due
@@ -250,7 +265,6 @@
             IntentFilter filter = new IntentFilter();
             filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
             mBroadcastDispatcher.registerReceiverWithHandler(this, filter, mHandler);
             // Force get initial values. Relying on Sticky behavior until API for getting info.
             if (!mHasReceivedBattery) {
@@ -332,8 +346,6 @@
                             plugged, bucket);
                 });
 
-            } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                mWarnings.userSwitched();
             } else {
                 Slog.w(TAG, "unknown intent: " + intent);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
index bb2b441..3c10778 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/FgsManagerController.kt
@@ -18,6 +18,9 @@
 
 import android.app.IActivityManager
 import android.app.IForegroundServiceObserver
+import android.app.job.IUserVisibleJobObserver
+import android.app.job.JobScheduler
+import android.app.job.UserVisibleJobSummary
 import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
@@ -47,6 +50,7 @@
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_ENABLED
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_FOOTER_DOT
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.systemui.Dumpable
 import com.android.systemui.R
@@ -92,6 +96,8 @@
      */
     val showFooterDot: StateFlow<Boolean>
 
+    val includesUserVisibleJobs: Boolean
+
     /**
      * Initialize this controller. This should be called once, before this controller is used for
      * the first time.
@@ -141,19 +147,21 @@
     @Background private val backgroundExecutor: Executor,
     private val systemClock: SystemClock,
     private val activityManager: IActivityManager,
+    private val jobScheduler: JobScheduler,
     private val packageManager: PackageManager,
     private val userTracker: UserTracker,
     private val deviceConfigProxy: DeviceConfigProxy,
     private val dialogLaunchAnimator: DialogLaunchAnimator,
     private val broadcastDispatcher: BroadcastDispatcher,
     private val dumpManager: DumpManager
-) : IForegroundServiceObserver.Stub(), Dumpable, FgsManagerController {
+) : Dumpable, FgsManagerController {
 
     companion object {
         private const val INTERACTION_JANK_TAG = "active_background_apps"
         private const val DEFAULT_TASK_MANAGER_ENABLED = true
         private const val DEFAULT_TASK_MANAGER_SHOW_FOOTER_DOT = false
         private const val DEFAULT_TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS = true
+        private const val DEFAULT_TASK_MANAGER_SHOW_USER_VISIBLE_JOBS = false
     }
 
     override var newChangesSinceDialogWasDismissed = false
@@ -167,6 +175,11 @@
 
     private var showStopBtnForUserAllowlistedApps = false
 
+    private var showUserVisibleJobs = DEFAULT_TASK_MANAGER_SHOW_USER_VISIBLE_JOBS
+
+    override val includesUserVisibleJobs: Boolean
+        get() = showUserVisibleJobs
+
     override val numRunningPackages: Int
         get() {
             synchronized(lock) {
@@ -186,7 +199,7 @@
     private var currentProfileIds = mutableSetOf<Int>()
 
     @GuardedBy("lock")
-    private val runningServiceTokens = mutableMapOf<UserPackage, StartTimeAndTokens>()
+    private val runningTaskIdentifiers = mutableMapOf<UserPackage, StartTimeAndIdentifiers>()
 
     @GuardedBy("lock")
     private var dialog: SystemUIDialog? = null
@@ -210,13 +223,29 @@
         }
     }
 
+    private val foregroundServiceObserver = ForegroundServiceObserver()
+
+    private val userVisibleJobObserver = UserVisibleJobObserver()
+
     override fun init() {
         synchronized(lock) {
             if (initialized) {
                 return
             }
+
+            showUserVisibleJobs = deviceConfigProxy.getBoolean(
+                NAMESPACE_SYSTEMUI,
+                TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, DEFAULT_TASK_MANAGER_SHOW_USER_VISIBLE_JOBS)
+
             try {
-                activityManager.registerForegroundServiceObserver(this)
+                activityManager.registerForegroundServiceObserver(foregroundServiceObserver)
+                // Clumping FGS and user-visible jobs here and showing a single entry and button
+                // for them is the easiest way to get user-visible jobs showing in Task Manager.
+                // Ideally, we would have dedicated UI in task manager for the user-visible jobs.
+                // TODO(255768978): distinguish jobs from FGS and give users more control
+                if (showUserVisibleJobs) {
+                    jobScheduler.registerUserVisibleJobObserver(userVisibleJobObserver)
+                }
             } catch (e: RemoteException) {
                 e.rethrowFromSystemServer()
             }
@@ -235,6 +264,12 @@
                 showStopBtnForUserAllowlistedApps = it.getBoolean(
                     TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS,
                     showStopBtnForUserAllowlistedApps)
+                var wasShowingUserVisibleJobs = showUserVisibleJobs
+                showUserVisibleJobs = it.getBoolean(
+                        TASK_MANAGER_SHOW_USER_VISIBLE_JOBS, showUserVisibleJobs)
+                if (showUserVisibleJobs != wasShowingUserVisibleJobs) {
+                    onShowUserVisibleJobsFlagChanged()
+                }
             }
 
             _isAvailable.value = deviceConfigProxy.getBoolean(
@@ -269,32 +304,6 @@
         }
     }
 
-    override fun onForegroundStateChanged(
-        token: IBinder,
-        packageName: String,
-        userId: Int,
-        isForeground: Boolean
-    ) {
-        synchronized(lock) {
-            val userPackageKey = UserPackage(userId, packageName)
-            if (isForeground) {
-                runningServiceTokens.getOrPut(userPackageKey) { StartTimeAndTokens(systemClock) }
-                    .addToken(token)
-            } else {
-                if (runningServiceTokens[userPackageKey]?.also {
-                    it.removeToken(token)
-                }?.isEmpty() == true
-                ) {
-                    runningServiceTokens.remove(userPackageKey)
-                }
-            }
-
-            updateNumberOfVisibleRunningPackagesLocked()
-
-            updateAppItemsLocked()
-        }
-    }
-
     @GuardedBy("lock")
     private val onNumberOfPackagesChangedListeners =
         mutableSetOf<FgsManagerController.OnNumberOfPackagesChangedListener>()
@@ -336,7 +345,7 @@
     }
 
     private fun getNumVisiblePackagesLocked(): Int {
-        return runningServiceTokens.keys.count {
+        return runningTaskIdentifiers.keys.count {
             it.uiControl != UIControl.HIDE_ENTRY && currentProfileIds.contains(it.userId)
         }
     }
@@ -361,7 +370,7 @@
     }
 
     private fun getNumVisibleButtonsLocked(): Int {
-        return runningServiceTokens.keys.count {
+        return runningTaskIdentifiers.keys.count {
             it.uiControl != UIControl.HIDE_BUTTON && currentProfileIds.contains(it.userId)
         }
     }
@@ -372,7 +381,7 @@
         synchronized(lock) {
             if (dialog == null) {
 
-                runningServiceTokens.keys.forEach {
+                runningTaskIdentifiers.keys.forEach {
                     it.updateUiControl()
                 }
 
@@ -434,17 +443,17 @@
             return
         }
 
-        val addedPackages = runningServiceTokens.keys.filter {
+        val addedPackages = runningTaskIdentifiers.keys.filter {
             currentProfileIds.contains(it.userId) &&
                     it.uiControl != UIControl.HIDE_ENTRY && runningApps[it]?.stopped != true
         }
-        val removedPackages = runningApps.keys.filter { !runningServiceTokens.containsKey(it) }
+        val removedPackages = runningApps.keys.filter { !runningTaskIdentifiers.containsKey(it) }
 
         addedPackages.forEach {
             val ai = packageManager.getApplicationInfoAsUser(it.packageName, 0, it.userId)
             runningApps[it] = RunningApp(
                 it.userId, it.packageName,
-                runningServiceTokens[it]!!.startTime, it.uiControl,
+                runningTaskIdentifiers[it]!!.startTime, it.uiControl,
                 packageManager.getApplicationLabel(ai),
                 packageManager.getUserBadgedIcon(
                     packageManager.getApplicationIcon(ai), UserHandle.of(it.userId)
@@ -471,7 +480,41 @@
 
     private fun stopPackage(userId: Int, packageName: String, timeStarted: Long) {
         logEvent(stopped = true, packageName, userId, timeStarted)
-        activityManager.stopAppForUser(packageName, userId)
+        val userPackageKey = UserPackage(userId, packageName)
+        if (showUserVisibleJobs &&
+                runningTaskIdentifiers[userPackageKey]?.hasRunningJobs() == true) {
+            // TODO(255768978): allow fine-grained job control
+            jobScheduler.stopUserVisibleJobsForUser(packageName, userId)
+        }
+        if (runningTaskIdentifiers[userPackageKey]?.hasFgs() == true) {
+            activityManager.stopAppForUser(packageName, userId)
+        }
+    }
+
+    private fun onShowUserVisibleJobsFlagChanged() {
+        if (showUserVisibleJobs) {
+            jobScheduler.registerUserVisibleJobObserver(userVisibleJobObserver)
+        } else {
+            jobScheduler.unregisterUserVisibleJobObserver(userVisibleJobObserver)
+
+            synchronized(lock) {
+                for ((userPackage, startTimeAndIdentifiers) in runningTaskIdentifiers) {
+                    if (startTimeAndIdentifiers.hasFgs()) {
+                        // The app still has FGS running, so all we need to do is remove
+                        // the job summaries
+                        startTimeAndIdentifiers.clearJobSummaries()
+                    } else {
+                        // The app only has user-visible jobs running, so remove it from
+                        // the map altogether
+                        runningTaskIdentifiers.remove(userPackage)
+                    }
+                }
+
+                updateNumberOfVisibleRunningPackagesLocked()
+
+                updateAppItemsLocked()
+            }
+        }
     }
 
     private fun logEvent(stopped: Boolean, packageName: String, userId: Int, timeStarted: Long) {
@@ -564,6 +607,62 @@
         }
     }
 
+    private inner class ForegroundServiceObserver : IForegroundServiceObserver.Stub() {
+        override fun onForegroundStateChanged(
+                token: IBinder,
+                packageName: String,
+                userId: Int,
+                isForeground: Boolean
+        ) {
+            synchronized(lock) {
+                val userPackageKey = UserPackage(userId, packageName)
+                if (isForeground) {
+                    runningTaskIdentifiers
+                            .getOrPut(userPackageKey) { StartTimeAndIdentifiers(systemClock) }
+                            .addFgsToken(token)
+                } else {
+                    if (runningTaskIdentifiers[userPackageKey]?.also {
+                                it.removeFgsToken(token)
+                            }?.isEmpty() == true
+                    ) {
+                        runningTaskIdentifiers.remove(userPackageKey)
+                    }
+                }
+
+                updateNumberOfVisibleRunningPackagesLocked()
+
+                updateAppItemsLocked()
+            }
+        }
+    }
+
+    private inner class UserVisibleJobObserver : IUserVisibleJobObserver.Stub() {
+        override fun onUserVisibleJobStateChanged(
+                summary: UserVisibleJobSummary,
+                isRunning: Boolean
+        ) {
+            synchronized(lock) {
+                val userPackageKey = UserPackage(summary.sourceUserId, summary.sourcePackageName)
+                if (isRunning) {
+                    runningTaskIdentifiers
+                            .getOrPut(userPackageKey) { StartTimeAndIdentifiers(systemClock) }
+                            .addJobSummary(summary)
+                } else {
+                    if (runningTaskIdentifiers[userPackageKey]?.also {
+                                it.removeJobSummary(summary)
+                            }?.isEmpty() == true
+                    ) {
+                        runningTaskIdentifiers.remove(userPackageKey)
+                    }
+                }
+
+                updateNumberOfVisibleRunningPackagesLocked()
+
+                updateAppItemsLocked()
+            }
+        }
+    }
+
     private inner class UserPackage(
         val userId: Int,
         val packageName: String
@@ -630,37 +729,64 @@
         }
     }
 
-    private data class StartTimeAndTokens(
+    private data class StartTimeAndIdentifiers(
         val systemClock: SystemClock
     ) {
         val startTime = systemClock.elapsedRealtime()
-        val tokens = mutableSetOf<IBinder>()
+        val fgsTokens = mutableSetOf<IBinder>()
+        val jobSummaries = mutableSetOf<UserVisibleJobSummary>()
 
-        fun addToken(token: IBinder) {
-            tokens.add(token)
+        fun addJobSummary(summary: UserVisibleJobSummary) {
+            jobSummaries.add(summary)
         }
 
-        fun removeToken(token: IBinder) {
-            tokens.remove(token)
+        fun clearJobSummaries() {
+            jobSummaries.clear()
+        }
+
+        fun removeJobSummary(summary: UserVisibleJobSummary) {
+            jobSummaries.remove(summary)
+        }
+
+        fun addFgsToken(token: IBinder) {
+            fgsTokens.add(token)
+        }
+
+        fun removeFgsToken(token: IBinder) {
+            fgsTokens.remove(token)
+        }
+
+        fun hasFgs(): Boolean {
+            return !fgsTokens.isEmpty()
+        }
+
+        fun hasRunningJobs(): Boolean {
+            return !jobSummaries.isEmpty()
         }
 
         fun isEmpty(): Boolean {
-            return tokens.isEmpty()
+            return fgsTokens.isEmpty() && jobSummaries.isEmpty()
         }
 
         fun dump(pw: PrintWriter) {
-            pw.println("StartTimeAndTokens: [")
+            pw.println("StartTimeAndIdentifiers: [")
             pw.indentIfPossible {
                 pw.println(
                     "startTime=$startTime (time running =" +
                         " ${systemClock.elapsedRealtime() - startTime}ms)"
                 )
-                pw.println("tokens: [")
+                pw.println("fgs tokens: [")
                 pw.indentIfPossible {
-                    for (token in tokens) {
+                    for (token in fgsTokens) {
                         pw.println("$token")
                     }
                 }
+                pw.println("job summaries: [")
+                pw.indentIfPossible {
+                    for (summary in jobSummaries) {
+                        pw.println("$summary")
+                    }
+                }
                 pw.println("]")
             }
             pw.println("]")
@@ -724,13 +850,13 @@
         synchronized(lock) {
             pw.println("current user profiles = $currentProfileIds")
             pw.println("newChangesSinceDialogWasShown=$newChangesSinceDialogWasDismissed")
-            pw.println("Running service tokens: [")
+            pw.println("Running task identifiers: [")
             pw.indentIfPossible {
-                runningServiceTokens.forEach { (userPackage, startTimeAndTokens) ->
+                runningTaskIdentifiers.forEach { (userPackage, startTimeAndIdentifiers) ->
                     pw.println("{")
                     pw.indentIfPossible {
                         userPackage.dump(pw)
-                        startTimeAndTokens.dump(pw)
+                        startTimeAndIdentifiers.dump(pw)
                     }
                     pw.println("}")
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
index 314252b..4c9c99c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/user/UserSwitchDialogController.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.qs.QSUserSwitcherEvent
 import com.android.systemui.qs.tiles.UserDetailView
 import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.user.ui.dialog.DialogShowerImpl
 import javax.inject.Inject
 import javax.inject.Provider
 
@@ -130,19 +131,6 @@
         }
     }
 
-    private class DialogShowerImpl(
-        private val animateFrom: Dialog,
-        private val dialogLaunchAnimator: DialogLaunchAnimator
-    ) : DialogInterface by animateFrom, DialogShower {
-        override fun showDialog(dialog: Dialog, cuj: DialogCuj) {
-            dialogLaunchAnimator.showFromDialog(
-                dialog,
-                animateFrom = animateFrom,
-                cuj
-            )
-        }
-    }
-
     interface DialogShower : DialogInterface {
         fun showDialog(dialog: Dialog, cuj: DialogCuj)
     }
diff --git a/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java
new file mode 100644
index 0000000..802db7e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/reardisplay/RearDisplayDialogController.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.reardisplay;
+
+import android.annotation.SuppressLint;
+import android.annotation.TestApi;
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.hardware.devicestate.DeviceStateManagerGlobal;
+import android.view.View;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.CoreStartable;
+import com.android.systemui.R;
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.Main;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieDrawable;
+
+import java.util.concurrent.Executor;
+
+import javax.inject.Inject;
+
+/**
+ * Provides an educational dialog to the user alerting them to what
+ * they may need to do to enter rear display mode. This may be to open the
+ * device if it is currently folded, or to confirm that they would like
+ * the content to move to the screen on their device that is aligned with
+ * the rear camera. This includes a device animation to provide more context
+ * to the user.
+ *
+ * We are suppressing lint for the VisibleForTests check because the use of
+ * DeviceStateManagerGlobal as in this file should not be encouraged for other use-cases.
+ * The lint check will notify any other use-cases that they are possibly doing something
+ * incorrectly.
+ */
+@SuppressLint("VisibleForTests") // TODO(b/260264542) Migrate away from DeviceStateManagerGlobal
+@SysUISingleton
+public class RearDisplayDialogController implements CoreStartable, CommandQueue.Callbacks {
+
+    private int[] mFoldedStates;
+    private boolean mStartedFolded;
+    private boolean mServiceNotified = false;
+    private int mAnimationRepeatCount = LottieDrawable.INFINITE;
+
+    private DeviceStateManagerGlobal mDeviceStateManagerGlobal;
+    private DeviceStateManager.DeviceStateCallback mDeviceStateManagerCallback =
+            new DeviceStateManagerCallback();
+
+    private final Context mContext;
+    private final CommandQueue mCommandQueue;
+    private final Executor mExecutor;
+
+    @VisibleForTesting
+    SystemUIDialog mRearDisplayEducationDialog;
+
+    @Inject
+    public RearDisplayDialogController(Context context, CommandQueue commandQueue,
+            @Main Executor executor) {
+        mContext = context;
+        mCommandQueue = commandQueue;
+        mExecutor = executor;
+    }
+
+    @Override
+    public void start() {
+        mCommandQueue.addCallback(this);
+    }
+
+    @Override
+    public void showRearDisplayDialog(int currentBaseState) {
+        initializeValues(currentBaseState);
+        createAndShowDialog();
+    }
+
+    private void createAndShowDialog() {
+        mServiceNotified = false;
+        Context dialogContext = mRearDisplayEducationDialog.getContext();
+
+        View dialogView;
+        if (mStartedFolded) {
+            dialogView = View.inflate(dialogContext,
+                    R.layout.activity_rear_display_education, null);
+        } else {
+            dialogView = View.inflate(dialogContext,
+                    R.layout.activity_rear_display_education_opened, null);
+        }
+        LottieAnimationView animationView = dialogView.findViewById(
+                R.id.rear_display_folded_animation);
+        animationView.setRepeatCount(mAnimationRepeatCount);
+        mRearDisplayEducationDialog.setView(dialogView);
+
+        configureDialogButtons();
+
+        mRearDisplayEducationDialog.show();
+    }
+
+    /**
+     * Configures the buttons on the dialog depending on the starting device posture
+     */
+    private void configureDialogButtons() {
+        // If we are open, we need to provide a confirm option
+        if (!mStartedFolded) {
+            mRearDisplayEducationDialog.setPositiveButton(
+                    R.string.rear_display_bottom_sheet_confirm,
+                    (dialog, which) -> closeOverlayAndNotifyService(false), true);
+        }
+        mRearDisplayEducationDialog.setNegativeButton(R.string.rear_display_bottom_sheet_cancel,
+                (dialog, which) -> closeOverlayAndNotifyService(true), true);
+        mRearDisplayEducationDialog.setOnDismissListener(dialog -> {
+            // Dialog is being dismissed before we've notified the system server
+            if (!mServiceNotified) {
+                closeOverlayAndNotifyService(true);
+            }
+        });
+    }
+
+    /**
+     * Initializes properties and values we need when getting ready to show the dialog.
+     *
+     * Ensures we're not using old values from when the dialog may have been shown previously.
+     */
+    private void initializeValues(int startingBaseState) {
+        mRearDisplayEducationDialog = new SystemUIDialog(mContext);
+        if (mFoldedStates == null) {
+            mFoldedStates = mContext.getResources().getIntArray(
+                    com.android.internal.R.array.config_foldedDeviceStates);
+        }
+        mStartedFolded = isFoldedState(startingBaseState);
+        mDeviceStateManagerGlobal = DeviceStateManagerGlobal.getInstance();
+        mDeviceStateManagerGlobal.registerDeviceStateCallback(mDeviceStateManagerCallback,
+                mExecutor);
+    }
+
+    private boolean isFoldedState(int state) {
+        for (int i = 0; i < mFoldedStates.length; i++) {
+            if (mFoldedStates[i] == state) return true;
+        }
+        return false;
+    }
+
+    /**
+     * Closes the educational overlay, and notifies the system service if rear display mode
+     * should be cancelled or enabled.
+     */
+    private void closeOverlayAndNotifyService(boolean shouldCancelRequest) {
+        mServiceNotified = true;
+        mDeviceStateManagerGlobal.unregisterDeviceStateCallback(mDeviceStateManagerCallback);
+        mDeviceStateManagerGlobal.onStateRequestOverlayDismissed(shouldCancelRequest);
+    }
+
+    /**
+     * TestAPI to allow us to set the folded states array, instead of reading from resources.
+     */
+    @TestApi
+    void setFoldedStates(int[] foldedStates) {
+        mFoldedStates = foldedStates;
+    }
+
+    @TestApi
+    void setDeviceStateManagerCallback(
+            DeviceStateManager.DeviceStateCallback deviceStateManagerCallback) {
+        mDeviceStateManagerCallback = deviceStateManagerCallback;
+    }
+
+    @TestApi
+    void setAnimationRepeatCount(int repeatCount) {
+        mAnimationRepeatCount = repeatCount;
+    }
+
+    private class DeviceStateManagerCallback implements DeviceStateManager.DeviceStateCallback {
+        @Override
+        public void onBaseStateChanged(int state) {
+            if (mStartedFolded && !isFoldedState(state)) {
+                // We've opened the device, we can close the overlay
+                mRearDisplayEducationDialog.dismiss();
+                closeOverlayAndNotifyService(false);
+            } else if (!mStartedFolded && isFoldedState(state)) {
+                // We've closed the device, finish activity
+                mRearDisplayEducationDialog.dismiss();
+                closeOverlayAndNotifyService(true);
+            }
+        }
+
+        // We only care about physical device changes in this scenario
+        @Override
+        public void onStateChanged(int state) {}
+    }
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 2ee5f05..645b125 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -51,10 +51,13 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.navigationbar.NavigationModeController;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.util.leak.RotationUtils;
@@ -76,6 +79,7 @@
     private final AccessibilityManager mAccessibilityService;
     private final WindowManager mWindowManager;
     private final BroadcastDispatcher mBroadcastDispatcher;
+    private final UserTracker mUserTracker;
 
     private RequestWindowView mRequestWindow;
     private int mNavBarMode;
@@ -83,12 +87,21 @@
     /** ID of task to be pinned or locked. */
     private int taskId;
 
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    clearPrompt();
+                }
+            };
+
     @Inject
     public ScreenPinningRequest(
             Context context,
             Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
             NavigationModeController navigationModeController,
-            BroadcastDispatcher broadcastDispatcher) {
+            BroadcastDispatcher broadcastDispatcher,
+            UserTracker userTracker) {
         mContext = context;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
         mAccessibilityService = (AccessibilityManager)
@@ -97,6 +110,7 @@
                 mContext.getSystemService(Context.WINDOW_SERVICE);
         mNavBarMode = navigationModeController.addListener(this);
         mBroadcastDispatcher = broadcastDispatcher;
+        mUserTracker = userTracker;
     }
 
     public void clearPrompt() {
@@ -228,9 +242,9 @@
             }
 
             IntentFilter filter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED);
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
             filter.addAction(Intent.ACTION_SCREEN_OFF);
             mBroadcastDispatcher.registerReceiver(mReceiver, filter);
+            mUserTracker.addCallback(mUserChangedCallback, mContext.getMainExecutor());
         }
 
         private void inflateView(int rotation) {
@@ -358,6 +372,7 @@
         @Override
         public void onDetachedFromWindow() {
             mBroadcastDispatcher.unregisterReceiver(mReceiver);
+            mUserTracker.removeCallback(mUserChangedCallback);
         }
 
         protected void onConfigurationChanged() {
@@ -388,8 +403,7 @@
             public void onReceive(Context context, Intent intent) {
                 if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
                     post(mUpdateLayoutRunnable);
-                } else if (intent.getAction().equals(Intent.ACTION_USER_SWITCHED)
-                        || intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
+                } else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                     clearPrompt();
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
index f4d59a8..db0052a 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/BaseScreenSharePermissionDialog.kt
@@ -23,8 +23,11 @@
 import android.view.WindowManager
 import android.widget.AdapterView
 import android.widget.ArrayAdapter
+import android.widget.ImageView
 import android.widget.Spinner
 import android.widget.TextView
+import androidx.annotation.ColorRes
+import androidx.annotation.DrawableRes
 import androidx.annotation.LayoutRes
 import androidx.annotation.StringRes
 import com.android.systemui.R
@@ -34,7 +37,9 @@
 open class BaseScreenSharePermissionDialog(
     context: Context?,
     private val screenShareOptions: List<ScreenShareOption>,
-    private val appName: String?
+    private val appName: String?,
+    @DrawableRes private val dialogIconDrawable: Int? = null,
+    @ColorRes private val dialogIconTint: Int? = null
 ) : SystemUIDialog(context), AdapterView.OnItemSelectedListener {
     private lateinit var dialogTitle: TextView
     private lateinit var startButton: TextView
@@ -53,10 +58,21 @@
         warning = findViewById(R.id.text_warning)
         startButton = findViewById(R.id.button_start)
         findViewById<TextView>(R.id.button_cancel).setOnClickListener { dismiss() }
+        updateIcon()
         initScreenShareOptions()
         createOptionsView(getOptionsViewLayoutId())
     }
 
+    private fun updateIcon() {
+        val icon = findViewById<ImageView>(R.id.screen_share_dialog_icon)
+        if (dialogIconTint != null) {
+            icon.setColorFilter(context.getColor(dialogIconTint))
+        }
+        if (dialogIconDrawable != null) {
+            icon.setImageDrawable(context.getDrawable(dialogIconDrawable))
+        }
+    }
+
     protected fun initScreenShareOptions() {
         selectedScreenShareOption = screenShareOptions.first()
         warning.text = warningText
@@ -69,8 +85,12 @@
     private fun initScreenShareSpinner() {
         val options = screenShareOptions.map { context.getString(it.spinnerText) }.toTypedArray()
         val adapter =
-            ArrayAdapter(context.applicationContext, android.R.layout.simple_spinner_item, options)
-        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
+            ArrayAdapter(
+                context.applicationContext,
+                R.layout.screen_share_dialog_spinner_text,
+                options
+            )
+        adapter.setDropDownViewResource(R.layout.screen_share_dialog_spinner_item_text)
         screenShareModeSpinner = findViewById(R.id.screen_share_mode_spinner)
         screenShareModeSpinner.adapter = adapter
         screenShareModeSpinner.onItemSelectedListener = this
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
index 15b0bc4..c5a82ce1 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/MediaProjectionPermissionDialog.kt
@@ -23,11 +23,15 @@
 class MediaProjectionPermissionDialog(
     context: Context?,
     private val onStartRecordingClicked: Runnable,
-    appName: String?
-) : BaseScreenSharePermissionDialog(context, createOptionList(), appName) {
+    private val appName: String?
+) : BaseScreenSharePermissionDialog(context, createOptionList(appName), appName) {
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
-        setDialogTitle(R.string.media_projection_permission_dialog_title)
+        if (appName == null) {
+            setDialogTitle(R.string.media_projection_permission_dialog_system_service_title)
+        } else {
+            setDialogTitle(R.string.media_projection_permission_dialog_title)
+        }
         setStartButtonText(R.string.media_projection_permission_dialog_continue)
         setStartButtonOnClickListener {
             // Note that it is important to run this callback before dismissing, so that the
@@ -38,17 +42,30 @@
     }
 
     companion object {
-        private fun createOptionList(): List<ScreenShareOption> {
+        private fun createOptionList(appName: String?): List<ScreenShareOption> {
+            val singleAppWarningText =
+                if (appName == null) {
+                    R.string.media_projection_permission_dialog_system_service_warning_single_app
+                } else {
+                    R.string.media_projection_permission_dialog_warning_single_app
+                }
+            val entireScreenWarningText =
+                if (appName == null) {
+                    R.string.media_projection_permission_dialog_system_service_warning_entire_screen
+                } else {
+                    R.string.media_projection_permission_dialog_warning_entire_screen
+                }
+
             return listOf(
                 ScreenShareOption(
-                    SINGLE_APP,
-                    R.string.media_projection_permission_dialog_option_single_app,
-                    R.string.media_projection_permission_dialog_warning_single_app
+                    mode = ENTIRE_SCREEN,
+                    spinnerText = R.string.media_projection_permission_dialog_option_entire_screen,
+                    warningText = entireScreenWarningText
                 ),
                 ScreenShareOption(
-                    ENTIRE_SCREEN,
-                    R.string.media_projection_permission_dialog_option_entire_screen,
-                    R.string.media_projection_permission_dialog_warning_entire_screen
+                    mode = SINGLE_APP,
+                    spinnerText = R.string.media_projection_permission_dialog_option_single_app,
+                    warningText = singleAppWarningText
                 )
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index ce4e0ec..b8684ee 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -33,13 +33,16 @@
 import com.android.systemui.animation.DialogLaunchAnimator;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.policy.CallbackController;
 
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -55,8 +58,10 @@
     private boolean mIsRecording;
     private PendingIntent mStopIntent;
     private CountDownTimer mCountDownTimer = null;
-    private BroadcastDispatcher mBroadcastDispatcher;
-    private UserContextProvider mUserContextProvider;
+    private final Executor mMainExecutor;
+    private final BroadcastDispatcher mBroadcastDispatcher;
+    private final UserContextProvider mUserContextProvider;
+    private final UserTracker mUserTracker;
 
     protected static final String INTENT_UPDATE_STATE =
             "com.android.systemui.screenrecord.UPDATE_STATE";
@@ -66,12 +71,13 @@
             new CopyOnWriteArrayList<>();
 
     @VisibleForTesting
-    protected final BroadcastReceiver mUserChangeReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            stopRecording();
-        }
-    };
+    final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    stopRecording();
+                }
+            };
 
     @VisibleForTesting
     protected final BroadcastReceiver mStateChangeReceiver = new BroadcastReceiver() {
@@ -92,10 +98,14 @@
      * Create a new RecordingController
      */
     @Inject
-    public RecordingController(BroadcastDispatcher broadcastDispatcher,
-            UserContextProvider userContextProvider) {
+    public RecordingController(@Main Executor mainExecutor,
+            BroadcastDispatcher broadcastDispatcher,
+            UserContextProvider userContextProvider,
+            UserTracker userTracker) {
+        mMainExecutor = mainExecutor;
         mBroadcastDispatcher = broadcastDispatcher;
         mUserContextProvider = userContextProvider;
+        mUserTracker = userTracker;
     }
 
     /** Create a dialog to show screen recording options to the user. */
@@ -139,9 +149,7 @@
                 }
                 try {
                     startIntent.send();
-                    IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
-                    mBroadcastDispatcher.registerReceiver(mUserChangeReceiver, userFilter, null,
-                            UserHandle.ALL);
+                    mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
 
                     IntentFilter stateFilter = new IntentFilter(INTENT_UPDATE_STATE);
                     mBroadcastDispatcher.registerReceiver(mStateChangeReceiver, stateFilter, null,
@@ -211,7 +219,7 @@
     public synchronized void updateState(boolean isRecording) {
         if (!isRecording && mIsRecording) {
             // Unregister receivers if we have stopped recording
-            mBroadcastDispatcher.unregisterReceiver(mUserChangeReceiver);
+            mUserTracker.removeCallback(mUserChangedCallback);
             mBroadcastDispatcher.unregisterReceiver(mStateChangeReceiver);
         }
         mIsRecording = isRecording;
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
index 19bb15a..44b18ec 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordPermissionDialog.kt
@@ -46,7 +46,14 @@
     private val dialogLaunchAnimator: DialogLaunchAnimator,
     private val userContextProvider: UserContextProvider,
     private val onStartRecordingClicked: Runnable?
-) : BaseScreenSharePermissionDialog(context, createOptionList(), null) {
+) :
+    BaseScreenSharePermissionDialog(
+        context,
+        createOptionList(),
+        null,
+        R.drawable.ic_screenrecord,
+        R.color.screenrecord_icon_color
+    ) {
     private lateinit var tapsSwitch: Switch
     private lateinit var tapsView: View
     private lateinit var audioSwitch: Switch
@@ -169,14 +176,14 @@
         private fun createOptionList(): List<ScreenShareOption> {
             return listOf(
                 ScreenShareOption(
-                    SINGLE_APP,
-                    R.string.screenrecord_option_single_app,
-                    R.string.screenrecord_warning_single_app
-                ),
-                ScreenShareOption(
                     ENTIRE_SCREEN,
                     R.string.screenrecord_option_entire_screen,
                     R.string.screenrecord_warning_entire_screen
+                ),
+                ScreenShareOption(
+                    SINGLE_APP,
+                    R.string.screenrecord_option_single_app,
+                    R.string.screenrecord_warning_single_app
                 )
             )
         }
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
index 914d29a..3d39fd8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenShareOption.kt
@@ -20,11 +20,11 @@
 import kotlin.annotation.Retention
 
 @Retention(AnnotationRetention.SOURCE)
-@IntDef(SINGLE_APP, ENTIRE_SCREEN)
+@IntDef(ENTIRE_SCREEN, SINGLE_APP)
 annotation class ScreenShareMode
 
-const val SINGLE_APP = 0
-const val ENTIRE_SCREEN = 1
+const val ENTIRE_SCREEN = 0
+const val SINGLE_APP = 1
 
 class ScreenShareOption(
     @ScreenShareMode val mode: Int,
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index 8609e4a..a6447a5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -84,6 +84,8 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.widget.Toast;
+import android.window.OnBackInvokedCallback;
+import android.window.OnBackInvokedDispatcher;
 import android.window.WindowContext;
 
 import androidx.concurrent.futures.CallbackToFutureAdapter;
@@ -279,6 +281,13 @@
     private final ActionIntentExecutor mActionExecutor;
     private final UserManager mUserManager;
 
+    private final OnBackInvokedCallback mOnBackInvokedCallback = () -> {
+        if (DEBUG_INPUT) {
+            Log.d(TAG, "Predictive Back callback dispatched");
+        }
+        respondToBack();
+    };
+
     private ScreenshotView mScreenshotView;
     private Bitmap mScreenBitmap;
     private SaveImageInBackgroundTask mSaveInBgTask;
@@ -465,6 +474,10 @@
         }
     }
 
+    private void respondToBack() {
+        dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
+    }
+
     /**
      * Update resources on configuration change. Reinflate for theme/color changes.
      */
@@ -476,6 +489,26 @@
         // Inflate the screenshot layout
         mScreenshotView = (ScreenshotView)
                 LayoutInflater.from(mContext).inflate(R.layout.screenshot, null);
+        mScreenshotView.addOnAttachStateChangeListener(
+                new View.OnAttachStateChangeListener() {
+                    @Override
+                    public void onViewAttachedToWindow(@NonNull View v) {
+                        if (DEBUG_INPUT) {
+                            Log.d(TAG, "Registering Predictive Back callback");
+                        }
+                        mScreenshotView.findOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+                                OnBackInvokedDispatcher.PRIORITY_DEFAULT, mOnBackInvokedCallback);
+                    }
+
+                    @Override
+                    public void onViewDetachedFromWindow(@NonNull View v) {
+                        if (DEBUG_INPUT) {
+                            Log.d(TAG, "Unregistering Predictive Back callback");
+                        }
+                        mScreenshotView.findOnBackInvokedDispatcher()
+                                .unregisterOnBackInvokedCallback(mOnBackInvokedCallback);
+                    }
+                });
         mScreenshotView.init(mUiEventLogger, new ScreenshotView.ScreenshotViewCallback() {
             @Override
             public void onUserInteraction() {
@@ -503,7 +536,7 @@
                 if (DEBUG_INPUT) {
                     Log.d(TAG, "onKeyEvent: KeyEvent.KEYCODE_BACK");
                 }
-                dismissScreenshot(SCREENSHOT_DISMISSED_OTHER);
+                respondToBack();
                 return true;
             }
             return false;
@@ -546,9 +579,16 @@
 
     private void saveScreenshot(Bitmap screenshot, Consumer<Uri> finisher, Rect screenRect,
             Insets screenInsets, ComponentName topComponent, boolean showFlash, UserHandle owner) {
-        withWindowAttached(() ->
+        withWindowAttached(() -> {
+            if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+                    && mUserManager.isManagedProfile(owner.getIdentifier())) {
+                mScreenshotView.announceForAccessibility(mContext.getResources().getString(
+                        R.string.screenshot_saving_work_profile_title));
+            } else {
                 mScreenshotView.announceForAccessibility(
-                        mContext.getResources().getString(R.string.screenshot_saving_title)));
+                        mContext.getResources().getString(R.string.screenshot_saving_title));
+            }
+        });
 
         mScreenshotView.reset();
 
@@ -972,13 +1012,8 @@
 
         if (imageData.uri != null) {
             if (!imageData.owner.equals(Process.myUserHandle())) {
-                // TODO: Handle non-primary user ownership (e.g. Work Profile)
-                // This image is owned by another user. Special treatment will be
-                // required in the UI (badging) as well as sending intents which can
-                // correctly forward those URIs on to be read (actions).
-
-                Log.d(TAG, "*** Screenshot saved to a non-primary user ("
-                        + imageData.owner + ") as " + imageData.uri);
+                Log.d(TAG, "Screenshot saved to user " + imageData.owner + " as "
+                        + imageData.uri);
             }
             mScreenshotHandler.post(() -> {
                 if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
@@ -1059,6 +1094,11 @@
                     R.string.screenshot_failed_to_save_text);
         } else {
             mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED, 0, mPackageName);
+            if (mFlags.isEnabled(SCREENSHOT_WORK_PROFILE_POLICY)
+                    && mUserManager.isManagedProfile(imageData.owner.getIdentifier())) {
+                mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED_TO_WORK_PROFILE, 0,
+                        mPackageName);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index 7641554..fae938d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -825,12 +825,23 @@
             }
         });
         if (mQuickShareChip != null) {
-            mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
-                    () -> {
-                        mUiEventLogger.log(
-                                ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED, 0, mPackageName);
-                        animateDismissal();
-                    });
+            if (imageData.quickShareAction != null) {
+                mQuickShareChip.setPendingIntent(imageData.quickShareAction.actionIntent,
+                        () -> {
+                            mUiEventLogger.log(
+                                    ScreenshotEvent.SCREENSHOT_SMART_ACTION_TAPPED, 0,
+                                    mPackageName);
+                            animateDismissal();
+                        });
+            } else {
+                // hide chip and unset pending interaction if necessary, since we don't actually
+                // have a useable quick share intent
+                Log.wtf(TAG, "Showed quick share chip, but quick share intent was null");
+                if (mPendingInteraction == PendingInteraction.QUICK_SHARE) {
+                    mPendingInteraction = null;
+                }
+                mQuickShareChip.setVisibility(GONE);
+            }
         }
 
         if (mPendingInteraction != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
index d450afa..bfba6df 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserFileManagerImpl.kt
@@ -35,12 +35,14 @@
 import javax.inject.Inject
 
 /**
- * Implementation for retrieving file paths for file storage of system and secondary users.
- * Files lie in {File Directory}/UserFileManager/{User Id} for secondary user.
- * For system user, we use the conventional {File Directory}
+ * Implementation for retrieving file paths for file storage of system and secondary users. Files
+ * lie in {File Directory}/UserFileManager/{User Id} for secondary user. For system user, we use the
+ * conventional {File Directory}
  */
 @SysUISingleton
-class UserFileManagerImpl @Inject constructor(
+class UserFileManagerImpl
+@Inject
+constructor(
     // Context of system process and system user.
     private val context: Context,
     val userManager: UserManager,
@@ -49,80 +51,114 @@
 ) : UserFileManager, CoreStartable {
     companion object {
         private const val FILES = "files"
-        @VisibleForTesting internal const val SHARED_PREFS = "shared_prefs"
+        const val SHARED_PREFS = "shared_prefs"
         @VisibleForTesting internal const val ID = "UserFileManager"
-    }
 
-   private val broadcastReceiver = object : BroadcastReceiver() {
+        /** Returns `true` if the given user ID is that for the primary/system user. */
+        fun isPrimaryUser(userId: Int): Boolean {
+            return UserHandle(userId).isSystem
+        }
+
         /**
-         * Listen to Intent.ACTION_USER_REMOVED to clear user data.
+         * Returns a [File] pointing to the correct path for a secondary user ID.
+         *
+         * Note that there is no check for the type of user. This should only be called for
+         * secondary users, never for the system user. For that, make sure to call [isPrimaryUser].
+         *
+         * Note also that there is no guarantee that the parent directory structure for the file
+         * exists on disk. For that, call [ensureParentDirExists].
+         *
+         * @param context The context
+         * @param fileName The name of the file
+         * @param directoryName The name of the directory that would contain the file
+         * @param userId The ID of the user to build a file path for
          */
-        override fun onReceive(context: Context, intent: Intent) {
-            if (intent.action == Intent.ACTION_USER_REMOVED) {
-                clearDeletedUserData()
+        fun secondaryUserFile(
+            context: Context,
+            fileName: String,
+            directoryName: String,
+            userId: Int,
+        ): File {
+            return Environment.buildPath(
+                context.filesDir,
+                ID,
+                userId.toString(),
+                directoryName,
+                fileName,
+            )
+        }
+
+        /**
+         * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs
+         * recursively.
+         */
+        fun ensureParentDirExists(file: File) {
+            val parent = file.parentFile
+            if (!parent.exists()) {
+                if (!parent.mkdirs()) {
+                    Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}")
+                }
             }
         }
     }
 
-    /**
-     * Poll for user-specific directories to delete upon start up.
-     */
+    private val broadcastReceiver =
+        object : BroadcastReceiver() {
+            /** Listen to Intent.ACTION_USER_REMOVED to clear user data. */
+            override fun onReceive(context: Context, intent: Intent) {
+                if (intent.action == Intent.ACTION_USER_REMOVED) {
+                    clearDeletedUserData()
+                }
+            }
+        }
+
+    /** Poll for user-specific directories to delete upon start up. */
     override fun start() {
         clearDeletedUserData()
-        val filter = IntentFilter().apply {
-            addAction(Intent.ACTION_USER_REMOVED)
-        }
+        val filter = IntentFilter().apply { addAction(Intent.ACTION_USER_REMOVED) }
         broadcastDispatcher.registerReceiver(broadcastReceiver, filter, backgroundExecutor)
     }
 
-    /**
-     * Return the file based on current user.
-     */
+    /** Return the file based on current user. */
     override fun getFile(fileName: String, userId: Int): File {
-        return if (UserHandle(userId).isSystem) {
-            Environment.buildPath(
-                context.filesDir,
-                fileName
-            )
+        return if (isPrimaryUser(userId)) {
+            Environment.buildPath(context.filesDir, fileName)
         } else {
-            val secondaryFile = Environment.buildPath(
-                context.filesDir,
-                ID,
-                userId.toString(),
-                FILES,
-                fileName
-            )
+            val secondaryFile =
+                secondaryUserFile(
+                    context = context,
+                    userId = userId,
+                    directoryName = FILES,
+                    fileName = fileName,
+                )
             ensureParentDirExists(secondaryFile)
             secondaryFile
         }
     }
 
-    /**
-     * Get shared preferences from user.
-     */
+    /** Get shared preferences from user. */
     override fun getSharedPreferences(
         fileName: String,
         @Context.PreferencesMode mode: Int,
         userId: Int
     ): SharedPreferences {
-        if (UserHandle(userId).isSystem) {
+        if (isPrimaryUser(userId)) {
             return context.getSharedPreferences(fileName, mode)
         }
-        val secondaryUserDir = Environment.buildPath(
-            context.filesDir,
-            ID,
-            userId.toString(),
-            SHARED_PREFS,
-            fileName
-        )
+
+        val secondaryUserDir =
+            secondaryUserFile(
+                context = context,
+                fileName = fileName,
+                directoryName = SHARED_PREFS,
+                userId = userId,
+            )
 
         ensureParentDirExists(secondaryUserDir)
         return context.getSharedPreferences(secondaryUserDir, mode)
     }
 
-    /**
-     * Remove dirs for deleted users.
-     */
+    /** Remove dirs for deleted users. */
     @VisibleForTesting
     internal fun clearDeletedUserData() {
         backgroundExecutor.execute {
@@ -133,10 +169,11 @@
 
             dirsToDelete.forEach { dir ->
                 try {
-                    val dirToDelete = Environment.buildPath(
-                        file,
-                        dir,
-                    )
+                    val dirToDelete =
+                        Environment.buildPath(
+                            file,
+                            dir,
+                        )
                     dirToDelete.deleteRecursively()
                 } catch (e: Exception) {
                     Log.e(ID, "Deletion failed.", e)
@@ -144,18 +181,4 @@
             }
         }
     }
-
-    /**
-     * Checks to see if parent dir of the file exists. If it does not, we create the parent dirs
-     * recursively.
-     */
-    @VisibleForTesting
-    internal fun ensureParentDirExists(file: File) {
-        val parent = file.parentFile
-        if (!parent.exists()) {
-            if (!parent.mkdirs()) {
-                Log.e(ID, "Could not create parent directory for file: ${file.absolutePath}")
-            }
-        }
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
index 31e4464..b511b54 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/LargeScreenShadeHeaderController.kt
@@ -19,6 +19,7 @@
 import android.annotation.IdRes
 import android.app.StatusBarManager
 import android.content.res.Configuration
+import android.os.Bundle
 import android.os.Trace
 import android.os.Trace.TRACE_TAG_APP
 import android.util.Pair
@@ -34,6 +35,8 @@
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -43,7 +46,6 @@
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.HEADER_TRANSITION_ID
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT
-import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
@@ -53,6 +55,7 @@
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent.CentralSurfacesScope
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_BATTERY_CONTROLLER
 import com.android.systemui.statusbar.phone.dagger.StatusBarViewModule.LARGE_SCREEN_SHADE_HEADER
+import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.VariableDateView
 import com.android.systemui.statusbar.policy.VariableDateViewController
@@ -69,11 +72,9 @@
  * expansion of the headers in small screen portrait.
  *
  * [header] will be a [MotionLayout] if [Flags.COMBINED_QS_HEADERS] is enabled. In this case, the
- * [MotionLayout] has 2 transitions:
+ * [MotionLayout] has one transitions:
  * * [HEADER_TRANSITION_ID]: [QQS_HEADER_CONSTRAINT] <-> [QS_HEADER_CONSTRAINT] for portrait
  *   handheld device configuration.
- * * [LARGE_SCREEN_HEADER_TRANSITION_ID]: [LARGE_SCREEN_HEADER_CONSTRAINT] (to itself) for all
- *   other configurations
  */
 @CentralSurfacesScope
 class LargeScreenShadeHeaderController @Inject constructor(
@@ -89,7 +90,8 @@
     private val dumpManager: DumpManager,
     private val featureFlags: FeatureFlags,
     private val qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder,
-    private val combinedShadeHeadersConstraintManager: CombinedShadeHeadersConstraintManager
+    private val combinedShadeHeadersConstraintManager: CombinedShadeHeadersConstraintManager,
+    private val demoModeController: DemoModeController
 ) : ViewController<View>(header), Dumpable {
 
     companion object {
@@ -99,8 +101,6 @@
         @VisibleForTesting
         internal val HEADER_TRANSITION_ID = R.id.header_transition
         @VisibleForTesting
-        internal val LARGE_SCREEN_HEADER_TRANSITION_ID = R.id.large_screen_header_transition
-        @VisibleForTesting
         internal val QQS_HEADER_CONSTRAINT = R.id.qqs_header_constraint
         @VisibleForTesting
         internal val QS_HEADER_CONSTRAINT = R.id.qs_header_constraint
@@ -115,10 +115,6 @@
         }
     }
 
-    init {
-        loadConstraints()
-    }
-
     private val combinedHeaders = featureFlags.isEnabled(Flags.COMBINED_QS_HEADERS)
 
     private lateinit var iconManager: StatusBarIconController.TintedIconManager
@@ -126,7 +122,7 @@
     private lateinit var qsCarrierGroupController: QSCarrierGroupController
 
     private val batteryIcon: BatteryMeterView = header.findViewById(R.id.batteryRemainingIcon)
-    private val clock: TextView = header.findViewById(R.id.clock)
+    private val clock: Clock = header.findViewById(R.id.clock)
     private val date: TextView = header.findViewById(R.id.date)
     private val iconContainer: StatusIconContainer = header.findViewById(R.id.statusIcons)
     private val qsCarrierGroup: QSCarrierGroup = header.findViewById(R.id.carrier_group)
@@ -212,6 +208,14 @@
         view.onApplyWindowInsets(insets)
     }
 
+    private val demoModeReceiver = object : DemoMode {
+        override fun demoCommands() = listOf(DemoMode.COMMAND_CLOCK)
+        override fun dispatchDemoCommand(command: String, args: Bundle) =
+            clock.dispatchDemoCommand(command, args)
+        override fun onDemoModeStarted() = clock.onDemoModeStarted()
+        override fun onDemoModeFinished() = clock.onDemoModeFinished()
+    }
+
     private val chipVisibilityListener: ChipVisibilityListener = object : ChipVisibilityListener {
         override fun onChipVisibilityRefreshed(visible: Boolean) {
             if (header is MotionLayout) {
@@ -300,6 +304,7 @@
 
         dumpManager.registerDumpable(this)
         configurationController.addCallback(configurationControllerListener)
+        demoModeController.addCallback(demoModeReceiver)
 
         updateVisibility()
         updateTransition()
@@ -309,6 +314,7 @@
         privacyIconsController.chipVisibilityListener = null
         dumpManager.unregisterDumpable(this::class.java.simpleName)
         configurationController.removeCallback(configurationControllerListener)
+        demoModeController.removeCallback(demoModeReceiver)
     }
 
     fun disable(state1: Int, state2: Int, animate: Boolean) {
@@ -330,11 +336,11 @@
         if (header is MotionLayout) {
             // Use resources.getXml instead of passing the resource id due to bug b/205018300
             header.getConstraintSet(QQS_HEADER_CONSTRAINT)
-                .load(context, resources.getXml(R.xml.qqs_header))
+                    .load(context, resources.getXml(R.xml.qqs_header))
             header.getConstraintSet(QS_HEADER_CONSTRAINT)
-                .load(context, resources.getXml(R.xml.qs_header))
+                    .load(context, resources.getXml(R.xml.qs_header))
             header.getConstraintSet(LARGE_SCREEN_HEADER_CONSTRAINT)
-                .load(context, resources.getXml(R.xml.large_screen_shade_header))
+                    .load(context, resources.getXml(R.xml.large_screen_shade_header))
         }
     }
 
@@ -423,7 +429,6 @@
         }
         header as MotionLayout
         if (largeScreenActive) {
-            header.setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
             header.getConstraintSet(LARGE_SCREEN_HEADER_CONSTRAINT).applyTo(header)
         } else {
             header.setTransition(HEADER_TRANSITION_ID)
@@ -521,4 +526,7 @@
             updateConstraints(LARGE_SCREEN_HEADER_CONSTRAINT, updates.largeScreenConstraintsChanges)
         }
     }
+
+    @VisibleForTesting
+    internal fun simulateViewDetached() = this.onViewDetached()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 7fbdeca..3b40aeb 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -200,7 +200,6 @@
 import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger;
 import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent;
-import com.android.systemui.statusbar.phone.PhoneStatusBarView;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -393,6 +392,9 @@
     private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
     private int mQsTrackingPointer;
     private VelocityTracker mQsVelocityTracker;
+    private TrackingStartedListener mTrackingStartedListener;
+    private OpenCloseListener mOpenCloseListener;
+    private GestureRecorder mGestureRecorder;
     private boolean mQsTracking;
     /** Whether the ongoing gesture might both trigger the expansion in both the view and QS. */
     private boolean mConflictingQsExpansionGesture;
@@ -913,6 +915,7 @@
         mQsFrameTranslateController = qsFrameTranslateController;
         updateUserSwitcherFlags();
         mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
+        mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
         onFinishInflate();
         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
                 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -930,7 +933,6 @@
                         unlockAnimationStarted(playingCannedAnimation, isWakeAndUnlock, startDelay);
                     }
                 });
-        mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
         dumpManager.registerDumpable(this);
     }
 
@@ -1106,6 +1108,7 @@
                 mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
         mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
         mKeyguardStatusViewController.init();
+        updateClockAppearance();
 
         if (mKeyguardUserSwitcherController != null) {
             // Try to close the switcher so that callbacks are triggered if necessary.
@@ -1362,6 +1365,14 @@
         mKeyguardIndicationController.setIndicationArea(mKeyguardBottomArea);
     }
 
+    void setOpenCloseListener(OpenCloseListener openCloseListener) {
+        mOpenCloseListener = openCloseListener;
+    }
+
+    void setTrackingStartedListener(TrackingStartedListener trackingStartedListener) {
+        mTrackingStartedListener = trackingStartedListener;
+    }
+
     private void updateGestureExclusionRect() {
         Rect exclusionRect = calculateGestureExclusionRect();
         mView.setSystemGestureExclusionRects(exclusionRect.isEmpty() ? Collections.emptyList()
@@ -1936,9 +1947,9 @@
     }
 
     private void fling(float vel) {
-        GestureRecorder gr = mCentralSurfaces.getGestureRecorder();
-        if (gr != null) {
-            gr.tag("fling " + ((vel > 0) ? "open" : "closed"), "notifications,v=" + vel);
+        if (mGestureRecorder != null) {
+            mGestureRecorder.tag("fling " + ((vel > 0) ? "open" : "closed"),
+                    "notifications,v=" + vel);
         }
         fling(vel, true, 1.0f /* collapseSpeedUpFactor */, false);
     }
@@ -2072,6 +2083,14 @@
                 mInitialTouchX = x;
                 initVelocityTracker();
                 trackMovement(event);
+                float qsExpansionFraction = computeQsExpansionFraction();
+                // Intercept the touch if QS is between fully collapsed and fully expanded state
+                if (!mSplitShadeEnabled
+                        && qsExpansionFraction > 0.0 && qsExpansionFraction < 1.0) {
+                    mShadeLog.logMotionEvent(event,
+                            "onQsIntercept: down action, QS partially expanded/collapsed");
+                    return true;
+                }
                 if (mKeyguardShowing
                         && shouldQuickSettingsIntercept(mInitialTouchX, mInitialTouchY, 0)) {
                     // Dragging down on the lockscreen statusbar should prohibit other interactions
@@ -2324,6 +2343,14 @@
         if (!isFullyCollapsed()) {
             handleQsDown(event);
         }
+        // defer touches on QQS to shade while shade is collapsing. Added margin for error
+        // as sometimes the qsExpansionFraction can be a tiny value instead of 0 when in QQS.
+        if (!mSplitShadeEnabled
+                && computeQsExpansionFraction() <= 0.01 && getExpandedFraction() < 1.0) {
+            mShadeLog.logMotionEvent(event,
+                    "handleQsTouch: QQS touched while shade collapsing");
+            mQsTracking = false;
+        }
         if (!mQsExpandImmediate && mQsTracking) {
             onQsTouch(event);
             if (!mConflictingQsExpansionGesture && !mSplitShadeEnabled) {
@@ -2564,7 +2591,6 @@
         // Reset scroll position and apply that position to the expanded height.
         float height = mQsExpansionHeight;
         setQsExpansionHeight(height);
-        updateExpandedHeightToMaxHeight();
         mNotificationStackScrollLayoutController.checkSnoozeLeavebehind();
 
         // When expanding QS, let's authenticate the user if possible,
@@ -3711,7 +3737,7 @@
         mFalsingCollector.onTrackingStarted(!mKeyguardStateController.canDismissLockScreen());
         endClosing();
         mTracking = true;
-        mCentralSurfaces.onTrackingStarted();
+        mTrackingStartedListener.onTrackingStarted();
         notifyExpandingStarted();
         updatePanelExpansionAndVisibility();
         mScrimController.onTrackingStarted();
@@ -3945,7 +3971,7 @@
     }
 
     private void onClosingFinished() {
-        mCentralSurfaces.onClosingFinished();
+        mOpenCloseListener.onClosingFinished();
         setClosingWithAlphaFadeout(false);
         mMediaHierarchyManager.closeGuts();
     }
@@ -4504,11 +4530,13 @@
      */
     public void initDependencies(
             CentralSurfaces centralSurfaces,
+            GestureRecorder recorder,
             Runnable hideExpandedRunnable,
             NotificationShelfController notificationShelfController) {
         // TODO(b/254859580): this can be injected.
         mCentralSurfaces = centralSurfaces;
 
+        mGestureRecorder = recorder;
         mHideExpandedRunnable = hideExpandedRunnable;
         mNotificationStackScrollLayoutController.setShelfController(notificationShelfController);
         mNotificationShelfController = notificationShelfController;
@@ -4559,55 +4587,6 @@
         return new TouchHandler();
     }
 
-    private final PhoneStatusBarView.TouchEventHandler mStatusBarViewTouchEventHandler =
-            new PhoneStatusBarView.TouchEventHandler() {
-                @Override
-                public void onInterceptTouchEvent(MotionEvent event) {
-                    mCentralSurfaces.onTouchEvent(event);
-                }
-
-                @Override
-                public boolean handleTouchEvent(MotionEvent event) {
-                    mCentralSurfaces.onTouchEvent(event);
-
-                    // TODO(b/202981994): Move the touch debugging in this method to a central
-                    //  location. (Right now, it's split between CentralSurfaces and here.)
-
-                    // If panels aren't enabled, ignore the gesture and don't pass it down to the
-                    // panel view.
-                    if (!mCommandQueue.panelsEnabled()) {
-                        if (event.getAction() == MotionEvent.ACTION_DOWN) {
-                            Log.v(
-                                    TAG,
-                                    String.format(
-                                            "onTouchForwardedFromStatusBar: "
-                                                    + "panel disabled, ignoring touch at (%d,%d)",
-                                            (int) event.getX(),
-                                            (int) event.getY()
-                                    )
-                            );
-                        }
-                        return false;
-                    }
-
-                    // If the view that would receive the touch is disabled, just have status bar
-                    // eat the gesture.
-                    if (event.getAction() == MotionEvent.ACTION_DOWN && !mView.isEnabled()) {
-                        Log.v(TAG,
-                                String.format(
-                                        "onTouchForwardedFromStatusBar: "
-                                                + "panel view disabled, eating touch at (%d,%d)",
-                                        (int) event.getX(),
-                                        (int) event.getY()
-                                )
-                        );
-                        return true;
-                    }
-
-                    return mView.dispatchTouchEvent(event);
-                }
-            };
-
     public NotificationStackScrollLayoutController getNotificationStackScrollLayoutController() {
         return mNotificationStackScrollLayoutController;
     }
@@ -5210,6 +5189,11 @@
     }
 
     /** */
+    public boolean sendTouchEventToView(MotionEvent event) {
+        return mView.dispatchTouchEvent(event);
+    }
+
+    /** */
     public void requestLayoutOnView() {
         mView.requestLayout();
     }
@@ -5219,6 +5203,11 @@
         ViewGroupFadeHelper.reset(mView);
     }
 
+    /** */
+    public boolean isViewEnabled() {
+        return mView.isEnabled();
+    }
+
     private void beginJankMonitoring() {
         if (mInteractionJankMonitor == null) {
             return;
@@ -5757,7 +5746,7 @@
             if (mSplitShadeEnabled && !isOnKeyguard()) {
                 setQsExpandImmediate(true);
             }
-            mCentralSurfaces.makeExpandedVisible(false);
+            mOpenCloseListener.onOpenStarted();
         }
         if (state == STATE_CLOSED) {
             setQsExpandImmediate(false);
@@ -5768,11 +5757,6 @@
         mCurrentPanelState = state;
     }
 
-    /** Returns the handler that the status bar should forward touches to. */
-    public PhoneStatusBarView.TouchEventHandler getStatusBarTouchEventHandler() {
-        return mStatusBarViewTouchEventHandler;
-    }
-
     @VisibleForTesting
     StatusBarStateController getStatusBarStateController() {
         return mStatusBarStateController;
@@ -6240,5 +6224,18 @@
             return super.performAccessibilityAction(host, action, args);
         }
     }
+
+    /** Listens for when touch tracking begins. */
+    interface TrackingStartedListener {
+        void onTrackingStarted();
+    }
+
+    /** Listens for when shade begins opening of finishes closing. */
+    interface OpenCloseListener {
+        /** Called when the shade finishes closing. */
+        void onClosingFinished();
+        /** Called when the shade starts opening. */
+        void onOpenStarted();
+    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
index aa610bd..a41a15d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeController.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.shade;
 
+import android.view.MotionEvent;
+
+import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -29,31 +32,32 @@
  */
 public interface ShadeController {
 
-    /**
-     * Make our window larger and the panel expanded
-     */
-    void instantExpandNotificationsPanel();
+    /** Make our window larger and the shade expanded */
+    void instantExpandShade();
 
-    /** See {@link #animateCollapsePanels(int, boolean)}. */
-    void animateCollapsePanels();
+    /** Collapse the shade instantly with no animation. */
+    void instantCollapseShade();
 
-    /** See {@link #animateCollapsePanels(int, boolean)}. */
-    void animateCollapsePanels(int flags);
+    /** See {@link #animateCollapsePanels(int, boolean, boolean, float)}. */
+    void animateCollapseShade();
+
+    /** See {@link #animateCollapsePanels(int, boolean, boolean, float)}. */
+    void animateCollapseShade(int flags);
+
+    /** See {@link #animateCollapsePanels(int, boolean, boolean, float)}. */
+    void animateCollapseShadeForced();
+
+    /** See {@link #animateCollapsePanels(int, boolean, boolean, float)}. */
+    void animateCollapseShadeDelayed();
 
     /**
      * Collapse the shade animated, showing the bouncer when on {@link StatusBarState#KEYGUARD} or
-     * dismissing {@link CentralSurfaces} when on {@link StatusBarState#SHADE}.
+     * dismissing status bar when on {@link StatusBarState#SHADE}.
      */
-    void animateCollapsePanels(int flags, boolean force);
-
-    /** See {@link #animateCollapsePanels(int, boolean)}. */
-    void animateCollapsePanels(int flags, boolean force, boolean delayed);
-
-    /** See {@link #animateCollapsePanels(int, boolean)}. */
     void animateCollapsePanels(int flags, boolean force, boolean delayed, float speedUpFactor);
 
     /**
-     * If the notifications panel is not fully expanded, collapse it animated.
+     * If the shade is not fully expanded, collapse it animated.
      *
      * @return Seems to always return false
      */
@@ -77,9 +81,7 @@
      */
     void addPostCollapseAction(Runnable action);
 
-    /**
-     * Run all of the runnables added by {@link #addPostCollapseAction}.
-     */
+    /** Run all of the runnables added by {@link #addPostCollapseAction}. */
     void runPostCollapseRunnables();
 
     /**
@@ -87,13 +89,51 @@
      *
      * @return true if the shade was open, else false
      */
-    boolean collapsePanel();
+    boolean collapseShade();
 
     /**
-     * If animate is true, does the same as {@link #collapsePanel()}. Otherwise, instantly collapse
-     * the panel. Post collapse runnables will be executed
+     * If animate is true, does the same as {@link #collapseShade()}. Otherwise, instantly collapse
+     * the shade. Post collapse runnables will be executed
      *
      * @param animate true to animate the collapse, false for instantaneous collapse
      */
-    void collapsePanel(boolean animate);
+    void collapseShade(boolean animate);
+
+    /** Makes shade expanded but not visible. */
+    void makeExpandedInvisible();
+
+    /** Makes shade expanded and visible. */
+    void makeExpandedVisible(boolean force);
+
+    /** Returns whether the shade is expanded and visible. */
+    boolean isExpandedVisible();
+
+    /** Handle status bar touch event. */
+    void onStatusBarTouch(MotionEvent event);
+
+    /** Called when the shade finishes collapsing. */
+    void onClosingFinished();
+
+    /** Sets the listener for when the visibility of the shade changes. */
+    void setVisibilityListener(ShadeVisibilityListener listener);
+
+    /** */
+    void setNotificationPresenter(NotificationPresenter presenter);
+
+    /** */
+    void setNotificationShadeWindowViewController(
+            NotificationShadeWindowViewController notificationShadeWindowViewController);
+
+    /** */
+    void setNotificationPanelViewController(
+            NotificationPanelViewController notificationPanelViewController);
+
+    /** Listens for shade visibility changes. */
+    interface ShadeVisibilityListener {
+        /** Called when the visibility of the shade changes. */
+        void visibilityChanged(boolean visible);
+
+        /** Called when shade expanded and visible state changed. */
+        void expandedVisibleChanged(boolean expandedVisible);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
index d783293..638e748 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerImpl.java
@@ -16,9 +16,12 @@
 
 package com.android.systemui.shade;
 
+import android.content.ComponentCallbacks2;
 import android.util.Log;
+import android.view.MotionEvent;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.dagger.SysUISingleton;
@@ -27,11 +30,12 @@
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.phone.CentralSurfaces;
+import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.statusbar.window.StatusBarWindowController;
 
 import java.util.ArrayList;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -39,68 +43,81 @@
 
 /** An implementation of {@link ShadeController}. */
 @SysUISingleton
-public class ShadeControllerImpl implements ShadeController {
+public final class ShadeControllerImpl implements ShadeController {
 
     private static final String TAG = "ShadeControllerImpl";
     private static final boolean SPEW = false;
 
-    private final CommandQueue mCommandQueue;
-    private final StatusBarStateController mStatusBarStateController;
-    protected final NotificationShadeWindowController mNotificationShadeWindowController;
-    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
     private final int mDisplayId;
-    protected final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy;
+
+    private final CommandQueue mCommandQueue;
+    private final KeyguardStateController mKeyguardStateController;
+    private final NotificationShadeWindowController mNotificationShadeWindowController;
+    private final StatusBarStateController mStatusBarStateController;
+    private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+    private final StatusBarWindowController mStatusBarWindowController;
+
     private final Lazy<AssistManager> mAssistManagerLazy;
+    private final Lazy<NotificationGutsManager> mGutsManager;
 
     private final ArrayList<Runnable> mPostCollapseRunnables = new ArrayList<>();
 
+    private boolean mExpandedVisible;
+
+    private NotificationPanelViewController mNotificationPanelViewController;
+    private NotificationPresenter mPresenter;
+    private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
+    private ShadeVisibilityListener mShadeVisibilityListener;
+
     @Inject
     public ShadeControllerImpl(
             CommandQueue commandQueue,
+            KeyguardStateController keyguardStateController,
             StatusBarStateController statusBarStateController,
-            NotificationShadeWindowController notificationShadeWindowController,
             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
+            StatusBarWindowController statusBarWindowController,
+            NotificationShadeWindowController notificationShadeWindowController,
             WindowManager windowManager,
-            Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy,
-            Lazy<AssistManager> assistManagerLazy
+            Lazy<AssistManager> assistManagerLazy,
+            Lazy<NotificationGutsManager> gutsManager
     ) {
         mCommandQueue = commandQueue;
         mStatusBarStateController = statusBarStateController;
+        mStatusBarWindowController = statusBarWindowController;
+        mGutsManager = gutsManager;
         mNotificationShadeWindowController = notificationShadeWindowController;
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mDisplayId = windowManager.getDefaultDisplay().getDisplayId();
-        // TODO: Remove circular reference to CentralSurfaces when possible.
-        mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
+        mKeyguardStateController = keyguardStateController;
         mAssistManagerLazy = assistManagerLazy;
     }
 
     @Override
-    public void instantExpandNotificationsPanel() {
+    public void instantExpandShade() {
         // Make our window larger and the panel expanded.
-        getCentralSurfaces().makeExpandedVisible(true /* force */);
-        getNotificationPanelViewController().expand(false /* animate */);
+        makeExpandedVisible(true /* force */);
+        mNotificationPanelViewController.expand(false /* animate */);
         mCommandQueue.recomputeDisableFlags(mDisplayId, false /* animate */);
     }
 
     @Override
-    public void animateCollapsePanels() {
-        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+    public void animateCollapseShade() {
+        animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE);
     }
 
     @Override
-    public void animateCollapsePanels(int flags) {
-        animateCollapsePanels(flags, false /* force */, false /* delayed */,
-                1.0f /* speedUpFactor */);
+    public void animateCollapseShade(int flags) {
+        animateCollapsePanels(flags, false, false, 1.0f);
     }
 
     @Override
-    public void animateCollapsePanels(int flags, boolean force) {
-        animateCollapsePanels(flags, force, false /* delayed */, 1.0f /* speedUpFactor */);
+    public void animateCollapseShadeForced() {
+        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true, false, 1.0f);
     }
 
     @Override
-    public void animateCollapsePanels(int flags, boolean force, boolean delayed) {
-        animateCollapsePanels(flags, force, delayed, 1.0f /* speedUpFactor */);
+    public void animateCollapseShadeDelayed() {
+        animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true, true, 1.0f);
     }
 
     @Override
@@ -111,34 +128,26 @@
             return;
         }
         if (SPEW) {
-            Log.d(TAG, "animateCollapse():"
-                    + " mExpandedVisible=" + getCentralSurfaces().isExpandedVisible()
-                    + " flags=" + flags);
+            Log.d(TAG,
+                    "animateCollapse(): mExpandedVisible=" + mExpandedVisible + "flags=" + flags);
         }
-
-        // TODO(b/62444020): remove when this bug is fixed
-        Log.v(TAG, "NotificationShadeWindow: " + getNotificationShadeWindowView()
-                + " canPanelBeCollapsed(): "
-                + getNotificationPanelViewController().canPanelBeCollapsed());
         if (getNotificationShadeWindowView() != null
-                && getNotificationPanelViewController().canPanelBeCollapsed()
+                && mNotificationPanelViewController.canPanelBeCollapsed()
                 && (flags & CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL) == 0) {
             // release focus immediately to kick off focus change transition
             mNotificationShadeWindowController.setNotificationShadeFocusable(false);
 
-            getCentralSurfaces().getNotificationShadeWindowViewController().cancelExpandHelper();
-            getNotificationPanelViewController()
-                    .collapsePanel(true /* animate */, delayed, speedUpFactor);
+            mNotificationShadeWindowViewController.cancelExpandHelper();
+            mNotificationPanelViewController.collapsePanel(true, delayed, speedUpFactor);
         }
     }
 
-
     @Override
     public boolean closeShadeIfOpen() {
-        if (!getNotificationPanelViewController().isFullyCollapsed()) {
+        if (!mNotificationPanelViewController.isFullyCollapsed()) {
             mCommandQueue.animateCollapsePanels(
                     CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
-            getCentralSurfaces().visibilityChanged(false);
+            notifyVisibilityChanged(false);
             mAssistManagerLazy.get().hideAssist();
         }
         return false;
@@ -146,21 +155,19 @@
 
     @Override
     public boolean isShadeOpen() {
-        NotificationPanelViewController controller =
-                getNotificationPanelViewController();
-        return controller.isExpanding() || controller.isFullyExpanded();
+        return mNotificationPanelViewController.isExpanding()
+                || mNotificationPanelViewController.isFullyExpanded();
     }
 
     @Override
     public void postOnShadeExpanded(Runnable executable) {
-        getNotificationPanelViewController().addOnGlobalLayoutListener(
+        mNotificationPanelViewController.addOnGlobalLayoutListener(
                 new ViewTreeObserver.OnGlobalLayoutListener() {
                     @Override
                     public void onGlobalLayout() {
-                        if (getCentralSurfaces().getNotificationShadeWindowView()
-                                .isVisibleToUser()) {
-                            getNotificationPanelViewController().removeOnGlobalLayoutListener(this);
-                            getNotificationPanelViewController().postToView(executable);
+                        if (getNotificationShadeWindowView().isVisibleToUser()) {
+                            mNotificationPanelViewController.removeOnGlobalLayoutListener(this);
+                            mNotificationPanelViewController.postToView(executable);
                         }
                     }
                 });
@@ -183,12 +190,11 @@
     }
 
     @Override
-    public boolean collapsePanel() {
-        if (!getNotificationPanelViewController().isFullyCollapsed()) {
+    public boolean collapseShade() {
+        if (!mNotificationPanelViewController.isFullyCollapsed()) {
             // close the shade if it was open
-            animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
-                    true /* force */, true /* delayed */);
-            getCentralSurfaces().visibilityChanged(false);
+            animateCollapseShadeDelayed();
+            notifyVisibilityChanged(false);
 
             return true;
         } else {
@@ -197,33 +203,154 @@
     }
 
     @Override
-    public void collapsePanel(boolean animate) {
+    public void collapseShade(boolean animate) {
         if (animate) {
-            boolean willCollapse = collapsePanel();
+            boolean willCollapse = collapseShade();
             if (!willCollapse) {
                 runPostCollapseRunnables();
             }
-        } else if (!getPresenter().isPresenterFullyCollapsed()) {
-            getCentralSurfaces().instantCollapseNotificationPanel();
-            getCentralSurfaces().visibilityChanged(false);
+        } else if (!mPresenter.isPresenterFullyCollapsed()) {
+            instantCollapseShade();
+            notifyVisibilityChanged(false);
         } else {
             runPostCollapseRunnables();
         }
     }
 
-    private CentralSurfaces getCentralSurfaces() {
-        return mCentralSurfacesOptionalLazy.get().get();
+    @Override
+    public void onStatusBarTouch(MotionEvent event) {
+        if (event.getAction() == MotionEvent.ACTION_UP) {
+            if (mExpandedVisible) {
+                animateCollapseShade();
+            }
+        }
     }
 
-    private NotificationPresenter getPresenter() {
-        return getCentralSurfaces().getPresenter();
+    @Override
+    public void onClosingFinished() {
+        runPostCollapseRunnables();
+        if (!mPresenter.isPresenterFullyCollapsed()) {
+            // if we set it not to be focusable when collapsing, we have to undo it when we aborted
+            // the closing
+            mNotificationShadeWindowController.setNotificationShadeFocusable(true);
+        }
     }
 
-    protected NotificationShadeWindowView getNotificationShadeWindowView() {
-        return getCentralSurfaces().getNotificationShadeWindowView();
+    @Override
+    public void instantCollapseShade() {
+        mNotificationPanelViewController.instantCollapse();
+        runPostCollapseRunnables();
     }
 
-    private NotificationPanelViewController getNotificationPanelViewController() {
-        return getCentralSurfaces().getNotificationPanelViewController();
+    @Override
+    public void makeExpandedVisible(boolean force) {
+        if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
+        if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
+            return;
+        }
+
+        mExpandedVisible = true;
+
+        // Expand the window to encompass the full screen in anticipation of the drag.
+        // It's only possible to do atomically because the status bar is at the top of the screen!
+        mNotificationShadeWindowController.setPanelVisible(true);
+
+        notifyVisibilityChanged(true);
+        mCommandQueue.recomputeDisableFlags(mDisplayId, !force /* animate */);
+        notifyExpandedVisibleChanged(true);
+    }
+
+    @Override
+    public void makeExpandedInvisible() {
+        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible);
+
+        if (!mExpandedVisible || getNotificationShadeWindowView() == null) {
+            return;
+        }
+
+        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
+        mNotificationPanelViewController.collapsePanel(false, false, 1.0f);
+
+        mNotificationPanelViewController.closeQs();
+
+        mExpandedVisible = false;
+        notifyVisibilityChanged(false);
+
+        // Update the visibility of notification shade and status bar window.
+        mNotificationShadeWindowController.setPanelVisible(false);
+        mStatusBarWindowController.setForceStatusBarVisible(false);
+
+        // Close any guts that might be visible
+        mGutsManager.get().closeAndSaveGuts(
+                true /* removeLeavebehind */,
+                true /* force */,
+                true /* removeControls */,
+                -1 /* x */,
+                -1 /* y */,
+                true /* resetMenu */);
+
+        runPostCollapseRunnables();
+        notifyExpandedVisibleChanged(false);
+        mCommandQueue.recomputeDisableFlags(
+                mDisplayId,
+                mNotificationPanelViewController.hideStatusBarIconsWhenExpanded() /* animate */);
+
+        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
+        // the bouncer appear animation.
+        if (!mKeyguardStateController.isShowing()) {
+            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
+        }
+    }
+
+    @Override
+    public boolean isExpandedVisible() {
+        return mExpandedVisible;
+    }
+
+    @Override
+    public void setVisibilityListener(ShadeVisibilityListener listener) {
+        mShadeVisibilityListener = listener;
+    }
+
+    private void notifyVisibilityChanged(boolean visible) {
+        mShadeVisibilityListener.visibilityChanged(visible);
+    }
+
+    private void notifyExpandedVisibleChanged(boolean expandedVisible) {
+        mShadeVisibilityListener.expandedVisibleChanged(expandedVisible);
+    }
+
+    @Override
+    public void setNotificationPresenter(NotificationPresenter presenter) {
+        mPresenter = presenter;
+    }
+
+    @Override
+    public void setNotificationShadeWindowViewController(
+            NotificationShadeWindowViewController controller) {
+        mNotificationShadeWindowViewController = controller;
+    }
+
+    private NotificationShadeWindowView getNotificationShadeWindowView() {
+        return mNotificationShadeWindowViewController.getView();
+    }
+
+    @Override
+    public void setNotificationPanelViewController(
+            NotificationPanelViewController notificationPanelViewController) {
+        mNotificationPanelViewController = notificationPanelViewController;
+        mNotificationPanelViewController.setTrackingStartedListener(this::runPostCollapseRunnables);
+        mNotificationPanelViewController.setOpenCloseListener(
+                new NotificationPanelViewController.OpenCloseListener() {
+                    @Override
+                    public void onClosingFinished() {
+                        ShadeControllerImpl.this.onClosingFinished();
+                    }
+
+                    @Override
+                    public void onOpenStarted() {
+                        makeExpandedVisible(false);
+                    }
+                });
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 3d161d9..24c66eb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -17,9 +17,12 @@
 package com.android.systemui.statusbar;
 
 import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.annotation.StringRes;
 import android.content.Context;
+import android.content.res.ColorStateList;
 import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.widget.TextView;
@@ -33,16 +36,30 @@
 public class EmptyShadeView extends StackScrollerDecorView {
 
     private TextView mEmptyText;
+    private TextView mEmptyFooterText;
+
     private @StringRes int mText = R.string.empty_shade_text;
 
+    private @DrawableRes int mFooterIcon = R.drawable.ic_friction_lock_closed;
+    private @StringRes int mFooterText = R.string.unlock_to_see_notif_text;
+    private @Visibility int mFooterVisibility = View.GONE;
+    private int mSize;
+
     public EmptyShadeView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mSize = getResources().getDimensionPixelSize(
+                R.dimen.notifications_unseen_footer_icon_size);
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
+        mSize = getResources().getDimensionPixelSize(
+                R.dimen.notifications_unseen_footer_icon_size);
         mEmptyText.setText(mText);
+        mEmptyFooterText.setVisibility(mFooterVisibility);
+        setFooterText(mFooterText);
+        setFooterIcon(mFooterIcon);
     }
 
     @Override
@@ -52,11 +69,13 @@
 
     @Override
     protected View findSecondaryView() {
-        return null;
+        return findViewById(R.id.no_notifications_footer);
     }
 
     public void setTextColor(@ColorInt int color) {
         mEmptyText.setTextColor(color);
+        mEmptyFooterText.setTextColor(color);
+        mEmptyFooterText.setCompoundDrawableTintList(ColorStateList.valueOf(color));
     }
 
     public void setText(@StringRes int text) {
@@ -64,14 +83,53 @@
         mEmptyText.setText(mText);
     }
 
+    public void setFooterVisibility(@Visibility int visibility) {
+        mFooterVisibility = visibility;
+        setSecondaryVisible(visibility == View.VISIBLE, false);
+    }
+
+    public void setFooterText(@StringRes int text) {
+        mFooterText = text;
+        if (text != 0) {
+            mEmptyFooterText.setText(mFooterText);
+        } else {
+            mEmptyFooterText.setText(null);
+        }
+    }
+
+    public void setFooterIcon(@DrawableRes int icon) {
+        mFooterIcon = icon;
+        Drawable drawable;
+        if (icon == 0) {
+            drawable = null;
+        } else {
+            drawable = getResources().getDrawable(icon);
+            drawable.setBounds(0, 0, mSize, mSize);
+        }
+        mEmptyFooterText.setCompoundDrawablesRelative(drawable, null, null, null);
+    }
+
+    @StringRes
     public int getTextResource() {
         return mText;
     }
 
+    @StringRes
+    public int getFooterTextResource() {
+        return mFooterText;
+    }
+
+    @DrawableRes
+    public int getFooterIconResource() {
+        return mFooterIcon;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         mEmptyText = (TextView) findContentView();
+        mEmptyFooterText = (TextView) findSecondaryView();
+        mEmptyFooterText.setCompoundDrawableTintList(mEmptyFooterText.getTextColors());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index bc456d5..2334a4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -15,6 +15,7 @@
 import android.util.AttributeSet
 import android.util.MathUtils.lerp
 import android.view.View
+import android.view.animation.PathInterpolator
 import com.android.systemui.animation.Interpolators
 import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
 import com.android.systemui.util.getColorWithAlpha
@@ -88,10 +89,12 @@
 
 class LinearLightRevealEffect(private val isVertical: Boolean) : LightRevealEffect {
 
-    private val INTERPOLATOR = Interpolators.FAST_OUT_SLOW_IN_REVERSE
+    // Interpolator that reveals >80% of the content at 0.5 progress, makes revealing faster
+    private val interpolator = PathInterpolator(/* controlX1= */ 0.4f, /* controlY1= */ 0f,
+            /* controlX2= */ 0.2f, /* controlY2= */ 1f)
 
     override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
-        val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
+        val interpolatedAmount = interpolator.getInterpolation(amount)
 
         scrim.interpolatedRevealAmount = interpolatedAmount
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index cdefae6..f4cd985 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -30,6 +30,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.os.Handler;
+import android.os.HandlerExecutor;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -37,6 +38,7 @@
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 
+import androidx.annotation.NonNull;
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.statusbar.NotificationVisibility;
@@ -127,21 +129,6 @@
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             switch (action) {
-                case Intent.ACTION_USER_SWITCHED:
-                    mCurrentUserId = intent.getIntExtra(
-                            Intent.EXTRA_USER_HANDLE, UserHandle.USER_ALL);
-                    updateCurrentProfilesCache();
-
-                    Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
-
-                    updateLockscreenNotificationSetting();
-                    updatePublicMode();
-                    mPresenter.onUserSwitched(mCurrentUserId);
-
-                    for (UserChangedListener listener : mListeners) {
-                        listener.onUserChanged(mCurrentUserId);
-                    }
-                    break;
                 case Intent.ACTION_USER_REMOVED:
                     int removedUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                     if (removedUserId != -1) {
@@ -181,6 +168,25 @@
         }
     };
 
+    protected final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    mCurrentUserId = newUser;
+                    updateCurrentProfilesCache();
+
+                    Log.v(TAG, "userId " + mCurrentUserId + " is in the house");
+
+                    updateLockscreenNotificationSetting();
+                    updatePublicMode();
+                    mPresenter.onUserSwitched(mCurrentUserId);
+
+                    for (UserChangedListener listener : mListeners) {
+                        listener.onUserChanged(mCurrentUserId);
+                    }
+                }
+            };
+
     protected final Context mContext;
     private final Handler mMainHandler;
     protected final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
@@ -284,7 +290,6 @@
                 null /* handler */, UserHandle.ALL);
 
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_UNLOCKED);
@@ -298,6 +303,8 @@
         mContext.registerReceiver(mBaseBroadcastReceiver, internalFilter, PERMISSION_SELF, null,
                 Context.RECEIVER_EXPORTED_UNAUDITED);
 
+        mUserTracker.addCallback(mUserChangedCallback, new HandlerExecutor(mMainHandler));
+
         mCurrentUserId = mUserTracker.getUserId(); // in case we reg'd receiver too late
         updateCurrentProfilesCache();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
index 99ff06a..37d83f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java
@@ -68,7 +68,7 @@
 import com.android.systemui.R;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
-import com.android.systemui.dagger.qualifiers.Background;
+import com.android.systemui.dagger.qualifiers.LongRunning;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.demomode.DemoMode;
 import com.android.systemui.demomode.DemoModeController;
@@ -223,12 +223,15 @@
 
     /**
      * Construct this controller object and register for updates.
+     *
+     * {@code @LongRunning} looper and bgExecutor instead {@code @Background} ones are used to
+     * address the b/246456655. This can be reverted after b/240663726 is fixed.
      */
     @Inject
     public NetworkControllerImpl(
             Context context,
-            @Background Looper bgLooper,
-            @Background Executor bgExecutor,
+            @LongRunning Looper bgLooper,
+            @LongRunning Executor bgExecutor,
             SubscriptionManager subscriptionManager,
             CallbackHandler callbackHandler,
             DeviceProvisionedController deviceProvisionedController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index 143c697..bd5b8f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -94,7 +94,11 @@
     private val views: Sequence<View>
         get() = if (!this::tl.isInitialized) sequenceOf() else sequenceOf(tl, tr, br, bl)
 
-    private var showingListener: ShowingListener? = null
+    var showingListener: ShowingListener? = null
+        set(value) {
+            field = value
+        }
+        get() = field
 
     init {
         contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener {
@@ -147,10 +151,6 @@
         return uiExecutor
     }
 
-    fun setShowingListener(l: ShowingListener?) {
-        showingListener = l
-    }
-
     @UiThread
     fun setNewRotation(rot: Int) {
         dlog("updateRotation: $rot")
@@ -219,7 +219,7 @@
 
     // Update the gravity and margins of the privacy views
     @UiThread
-    private fun updateRotations(rotation: Int, paddingTop: Int) {
+    open fun updateRotations(rotation: Int, paddingTop: Int) {
         // To keep a view in the corner, its gravity is always the description of its current corner
         // Therefore, just figure out which view is in which corner. This turns out to be something
         // like (myCorner - rot) mod 4, where topLeft = 0, topRight = 1, etc. and portrait = 0, and
@@ -250,7 +250,7 @@
     }
 
     @UiThread
-    private fun setCornerSizes(state: ViewState) {
+    open fun setCornerSizes(state: ViewState) {
         // StatusBarContentInsetsProvider can tell us the location of the privacy indicator dot
         // in every rotation. The only thing we need to check is rtl
         val rtl = state.layoutRtl
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
index 7eb8906..39daa13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotifPipelineFlags.kt
@@ -44,4 +44,8 @@
     val shouldFilterUnseenNotifsOnKeyguard: Boolean by lazy {
         featureFlags.isEnabled(Flags.FILTER_UNSEEN_NOTIFS_ON_KEYGUARD)
     }
+
+    val isNoHunForOldWhenEnabled: Boolean by lazy {
+        featureFlags.isEnabled(Flags.NO_HUN_FOR_OLD_WHEN)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index d97b712..3e2dd05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -38,6 +38,7 @@
 import javax.inject.Inject
 import kotlin.math.min
 
+
 @SysUISingleton
 class NotificationWakeUpCoordinator @Inject constructor(
     dumpManager: DumpManager,
@@ -45,7 +46,8 @@
     private val statusBarStateController: StatusBarStateController,
     private val bypassController: KeyguardBypassController,
     private val dozeParameters: DozeParameters,
-    private val screenOffAnimationController: ScreenOffAnimationController
+    private val screenOffAnimationController: ScreenOffAnimationController,
+    private val logger: NotificationWakeUpCoordinatorLogger,
 ) : OnHeadsUpChangedListener, StatusBarStateController.StateListener, ShadeExpansionListener,
     Dumpable {
 
@@ -242,6 +244,7 @@
     }
 
     override fun onDozeAmountChanged(linear: Float, eased: Float) {
+        logger.logOnDozeAmountChanged(linear, eased)
         if (overrideDozeAmountIfAnimatingScreenOff(linear)) {
             return
         }
@@ -273,6 +276,7 @@
     }
 
     override fun onStateChanged(newState: Int) {
+        logger.logOnStateChanged(newState)
         if (state == StatusBarState.SHADE && newState == StatusBarState.SHADE) {
             // The SHADE -> SHADE transition is only possible as part of cancelling the screen-off
             // animation (e.g. by fingerprint unlock).  This is done because the system is in an
@@ -320,8 +324,12 @@
     private fun overrideDozeAmountIfBypass(): Boolean {
         if (bypassController.bypassEnabled) {
             if (statusBarStateController.state == StatusBarState.KEYGUARD) {
+                logger.logSetDozeAmount("1.0", "1.0",
+                        "Override: bypass (keyguard)", StatusBarState.KEYGUARD)
                 setDozeAmount(1f, 1f, source = "Override: bypass (keyguard)")
             } else {
+                logger.logSetDozeAmount("0.0", "0.0",
+                        "Override: bypass (shade)", statusBarStateController.state)
                 setDozeAmount(0f, 0f, source = "Override: bypass (shade)")
             }
             return true
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
new file mode 100644
index 0000000..b40ce25
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinatorLogger.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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.log.dagger.NotificationLog
+import com.android.systemui.plugins.log.LogBuffer
+import com.android.systemui.plugins.log.LogLevel.DEBUG
+import javax.inject.Inject
+
+class NotificationWakeUpCoordinatorLogger
+@Inject
+constructor(@NotificationLog private val buffer: LogBuffer) {
+    fun logSetDozeAmount(linear: String, eased: String, source: String, state: Int) {
+        buffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = linear
+                str2 = eased
+                str3 = source
+                int1 = state
+            },
+            { "setDozeAmount: linear: $str1, eased: $str2, source: $str3, state: $int1" }
+        )
+    }
+
+    fun logOnDozeAmountChanged(linear: Float, eased: Float) {
+        buffer.log(
+            TAG,
+            DEBUG,
+            {
+                double1 = linear.toDouble()
+                str2 = eased.toString()
+            },
+            { "onDozeAmountChanged($double1, $str2)" }
+        )
+    }
+
+    fun logOnStateChanged(newState: Int) {
+        buffer.log(TAG, DEBUG, { int1 = newState }, { "onStateChanged($int1)" })
+    }
+}
+
+private const val TAG = "NotificationWakeUpCoordinator"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
index 6e5fceb..9da94ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinator.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import javax.inject.Inject
 import kotlin.time.Duration.Companion.seconds
@@ -49,6 +50,7 @@
     private val notifPipelineFlags: NotifPipelineFlags,
     @Application private val scope: CoroutineScope,
     private val sectionHeaderVisibilityProvider: SectionHeaderVisibilityProvider,
+    private val seenNotifsProvider: SeenNotificationsProviderImpl,
     private val statusBarStateController: StatusBarStateController,
 ) : Coordinator {
 
@@ -105,6 +107,9 @@
     @VisibleForTesting
     internal val unseenNotifFilter =
         object : NotifFilter("$TAG-unseen") {
+
+            var hasFilteredAnyNotifs = false
+
             override fun shouldFilterOut(entry: NotificationEntry, now: Long): Boolean =
                 when {
                     // Don't apply filter if the keyguard isn't currently showing
@@ -115,7 +120,12 @@
                     //  - summary will be pruned if necessary, depending on if children are filtered
                     entry.parent?.summary == entry -> false
                     else -> true
-                }
+                }.also { hasFiltered -> hasFilteredAnyNotifs = hasFilteredAnyNotifs || hasFiltered }
+
+            override fun onCleanup() {
+                seenNotifsProvider.hasFilteredOutSeenNotifications = hasFilteredAnyNotifs
+                hasFilteredAnyNotifs = false
+            }
         }
 
     private val notifFilter: NotifFilter =
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
index 966ab4c..afdadeb 100644
--- 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
@@ -51,7 +51,9 @@
      */
     public final void invalidateList(@Nullable String reason) {
         if (mListener != null) {
-            Trace.beginSection("Pluggable<" + mName + ">.invalidateList");
+            if (Trace.isEnabled()) {
+                Trace.traceBegin(Trace.TRACE_TAG_APP, "Pluggable<" + mName + ">.invalidateList");
+            }
             mListener.onPluggableInvalidated((This) this, reason);
             Trace.endSection();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
new file mode 100644
index 0000000..cff47e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/SeenNotificationsProvider.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.provider
+
+import com.android.systemui.dagger.SysUISingleton
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+
+/** Keeps track of whether "seen" notification content has been filtered out of the shade. */
+interface SeenNotificationsProvider {
+    /** Are any already-seen notifications currently filtered out of the shade? */
+    val hasFilteredOutSeenNotifications: Boolean
+}
+
+@Module
+interface SeenNotificationsProviderModule {
+    @Binds
+    fun bindSeenNotificationsProvider(
+        impl: SeenNotificationsProviderImpl
+    ): SeenNotificationsProvider
+}
+
+@SysUISingleton
+class SeenNotificationsProviderImpl @Inject constructor() : SeenNotificationsProvider {
+    override var hasFilteredOutSeenNotifications: Boolean = false
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index a7b7a23..808638a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -52,6 +52,7 @@
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationVisibilityProviderImpl;
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderModule;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManagerImpl;
@@ -96,6 +97,7 @@
 @Module(includes = {
         CoordinatorsModule.class,
         KeyguardNotificationVisibilityProviderModule.class,
+        SeenNotificationsProviderModule.class,
         ShadeEventsModule.class,
         NotifPipelineChoreographerModule.class,
         NotificationSectionHeadersModule.class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
index e6dbcee..7513aa7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProvider.kt
@@ -2,22 +2,20 @@
 
 import android.app.Notification
 import android.app.Notification.VISIBILITY_SECRET
-import android.content.BroadcastReceiver
 import android.content.Context
-import android.content.Intent
-import android.content.IntentFilter
 import android.database.ContentObserver
 import android.net.Uri
 import android.os.Handler
+import android.os.HandlerExecutor
 import android.os.UserHandle
 import android.provider.Settings
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.CoreStartable
-import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.NotificationLockscreenUserManager
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.SysuiStatusBarStateController
@@ -78,7 +76,7 @@
     private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
     private val highPriorityProvider: HighPriorityProvider,
     private val statusBarStateController: SysuiStatusBarStateController,
-    private val broadcastDispatcher: BroadcastDispatcher,
+    private val userTracker: UserTracker,
     private val secureSettings: SecureSettings,
     private val globalSettings: GlobalSettings
 ) : CoreStartable, KeyguardNotificationVisibilityProvider {
@@ -87,6 +85,15 @@
     private val onStateChangedListeners = ListenerSet<Consumer<String>>()
     private var hideSilentNotificationsOnLockscreen: Boolean = false
 
+    private val userTrackerCallback = object : UserTracker.Callback {
+        override fun onUserChanged(newUser: Int, userContext: Context) {
+            if (isLockedOrLocking) {
+                // maybe public mode changed
+                notifyStateChanged("onUserSwitched")
+            }
+        }
+    }
+
     override fun start() {
         readShowSilentNotificationSetting()
         keyguardStateController.addCallback(object : KeyguardStateController.Callback {
@@ -143,14 +150,7 @@
                 notifyStateChanged("onStatusBarUpcomingStateChanged")
             }
         })
-        broadcastDispatcher.registerReceiver(object : BroadcastReceiver() {
-            override fun onReceive(context: Context, intent: Intent) {
-                if (isLockedOrLocking) {
-                    // maybe public mode changed
-                    notifyStateChanged(intent.action!!)
-                }
-            }
-        }, IntentFilter(Intent.ACTION_USER_SWITCHED))
+        userTracker.addCallback(userTrackerCallback, HandlerExecutor(handler))
     }
 
     override fun addOnStateChangedListener(listener: Consumer<String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
index 073b6b0..13b3aca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptLogger.kt
@@ -106,6 +106,36 @@
         })
     }
 
+    fun logNoHeadsUpOldWhen(
+        entry: NotificationEntry,
+        notifWhen: Long,
+        notifAge: Long
+    ) {
+        buffer.log(TAG, DEBUG, {
+            str1 = entry.logKey
+            long1 = notifWhen
+            long2 = notifAge
+        }, {
+            "No heads up: old when $long1 (age=$long2 ms): $str1"
+        })
+    }
+
+    fun logMaybeHeadsUpDespiteOldWhen(
+        entry: NotificationEntry,
+        notifWhen: Long,
+        notifAge: Long,
+        reason: String
+    ) {
+        buffer.log(TAG, DEBUG, {
+            str1 = entry.logKey
+            str2 = reason
+            long1 = notifWhen
+            long2 = notifAge
+        }, {
+            "Maybe heads up: old when $long1 (age=$long2 ms) but $str2: $str1"
+        })
+    }
+
     fun logNoHeadsUpSuppressedBy(
         entry: NotificationEntry,
         suppressor: NotificationInterruptSuppressor
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
index c4f5a3a..ec5bd68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java
@@ -20,6 +20,7 @@
 import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD;
 import static com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProviderImpl.NotificationInterruptEvent.FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR;
 
+import android.app.Notification;
 import android.app.NotificationManager;
 import android.content.ContentResolver;
 import android.database.ContentObserver;
@@ -82,7 +83,10 @@
         FSI_SUPPRESSED_SUPPRESSIVE_GROUP_ALERT_BEHAVIOR(1235),
 
         @UiEvent(doc = "FSI suppressed for requiring neither HUN nor keyguard")
-        FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236);
+        FSI_SUPPRESSED_NO_HUN_OR_KEYGUARD(1236),
+
+        @UiEvent(doc = "HUN suppressed for old when")
+        HUN_SUPPRESSED_OLD_WHEN(1237);
 
         private final int mId;
 
@@ -346,6 +350,10 @@
             return false;
         }
 
+        if (shouldSuppressHeadsUpWhenAwakeForOldWhen(entry, log)) {
+            return false;
+        }
+
         for (int i = 0; i < mSuppressors.size(); i++) {
             if (mSuppressors.get(i).suppressAwakeHeadsUp(entry)) {
                 if (log) mLogger.logNoHeadsUpSuppressedBy(entry, mSuppressors.get(i));
@@ -470,4 +478,51 @@
     private boolean isSnoozedPackage(StatusBarNotification sbn) {
         return mHeadsUpManager.isSnoozed(sbn.getPackageName());
     }
+
+    private boolean shouldSuppressHeadsUpWhenAwakeForOldWhen(NotificationEntry entry, boolean log) {
+        if (!mFlags.isNoHunForOldWhenEnabled()) {
+            return false;
+        }
+
+        final Notification notification = entry.getSbn().getNotification();
+        if (notification == null) {
+            return false;
+        }
+
+        final long when = notification.when;
+        final long now = System.currentTimeMillis();
+        final long age = now - when;
+
+        if (age < MAX_HUN_WHEN_AGE_MS) {
+            return false;
+        }
+
+        if (when <= 0) {
+            // Some notifications (including many system notifications) are posted with the "when"
+            // field set to 0. Nothing in the Javadocs for Notification mentions a special meaning
+            // for a "when" of 0, but Android didn't even exist at the dawn of the Unix epoch.
+            // Therefore, assume that these notifications effectively don't have a "when" value,
+            // and don't suppress HUNs.
+            if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "when <= 0");
+            return false;
+        }
+
+        if (notification.fullScreenIntent != null) {
+            if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "full-screen intent");
+            return false;
+        }
+
+        if (notification.isForegroundService()) {
+            if (log) mLogger.logMaybeHeadsUpDespiteOldWhen(entry, when, age, "foreground service");
+            return false;
+        }
+
+        if (log) mLogger.logNoHeadsUpOldWhen(entry, when, age);
+        final int uid = entry.getSbn().getUid();
+        final String packageName = entry.getSbn().getPackageName();
+        mUiEventLogger.log(NotificationInterruptEvent.HUN_SUPPRESSED_OLD_WHEN, uid, packageName);
+        return true;
+    }
+
+    public static final long MAX_HUN_WHEN_AGE_MS = 24 * 60 * 60 * 1000;
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 1eccc98..d7d5ac9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -19,6 +19,7 @@
 import static android.app.Notification.Action.SEMANTIC_ACTION_MARK_CONVERSATION_AS_PRIORITY;
 import static android.service.notification.NotificationListenerService.REASON_CANCEL;
 
+import static com.android.systemui.statusbar.notification.collection.NotificationEntry.DismissState.PARENT_DISMISSED;
 import static com.android.systemui.statusbar.notification.row.NotificationContentView.VISIBLE_TYPE_HEADSUP;
 
 import android.animation.Animator;
@@ -1404,6 +1405,11 @@
         mKeepInParentForDismissAnimation = keepInParent;
     }
 
+    /** @return true if the User has dismissed this notif's parent */
+    public boolean isParentDismissed() {
+        return getEntry().getDismissState() == PARENT_DISMISSED;
+    }
+
     @Override
     public boolean isRemoved() {
         return mRemoved;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index f9e9a2d..8a400d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -359,10 +359,15 @@
 
     @Override
     public boolean offerToKeepInParentForAnimation() {
-        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)) {
+        //If the User dismissed the notification's parent, we want to keep it attached until the
+        //dismiss animation is ongoing. Therefore we don't want to remove it in the ShadeViewDiffer.
+        if (mFeatureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION)
+                && mView.isParentDismissed()) {
             mView.setKeepInParentForDismissAnimation(true);
             return true;
         }
+
+        //Otherwise the view system doesn't do the removal, so we rely on the ShadeViewDiffer
         return false;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
index 64f87ca..b56bae1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragController.java
@@ -54,8 +54,6 @@
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
-import java.util.Collections;
-
 import javax.inject.Inject;
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index 0ce9656..f21db0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -154,7 +154,7 @@
         // If the user selected Priority and the previous selection was not priority, show a
         // People Tile add request.
         if (mSelectedAction == ACTION_FAVORITE && getPriority() != mSelectedAction) {
-            mShadeController.animateCollapsePanels();
+            mShadeController.animateCollapseShade();
             mPeopleSpaceWidgetManager.requestPinAppWidget(mShortcutInfo, new Bundle());
         }
         mGutsContainer.closeControls(v, /* save= */ true);
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 073bd4b..7c3e52c 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
@@ -32,10 +32,12 @@
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.annotation.ColorInt;
+import android.annotation.DrawableRes;
 import android.annotation.FloatRange;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Configuration;
@@ -1401,10 +1403,10 @@
             mExpandedHeight = height;
             setIsExpanded(height > 0);
             int minExpansionHeight = getMinExpansionHeight();
-            if (height < minExpansionHeight) {
+            if (height < minExpansionHeight && !mShouldUseSplitNotificationShade) {
                 mClipRect.left = 0;
                 mClipRect.right = getWidth();
-                mClipRect.top = getNotificationsClippingTopBound();
+                mClipRect.top = 0;
                 mClipRect.bottom = (int) height;
                 height = minExpansionHeight;
                 setRequestedClipBounds(mClipRect);
@@ -1466,17 +1468,6 @@
         notifyAppearChangedListeners();
     }
 
-    private int getNotificationsClippingTopBound() {
-        if (isHeadsUpTransition()) {
-            // HUN in split shade can go higher than bottom of NSSL when swiping up so we want
-            // to give it extra clipping margin. Because clipping has rounded corners, we also
-            // need to account for that corner clipping.
-            return -mAmbientState.getStackTopMargin() - mCornerRadius;
-        } else {
-            return 0;
-        }
-    }
-
     private void notifyAppearChangedListeners() {
         float appear;
         float expandAmount;
@@ -4236,7 +4227,7 @@
                 mShadeNeedsToClose = false;
                 postDelayed(
                         () -> {
-                            mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
+                            mShadeController.animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE);
                         },
                         DELAY_BEFORE_SHADE_CLOSE /* delayMillis */);
             }
@@ -4567,7 +4558,7 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    void setEmptyShadeView(EmptyShadeView emptyShadeView) {
+    public void setEmptyShadeView(EmptyShadeView emptyShadeView) {
         int index = -1;
         if (mEmptyShadeView != null) {
             index = indexOfChild(mEmptyShadeView);
@@ -4578,15 +4569,43 @@
     }
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
-    void updateEmptyShadeView(boolean visible, boolean areNotificationsHiddenInShade) {
+    void updateEmptyShadeView(
+            boolean visible, boolean areNotificationsHiddenInShade, boolean areSeenNotifsFiltered) {
         mEmptyShadeView.setVisible(visible, mIsExpanded && mAnimationsEnabled);
 
+        if (areNotificationsHiddenInShade) {
+            updateEmptyShadeView(R.string.dnd_suppressing_shade_text, 0, 0);
+        } else if (areSeenNotifsFiltered) {
+            updateEmptyShadeView(
+                    R.string.no_unseen_notif_text,
+                    R.string.unlock_to_see_notif_text,
+                    R.drawable.ic_friction_lock_closed);
+        } else {
+            updateEmptyShadeView(R.string.empty_shade_text, 0, 0);
+        }
+    }
+
+    private void updateEmptyShadeView(
+            @StringRes int newTextRes,
+            @StringRes int newFooterTextRes,
+            @DrawableRes int newFooterIconRes) {
         int oldTextRes = mEmptyShadeView.getTextResource();
-        int newTextRes = areNotificationsHiddenInShade
-                ? R.string.dnd_suppressing_shade_text : R.string.empty_shade_text;
         if (oldTextRes != newTextRes) {
             mEmptyShadeView.setText(newTextRes);
         }
+        int oldFooterTextRes = mEmptyShadeView.getFooterTextResource();
+        if (oldFooterTextRes != newFooterTextRes) {
+            mEmptyShadeView.setFooterText(newFooterTextRes);
+        }
+        int oldFooterIconRes = mEmptyShadeView.getFooterIconResource();
+        if (oldFooterIconRes != newFooterIconRes) {
+            mEmptyShadeView.setFooterIcon(newFooterIconRes);
+        }
+        if (newFooterIconRes != 0 || newFooterTextRes != 0) {
+            mEmptyShadeView.setFooterVisibility(View.VISIBLE);
+        } else {
+            mEmptyShadeView.setFooterVisibility(View.GONE);
+        }
     }
 
     public boolean isEmptyShadeViewVisible() {
@@ -5139,6 +5158,7 @@
             println(pw, "intrinsicPadding", mIntrinsicPadding);
             println(pw, "topPadding", mTopPadding);
             println(pw, "bottomPadding", mBottomPadding);
+            mNotificationStackSizeCalculator.dump(pw, args);
         });
         pw.println();
         pw.println("Contents:");
@@ -5358,9 +5378,9 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     private void inflateEmptyShadeView() {
+        EmptyShadeView oldView = mEmptyShadeView;
         EmptyShadeView view = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_no_notifications, this, false);
-        view.setText(R.string.empty_shade_text);
         view.setOnClickListener(v -> {
             final boolean showHistory = mController.isHistoryEnabled();
             Intent intent = showHistory
@@ -5369,6 +5389,10 @@
             mCentralSurfaces.startActivity(intent, true, true, Intent.FLAG_ACTIVITY_SINGLE_TOP);
         });
         setEmptyShadeView(view);
+        updateEmptyShadeView(
+                oldView == null ? R.string.empty_shade_text : oldView.getTextResource(),
+                oldView == null ? 0 : oldView.getFooterTextResource(),
+                oldView == null ? 0 : oldView.getFooterIconResource());
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index ad4501a..2d6d0a9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -81,6 +81,7 @@
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
@@ -89,6 +90,7 @@
 import com.android.systemui.statusbar.notification.collection.PipelineDumper;
 import com.android.systemui.statusbar.notification.collection.notifcollection.DismissedByUserStats;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotifStackController;
@@ -174,6 +176,8 @@
     private final StackStateLogger mStackStateLogger;
     private final NotificationStackScrollLogger mLogger;
     private final GroupExpansionManager mGroupExpansionManager;
+    private final NotifPipelineFlags mNotifPipelineFlags;
+    private final SeenNotificationsProvider mSeenNotificationsProvider;
 
     private NotificationStackScrollLayout mView;
     private boolean mFadeNotificationsOnDismiss;
@@ -639,12 +643,14 @@
             GroupExpansionManager groupManager,
             @SilentHeader SectionHeaderController silentHeaderController,
             NotifPipeline notifPipeline,
+            NotifPipelineFlags notifPipelineFlags,
             NotifCollection notifCollection,
             LockscreenShadeTransitionController lockscreenShadeTransitionController,
             ShadeTransitionController shadeTransitionController,
             UiEventLogger uiEventLogger,
             NotificationRemoteInputManager remoteInputManager,
             VisibilityLocationProviderDelegator visibilityLocationProviderDelegator,
+            SeenNotificationsProvider seenNotificationsProvider,
             ShadeController shadeController,
             InteractionJankMonitor jankMonitor,
             StackStateLogger stackLogger,
@@ -683,10 +689,12 @@
         mGroupExpansionManager = groupManager;
         mSilentHeaderController = silentHeaderController;
         mNotifPipeline = notifPipeline;
+        mNotifPipelineFlags = notifPipelineFlags;
         mNotifCollection = notifCollection;
         mUiEventLogger = uiEventLogger;
         mRemoteInputManager = remoteInputManager;
         mVisibilityLocationProviderDelegator = visibilityLocationProviderDelegator;
+        mSeenNotificationsProvider = seenNotificationsProvider;
         mShadeController = shadeController;
         mFeatureFlags = featureFlags;
         mNotificationTargetsHelper = notificationTargetsHelper;
@@ -975,7 +983,7 @@
     }
 
     public boolean isAddOrRemoveAnimationPending() {
-        return mView.isAddOrRemoveAnimationPending();
+        return mView != null && mView.isAddOrRemoveAnimationPending();
     }
 
     public int getVisibleNotificationCount() {
@@ -1132,7 +1140,9 @@
     }
 
     public void setAlpha(float alpha) {
-        mView.setAlpha(alpha);
+        if (mView != null) {
+            mView.setAlpha(alpha);
+        }
     }
 
     public float calculateAppearFraction(float height) {
@@ -1212,7 +1222,11 @@
                 // For more details, see: b/228790482
                 && !isInTransitionToKeyguard();
 
-        mView.updateEmptyShadeView(shouldShow, mZenModeController.areNotificationsHiddenInShade());
+        mView.updateEmptyShadeView(
+                shouldShow,
+                mZenModeController.areNotificationsHiddenInShade(),
+                mNotifPipelineFlags.getShouldFilterUnseenNotifsOnKeyguard()
+                        && mSeenNotificationsProvider.getHasFilteredOutSeenNotifications());
 
         Trace.endSection();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
index ae854e2..25f99c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackSizeCalculator.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.util.Compile
 import com.android.systemui.util.children
+import java.io.PrintWriter
 import javax.inject.Inject
 import kotlin.math.max
 import kotlin.math.min
@@ -53,6 +54,8 @@
     @Main private val resources: Resources
 ) {
 
+    private lateinit var lastComputeHeightLog : String
+
     /**
      * Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow shelf.
      * If there are exactly 1 + mMaxKeyguardNotifications, and they fit in the available space
@@ -114,7 +117,9 @@
         shelfIntrinsicHeight: Float
     ): Int {
         log { "\n" }
-        val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)
+
+        val stackHeightSequence = computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight,
+            /* computeHeight= */ false)
 
         var maxNotifications =
             stackHeightSequence.lastIndexWhile { heightResult ->
@@ -157,18 +162,21 @@
         shelfIntrinsicHeight: Float
     ): Float {
         log { "\n" }
+        lastComputeHeightLog = ""
         val heightPerMaxNotifications =
-            computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight)
+            computeHeightPerNotificationLimit(stack, shelfIntrinsicHeight,
+                    /* computeHeight= */ true)
 
         val (notificationsHeight, shelfHeightWithSpaceBefore) =
             heightPerMaxNotifications.elementAtOrElse(maxNotifications) {
                 heightPerMaxNotifications.last() // Height with all notifications visible.
             }
-        log {
-            "computeHeight(maxNotifications=$maxNotifications," +
+        lastComputeHeightLog += "\ncomputeHeight(maxNotifications=$maxNotifications," +
                 "shelfIntrinsicHeight=$shelfIntrinsicHeight) -> " +
                 "${notificationsHeight + shelfHeightWithSpaceBefore}" +
                 " = ($notificationsHeight + $shelfHeightWithSpaceBefore)"
+        log {
+            lastComputeHeightLog
         }
         return notificationsHeight + shelfHeightWithSpaceBefore
     }
@@ -184,7 +192,8 @@
 
     private fun computeHeightPerNotificationLimit(
         stack: NotificationStackScrollLayout,
-        shelfHeight: Float
+        shelfHeight: Float,
+        computeHeight: Boolean
     ): Sequence<StackHeight> = sequence {
         log { "computeHeightPerNotificationLimit" }
 
@@ -213,9 +222,14 @@
                             currentIndex = firstViewInShelfIndex)
                     spaceBeforeShelf + shelfHeight
                 }
+
+            val currentLog = "computeHeight | i=$i notificationsHeight=$notifications " +
+                "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore"
+            if (computeHeight) {
+                lastComputeHeightLog += "\n" + currentLog
+            }
             log {
-                "i=$i notificationsHeight=$notifications " +
-                    "shelfHeightWithSpaceBefore=$shelfWithSpaceBefore"
+                currentLog
             }
             yield(
                 StackHeight(
@@ -260,6 +274,10 @@
         return size
     }
 
+    fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println("NotificationStackSizeCalculator lastComputeHeightLog = $lastComputeHeightLog")
+    }
+
     private fun ExpandableView.isShowable(onLockscreen: Boolean): Boolean {
         if (visibility == GONE || hasNoContentHeight()) return false
         if (onLockscreen) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 34e62ce..03057a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -496,7 +496,7 @@
                 && mPendingAuthenticated.userId == KeyguardUpdateMonitor.getCurrentUser();
     }
 
-    public int getMode() {
+    public @WakeAndUnlockMode int getMode() {
         return mMode;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index be08183..c7c6441 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -28,7 +28,6 @@
 import android.os.UserHandle;
 import android.service.notification.StatusBarNotification;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.RemoteAnimationAdapter;
 import android.view.View;
 import android.view.ViewGroup;
@@ -51,7 +50,6 @@
 import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.shade.NotificationShadeWindowView;
 import com.android.systemui.shade.NotificationShadeWindowViewController;
-import com.android.systemui.statusbar.GestureRecorder;
 import com.android.systemui.statusbar.LightRevealScrim;
 import com.android.systemui.statusbar.NotificationPresenter;
 
@@ -122,6 +120,7 @@
         ActivityOptions options = getDefaultActivityOptions(animationAdapter);
         options.setLaunchDisplayId(displayId);
         options.setCallerDisplayId(displayId);
+        options.setPendingIntentBackgroundActivityLaunchAllowed(true);
         return options.toBundle();
     }
 
@@ -145,6 +144,7 @@
                 : ActivityOptions.SourceInfo.TYPE_NOTIFICATION, eventTime);
         options.setLaunchDisplayId(displayId);
         options.setCallerDisplayId(displayId);
+        options.setPendingIntentBackgroundActivityLaunchAllowed(true);
         return options.toBundle();
     }
 
@@ -191,8 +191,6 @@
 
     void animateExpandSettingsPanel(@Nullable String subpanel);
 
-    void animateCollapsePanels(int flags, boolean force);
-
     void collapsePanelOnMainThread();
 
     void togglePanel();
@@ -280,17 +278,17 @@
 
     void postAnimateOpenPanels();
 
-    boolean isExpandedVisible();
-
     boolean isPanelExpanded();
 
     void onInputFocusTransfer(boolean start, boolean cancel, float velocity);
 
     void animateCollapseQuickSettings();
 
-    void onTouchEvent(MotionEvent event);
+    /** */
+    boolean getCommandQueuePanelsEnabled();
 
-    GestureRecorder getGestureRecorder();
+    /** */
+    int getStatusBarWindowState();
 
     BiometricUnlockController getBiometricUnlockController();
 
@@ -406,10 +404,6 @@
 
     LightRevealScrim getLightRevealScrim();
 
-    void onTrackingStarted();
-
-    void onClosingFinished();
-
     // TODO: Figure out way to remove these.
     NavigationBarView getNavigationBarView();
 
@@ -493,12 +487,6 @@
 
     void updateNotificationPanelTouchState();
 
-    void makeExpandedVisible(boolean force);
-
-    void instantCollapseNotificationPanel();
-
-    void visibilityChanged(boolean visible);
-
     int getDisplayId();
 
     int getRotation();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
index f3482f4..6b72e96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacks.java
@@ -209,7 +209,7 @@
     public void animateExpandNotificationsPanel() {
         if (CentralSurfaces.SPEW) {
             Log.d(CentralSurfaces.TAG,
-                    "animateExpand: mExpandedVisible=" + mCentralSurfaces.isExpandedVisible());
+                    "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible());
         }
         if (!mCommandQueue.panelsEnabled()) {
             return;
@@ -222,7 +222,7 @@
     public void animateExpandSettingsPanel(@Nullable String subPanel) {
         if (CentralSurfaces.SPEW) {
             Log.d(CentralSurfaces.TAG,
-                    "animateExpand: mExpandedVisible=" + mCentralSurfaces.isExpandedVisible());
+                    "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible());
         }
         if (!mCommandQueue.panelsEnabled()) {
             return;
@@ -276,7 +276,7 @@
 
         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
-                mShadeController.animateCollapsePanels();
+                mShadeController.animateCollapseShade();
             }
         }
 
@@ -293,7 +293,7 @@
         if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
             mCentralSurfaces.updateQsExpansionEnabled();
             if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
-                mShadeController.animateCollapsePanels();
+                mShadeController.animateCollapseShade();
             }
         }
 
@@ -550,7 +550,7 @@
     @Override
     public void togglePanel() {
         if (mCentralSurfaces.isPanelExpanded()) {
-            mShadeController.animateCollapsePanels();
+            mShadeController.animateCollapseShade();
         } else {
             animateExpandNotificationsPanel();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 5efd460..b394535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -58,7 +58,6 @@
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -94,7 +93,6 @@
 import android.view.IRemoteAnimationRunner;
 import android.view.IWindowManager;
 import android.view.KeyEvent;
-import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
@@ -159,6 +157,8 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.binder.LightRevealScrimViewBinder;
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationBarView;
 import com.android.systemui.plugins.DarkIconDispatcher;
@@ -406,12 +406,6 @@
 
     /** */
     @Override
-    public void animateCollapsePanels(int flags, boolean force) {
-        mCommandQueueCallbacks.animateCollapsePanels(flags, force);
-    }
-
-    /** */
-    @Override
     public void togglePanel() {
         mCommandQueueCallbacks.togglePanel();
     }
@@ -481,6 +475,7 @@
     private final OngoingCallController mOngoingCallController;
     private final StatusBarSignalPolicy mStatusBarSignalPolicy;
     private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
+    private final Lazy<LightRevealScrimViewModel> mLightRevealScrimViewModelLazy;
 
     /** Controller for the Shade. */
     @VisibleForTesting
@@ -493,8 +488,6 @@
 
     private View mReportRejectedTouch;
 
-    private boolean mExpandedVisible;
-
     private final NotificationGutsManager mGutsManager;
     private final NotificationLogger mNotificationLogger;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
@@ -749,7 +742,8 @@
             DeviceStateManager deviceStateManager,
             WiredChargingRippleController wiredChargingRippleController,
             IDreamManager dreamManager,
-            Lazy<CameraLauncher> cameraLauncherLazy) {
+            Lazy<CameraLauncher> cameraLauncherLazy,
+            Lazy<LightRevealScrimViewModel> lightRevealScrimViewModelLazy) {
         mContext = context;
         mNotificationsController = notificationsController;
         mFragmentService = fragmentService;
@@ -863,6 +857,8 @@
         deviceStateManager.registerCallback(mMainExecutor,
                 new FoldStateListener(mContext, this::onFoldedStateChanged));
         wiredChargingRippleController.registerCallbacks();
+
+        mLightRevealScrimViewModelLazy = lightRevealScrimViewModelLazy;
     }
 
     @Override
@@ -893,6 +889,8 @@
         updateDisplaySize();
         mStatusBarHideIconsForBouncerManager.setDisplayId(mDisplayId);
 
+        initShadeVisibilityListener();
+
         // start old BaseStatusBar.start().
         mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
         mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
@@ -977,6 +975,11 @@
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy.init();
 
+        // Based on teamfood flag, turn predictive back dispatch on at runtime.
+        if (mFeatureFlags.isEnabled(Flags.WM_ENABLE_PREDICTIVE_BACK_SYSUI)) {
+            mContext.getApplicationInfo().setEnableOnBackInvokedCallback(true);
+        }
+
         mKeyguardStateController.addCallback(new KeyguardStateController.Callback() {
             @Override
             public void onUnlockedChanged() {
@@ -985,6 +988,12 @@
 
             @Override
             public void onKeyguardGoingAwayChanged() {
+                if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+                    // This code path is not used if the KeyguardTransitionRepository is managing
+                    // the lightreveal scrim.
+                    return;
+                }
+
                 // The light reveal scrim should always be fully revealed by the time the keyguard
                 // is done going away. Double check that this is true.
                 if (!mKeyguardStateController.isKeyguardGoingAway()) {
@@ -1078,6 +1087,25 @@
                                 requestTopUi, componentTag))));
     }
 
+    @VisibleForTesting
+    void initShadeVisibilityListener() {
+        mShadeController.setVisibilityListener(new ShadeController.ShadeVisibilityListener() {
+            @Override
+            public void visibilityChanged(boolean visible) {
+                onShadeVisibilityChanged(visible);
+            }
+
+            @Override
+            public void expandedVisibleChanged(boolean expandedVisible) {
+                if (expandedVisible) {
+                    setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
+                } else {
+                    onExpandedInvisible();
+                }
+            }
+        });
+    }
+
     private void onFoldedStateChanged(boolean isFolded, boolean willGoToSleep) {
         Trace.beginSection("CentralSurfaces#onFoldedStateChanged");
         onFoldedStateChangedInternal(isFolded, willGoToSleep);
@@ -1202,6 +1230,12 @@
         mScrimController.attachViews(scrimBehind, notificationsScrim, scrimInFront);
 
         mLightRevealScrim = mNotificationShadeWindowView.findViewById(R.id.light_reveal_scrim);
+
+        if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+            LightRevealScrimViewBinder.bind(
+                    mLightRevealScrim, mLightRevealScrimViewModelLazy.get());
+        }
+
         mLightRevealScrim.setScrimOpaqueChangedListener((opaque) -> {
             Runnable updateOpaqueness = () -> {
                 mNotificationShadeWindowController.setLightRevealScrimOpaque(
@@ -1223,7 +1257,8 @@
 
         mNotificationPanelViewController.initDependencies(
                 this,
-                this::makeExpandedInvisible,
+                mGestureRec,
+                mShadeController::makeExpandedInvisible,
                 mNotificationShelfController);
 
         BackDropView backdrop = mNotificationShadeWindowView.findViewById(R.id.backdrop);
@@ -1426,6 +1461,7 @@
         mRemoteInputManager.addControllerCallback(mNotificationShadeWindowController);
         mStackScrollerController.setNotificationActivityStarter(mNotificationActivityStarter);
         mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
+        mShadeController.setNotificationPresenter(mPresenter);
         mNotificationsController.initialize(
                 this,
                 mPresenter,
@@ -1475,11 +1511,7 @@
         return (v, event) -> {
             mAutoHideController.checkUserAutoHide(event);
             mRemoteInputManager.checkRemoteInputOutside(event);
-            if (event.getAction() == MotionEvent.ACTION_UP) {
-                if (mExpandedVisible) {
-                    mShadeController.animateCollapsePanels();
-                }
-            }
+            mShadeController.onStatusBarTouch(event);
             return mNotificationShadeWindowView.onTouchEvent(event);
         };
     }
@@ -1501,6 +1533,9 @@
         mNotificationShadeWindowViewController.setupExpandedStatusBar();
         mNotificationPanelViewController =
                 mCentralSurfacesComponent.getNotificationPanelViewController();
+        mShadeController.setNotificationPanelViewController(mNotificationPanelViewController);
+        mShadeController.setNotificationShadeWindowViewController(
+                mNotificationShadeWindowViewController);
         mCentralSurfacesComponent.getLockIconViewController().init();
         mStackScrollerController =
                 mCentralSurfacesComponent.getNotificationStackScrollLayoutController();
@@ -1820,9 +1855,9 @@
     public void onLaunchAnimationCancelled(boolean isLaunchForActivity) {
         if (mPresenter.isPresenterFullyCollapsed() && !mPresenter.isCollapsing()
                 && isLaunchForActivity) {
-            onClosingFinished();
+            mShadeController.onClosingFinished();
         } else {
-            mShadeController.collapsePanel(true /* animate */);
+            mShadeController.collapseShade(true /* animate */);
         }
     }
 
@@ -1830,10 +1865,10 @@
     @Override
     public void onLaunchAnimationEnd(boolean launchIsFullScreen) {
         if (!mPresenter.isCollapsing()) {
-            onClosingFinished();
+            mShadeController.onClosingFinished();
         }
         if (launchIsFullScreen) {
-            instantCollapseNotificationPanel();
+            mShadeController.instantCollapseShade();
         }
     }
 
@@ -1923,33 +1958,13 @@
     }
 
     @Override
-    public void makeExpandedVisible(boolean force) {
-        if (SPEW) Log.d(TAG, "Make expanded visible: expanded visible=" + mExpandedVisible);
-        if (!force && (mExpandedVisible || !mCommandQueue.panelsEnabled())) {
-            return;
-        }
-
-        mExpandedVisible = true;
-
-        // Expand the window to encompass the full screen in anticipation of the drag.
-        // This is only possible to do atomically because the status bar is at the top of the screen!
-        mNotificationShadeWindowController.setPanelVisible(true);
-
-        visibilityChanged(true);
-        mCommandQueue.recomputeDisableFlags(mDisplayId, !force /* animate */);
-        setInteracting(StatusBarManager.WINDOW_STATUS_BAR, true);
-    }
-
-    @Override
     public void postAnimateCollapsePanels() {
-        mMainExecutor.execute(mShadeController::animateCollapsePanels);
+        mMainExecutor.execute(mShadeController::animateCollapseShade);
     }
 
     @Override
     public void postAnimateForceCollapsePanels() {
-        mMainExecutor.execute(
-                () -> mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE,
-                true /* force */));
+        mMainExecutor.execute(mShadeController::animateCollapseShadeForced);
     }
 
     @Override
@@ -1958,11 +1973,6 @@
     }
 
     @Override
-    public boolean isExpandedVisible() {
-        return mExpandedVisible;
-    }
-
-    @Override
     public boolean isPanelExpanded() {
         return mPanelExpanded;
     }
@@ -1991,89 +2001,23 @@
         }
     }
 
-    void makeExpandedInvisible() {
-        if (SPEW) Log.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible);
-
-        if (!mExpandedVisible || mNotificationShadeWindowView == null) {
-            return;
-        }
-
-        // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
-        mNotificationPanelViewController.collapsePanel(/*animate=*/ false, false /* delayed*/,
-                1.0f /* speedUpFactor */);
-
-        mNotificationPanelViewController.closeQs();
-
-        mExpandedVisible = false;
-        visibilityChanged(false);
-
-        // Update the visibility of notification shade and status bar window.
-        mNotificationShadeWindowController.setPanelVisible(false);
-        mStatusBarWindowController.setForceStatusBarVisible(false);
-
-        // Close any guts that might be visible
-        mGutsManager.closeAndSaveGuts(true /* removeLeavebehind */, true /* force */,
-                true /* removeControls */, -1 /* x */, -1 /* y */, true /* resetMenu */);
-
-        mShadeController.runPostCollapseRunnables();
+    private void onExpandedInvisible() {
         setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
         if (!mNotificationActivityStarter.isCollapsingToShowActivityOverLockscreen()) {
             showBouncerOrLockScreenIfKeyguard();
         } else if (DEBUG) {
             Log.d(TAG, "Not showing bouncer due to activity showing over lockscreen");
         }
-        mCommandQueue.recomputeDisableFlags(
-                mDisplayId,
-                mNotificationPanelViewController.hideStatusBarIconsWhenExpanded() /* animate */);
-
-        // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in
-        // the bouncer appear animation.
-        if (!mKeyguardStateController.isShowing()) {
-            WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
-        }
-    }
-
-    /** Called when a touch event occurred on {@link PhoneStatusBarView}. */
-    @Override
-    public void onTouchEvent(MotionEvent event) {
-        // TODO(b/202981994): Move this touch debugging to a central location. (Right now, it's
-        //   split between NotificationPanelViewController and here.)
-        if (DEBUG_GESTURES) {
-            if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
-                EventLog.writeEvent(EventLogTags.SYSUI_STATUSBAR_TOUCH,
-                        event.getActionMasked(), (int) event.getX(), (int) event.getY(),
-                        mDisabled1, mDisabled2);
-            }
-
-        }
-
-        if (SPEW) {
-            Log.d(TAG, "Touch: rawY=" + event.getRawY() + " event=" + event + " mDisabled1="
-                    + mDisabled1 + " mDisabled2=" + mDisabled2);
-        } else if (CHATTY) {
-            if (event.getAction() != MotionEvent.ACTION_MOVE) {
-                Log.d(TAG, String.format(
-                            "panel: %s at (%f, %f) mDisabled1=0x%08x mDisabled2=0x%08x",
-                            MotionEvent.actionToString(event.getAction()),
-                            event.getRawX(), event.getRawY(), mDisabled1, mDisabled2));
-            }
-        }
-
-        if (DEBUG_GESTURES) {
-            mGestureRec.add(event);
-        }
-
-        if (mStatusBarWindowState == WINDOW_STATE_SHOWING) {
-            final boolean upOrCancel =
-                    event.getAction() == MotionEvent.ACTION_UP ||
-                    event.getAction() == MotionEvent.ACTION_CANCEL;
-            setInteracting(StatusBarManager.WINDOW_STATUS_BAR, !upOrCancel || mExpandedVisible);
-        }
     }
 
     @Override
-    public GestureRecorder getGestureRecorder() {
-        return mGestureRec;
+    public boolean getCommandQueuePanelsEnabled() {
+        return mCommandQueue.panelsEnabled();
+    }
+
+    @Override
+    public int getStatusBarWindowState() {
+        return mStatusBarWindowState;
     }
 
     @Override
@@ -2216,7 +2160,7 @@
         IndentingPrintWriter pw = DumpUtilsKt.asIndenting(pwOriginal);
         synchronized (mQueueLock) {
             pw.println("Current Status Bar state:");
-            pw.println("  mExpandedVisible=" + mExpandedVisible);
+            pw.println("  mExpandedVisible=" + mShadeController.isExpandedVisible());
             pw.println("  mDisplayMetrics=" + mDisplayMetrics);
             pw.println("  mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller));
             pw.println("  mStackScroller: " + CentralSurfaces.viewInfo(mStackScroller)
@@ -2531,10 +2475,8 @@
                     }
                 }
                 if (dismissShade) {
-                    if (mExpandedVisible && !mBouncerShowing) {
-                        mShadeController.animateCollapsePanels(
-                                CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
-                                true /* force */, true /* delayed*/);
+                    if (mShadeController.isExpandedVisible() && !mBouncerShowing) {
+                        mShadeController.animateCollapseShadeDelayed();
                     } else {
                         // Do it after DismissAction has been processed to conserve the needed
                         // ordering.
@@ -2576,7 +2518,7 @@
                             flags |= CommandQueue.FLAG_EXCLUDE_NOTIFICATION_PANEL;
                         }
                     }
-                    mShadeController.animateCollapsePanels(flags);
+                    mShadeController.animateCollapseShade(flags);
                 }
             } else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
                 if (mNotificationShadeWindowController != null) {
@@ -2691,10 +2633,9 @@
                 com.android.systemui.R.dimen.physical_power_button_center_screen_location_y));
     }
 
-    // Visibility reporting
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         if (visibleToUser) {
-            handleVisibleToUserChangedImpl(visibleToUser);
+            onVisibleToUser();
             mNotificationLogger.startNotificationLogging();
 
             if (!mIsBackCallbackRegistered) {
@@ -2711,7 +2652,7 @@
             }
         } else {
             mNotificationLogger.stopNotificationLogging();
-            handleVisibleToUserChangedImpl(visibleToUser);
+            onInvisibleToUser();
 
             if (mIsBackCallbackRegistered) {
                 ViewRootImpl viewRootImpl = getViewRootImpl();
@@ -2731,41 +2672,38 @@
         }
     }
 
-    // Visibility reporting
-    void handleVisibleToUserChangedImpl(boolean visibleToUser) {
-        if (visibleToUser) {
-            /* The LEDs are turned off when the notification panel is shown, even just a little bit.
-             * See also CentralSurfaces.setPanelExpanded for another place where we attempt to do
-             * this.
-             */
-            boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
-            boolean clearNotificationEffects =
-                    !mPresenter.isPresenterFullyCollapsed() &&
-                            (mState == StatusBarState.SHADE
-                                    || mState == StatusBarState.SHADE_LOCKED);
-            int notificationLoad = mNotificationsController.getActiveNotificationsCount();
-            if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
-                notificationLoad = 1;
-            }
-            final int finalNotificationLoad = notificationLoad;
-            mUiBgExecutor.execute(() -> {
-                try {
-                    mBarService.onPanelRevealed(clearNotificationEffects,
-                            finalNotificationLoad);
-                } catch (RemoteException ex) {
-                    // Won't fail unless the world has ended.
-                }
-            });
-        } else {
-            mUiBgExecutor.execute(() -> {
-                try {
-                    mBarService.onPanelHidden();
-                } catch (RemoteException ex) {
-                    // Won't fail unless the world has ended.
-                }
-            });
+    void onVisibleToUser() {
+        /* The LEDs are turned off when the notification panel is shown, even just a little bit.
+         * See also CentralSurfaces.setPanelExpanded for another place where we attempt to do
+         * this.
+         */
+        boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+        boolean clearNotificationEffects =
+                !mPresenter.isPresenterFullyCollapsed() && (mState == StatusBarState.SHADE
+                        || mState == StatusBarState.SHADE_LOCKED);
+        int notificationLoad = mNotificationsController.getActiveNotificationsCount();
+        if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
+            notificationLoad = 1;
         }
+        final int finalNotificationLoad = notificationLoad;
+        mUiBgExecutor.execute(() -> {
+            try {
+                mBarService.onPanelRevealed(clearNotificationEffects,
+                        finalNotificationLoad);
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        });
+    }
 
+    void onInvisibleToUser() {
+        mUiBgExecutor.execute(() -> {
+            try {
+                mBarService.onPanelHidden();
+            } catch (RemoteException ex) {
+                // Won't fail unless the world has ended.
+            }
+        });
     }
 
     private void logStateToEventlog() {
@@ -2943,7 +2881,7 @@
     private void updatePanelExpansionForKeyguard() {
         if (mState == StatusBarState.KEYGUARD && mBiometricUnlockController.getMode()
                 != BiometricUnlockController.MODE_WAKE_AND_UNLOCK && !mBouncerShowing) {
-            mShadeController.instantExpandNotificationsPanel();
+            mShadeController.instantExpandShade();
         }
     }
 
@@ -3062,7 +3000,7 @@
             // too heavy for the CPU and GPU on any device.
             mNavigationBarController.disableAnimationsDuringHide(mDisplayId, delay);
         } else if (!mNotificationPanelViewController.isCollapsing()) {
-            instantCollapseNotificationPanel();
+            mShadeController.instantCollapseShade();
         }
 
         // Keyguard state has changed, but QS is not listening anymore. Make sure to update the tile
@@ -3220,8 +3158,7 @@
     @Override
     public boolean onMenuPressed() {
         if (shouldUnlockOnMenuPressed()) {
-            mShadeController.animateCollapsePanels(
-                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
+            mShadeController.animateCollapseShadeForced();
             return true;
         }
         return false;
@@ -3266,7 +3203,7 @@
         if (mState != StatusBarState.KEYGUARD && mState != StatusBarState.SHADE_LOCKED
                 && !isBouncerShowingOverDream()) {
             if (mNotificationPanelViewController.canPanelBeCollapsed()) {
-                mShadeController.animateCollapsePanels();
+                mShadeController.animateCollapseShade();
             }
             return true;
         }
@@ -3276,8 +3213,7 @@
     @Override
     public boolean onSpacePressed() {
         if (mDeviceInteractive && mState != StatusBarState.SHADE) {
-            mShadeController.animateCollapsePanels(
-                    CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */);
+            mShadeController.animateCollapseShadeForced();
             return true;
         }
         return false;
@@ -3317,12 +3253,6 @@
         }
     }
 
-    @Override
-    public void instantCollapseNotificationPanel() {
-        mNotificationPanelViewController.instantCollapse();
-        mShadeController.runPostCollapseRunnables();
-    }
-
     /**
      * Collapse the panel directly if we are on the main thread, post the collapsing on the main
      * thread if we are not.
@@ -3330,9 +3260,9 @@
     @Override
     public void collapsePanelOnMainThread() {
         if (Looper.getMainLooper().isCurrentThread()) {
-            mShadeController.collapsePanel();
+            mShadeController.collapseShade();
         } else {
-            mContext.getMainExecutor().execute(mShadeController::collapsePanel);
+            mContext.getMainExecutor().execute(mShadeController::collapseShade);
         }
     }
 
@@ -3347,6 +3277,10 @@
             return;
         }
 
+        if (mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+            return;
+        }
+
         final boolean wakingUpFromPowerButton = wakingUp
                 && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)
                 && mWakefulnessLifecycle.getLastWakeReason()
@@ -3373,21 +3307,6 @@
         return mLightRevealScrim;
     }
 
-    @Override
-    public void onTrackingStarted() {
-        mShadeController.runPostCollapseRunnables();
-    }
-
-    @Override
-    public void onClosingFinished() {
-        mShadeController.runPostCollapseRunnables();
-        if (!mPresenter.isPresenterFullyCollapsed()) {
-            // if we set it not to be focusable when collapsing, we have to undo it when we aborted
-            // the closing
-            mNotificationShadeWindowController.setNotificationShadeFocusable(true);
-        }
-    }
-
     // TODO: Figure out way to remove these.
     @Override
     public NavigationBarView getNavigationBarView() {
@@ -3472,7 +3391,7 @@
             mNotificationShadeWindowViewController.cancelCurrentTouch();
         }
         if (mPanelExpanded && mState == StatusBarState.SHADE) {
-            mShadeController.animateCollapsePanels();
+            mShadeController.animateCollapseShade();
         }
     }
 
@@ -3535,7 +3454,7 @@
             // The unlocked screen off and fold to aod animations might use our LightRevealScrim -
             // we need to be expanded for it to be visible.
             if (mDozeParameters.shouldShowLightRevealScrim()) {
-                makeExpandedVisible(true);
+                mShadeController.makeExpandedVisible(true);
             }
 
             DejankUtils.stopDetectingBlockingIpcs(tag);
@@ -3564,7 +3483,7 @@
                 // If we are waking up during the screen off animation, we should undo making the
                 // expanded visible (we did that so the LightRevealScrim would be visible).
                 if (mScreenOffAnimationController.shouldHideLightRevealScrimOnWakeUp()) {
-                    makeExpandedInvisible();
+                    mShadeController.makeExpandedInvisible();
                 }
 
             });
@@ -3899,8 +3818,7 @@
                 Settings.Secure.putInt(mContext.getContentResolver(),
                         Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
                 if (BANNER_ACTION_SETUP.equals(action)) {
-                    mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL,
-                            true /* force */);
+                    mShadeController.animateCollapseShadeForced();
                     mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION)
                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
 
@@ -3962,7 +3880,7 @@
                     action.run();
                 }).start();
 
-                return collapsePanel ? mShadeController.collapsePanel() : willAnimateOnKeyguard;
+                return collapsePanel ? mShadeController.collapseShade() : willAnimateOnKeyguard;
             }
 
             @Override
@@ -4057,8 +3975,7 @@
         mMainExecutor.execute(runnable);
     }
 
-    @Override
-    public void visibilityChanged(boolean visible) {
+    private void onShadeVisibilityChanged(boolean visible) {
         if (mVisible != visible) {
             mVisible = visible;
             if (!visible) {
@@ -4128,7 +4045,9 @@
             return;
         }
 
-        mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
+        if (!mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)) {
+            mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
+        }
     }
 
     @Override
@@ -4309,6 +4228,7 @@
                 @Override
                 public void onDozeAmountChanged(float linear, float eased) {
                     if (mFeatureFlags.isEnabled(Flags.LOCKSCREEN_ANIMATIONS)
+                            && !mFeatureFlags.isEnabled(Flags.LIGHT_REVEAL_MIGRATION)
                             && !(mLightRevealScrim.getRevealEffect() instanceof CircleReveal)) {
                         mLightRevealScrim.setRevealAmount(1f - linear);
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index aa0757e..000fe14 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -240,8 +240,8 @@
                     && !mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
                             KeyguardUpdateMonitor.getCurrentUser())
                     && !needsFullscreenBouncer()
-                    && !mKeyguardUpdateMonitor.isFaceLockedOut()
-                    && !mKeyguardUpdateMonitor.userNeedsStrongAuth()
+                    && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                            BiometricSourceType.FACE)
                     && !mKeyguardBypassController.getBypassEnabled()) {
                 mHandler.postDelayed(mShowRunnable, BOUNCER_FACE_DELAY);
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
index 26e6db6..4beb87d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ManagedProfileControllerImpl.java
@@ -15,23 +15,21 @@
 package com.android.systemui.statusbar.phone;
 
 import android.app.StatusBarManager;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
 import android.os.UserManager;
 
 import androidx.annotation.NonNull;
 
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.settings.UserTracker;
 
 import java.util.ArrayList;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -43,9 +41,9 @@
     private final List<Callback> mCallbacks = new ArrayList<>();
 
     private final Context mContext;
+    private final Executor mMainExecutor;
     private final UserManager mUserManager;
     private final UserTracker mUserTracker;
-    private final BroadcastDispatcher mBroadcastDispatcher;
     private final LinkedList<UserInfo> mProfiles;
     private boolean mListening;
     private int mCurrentUser;
@@ -53,12 +51,12 @@
     /**
      */
     @Inject
-    public ManagedProfileControllerImpl(Context context, UserTracker userTracker,
-            BroadcastDispatcher broadcastDispatcher) {
+    public ManagedProfileControllerImpl(Context context, @Main Executor mainExecutor,
+            UserTracker userTracker) {
         mContext = context;
+        mMainExecutor = mainExecutor;
         mUserManager = UserManager.get(mContext);
         mUserTracker = userTracker;
-        mBroadcastDispatcher = broadcastDispatcher;
         mProfiles = new LinkedList<UserInfo>();
     }
 
@@ -130,30 +128,34 @@
     }
 
     private void setListening(boolean listening) {
+        if (mListening == listening) {
+            return;
+        }
         mListening = listening;
         if (listening) {
             reloadManagedProfiles();
-
-            final IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_USER_SWITCHED);
-            filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-            filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
-            filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);
-            filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);
-            mBroadcastDispatcher.registerReceiver(
-                    mReceiver, filter, null /* handler */, UserHandle.ALL);
+            mUserTracker.addCallback(mUserChangedCallback, mMainExecutor);
         } else {
-            mBroadcastDispatcher.unregisterReceiver(mReceiver);
+            mUserTracker.removeCallback(mUserChangedCallback);
         }
     }
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            reloadManagedProfiles();
-            for (Callback callback : mCallbacks) {
-                callback.onManagedProfileChanged();
-            }
-        }
-    };
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    reloadManagedProfiles();
+                    for (Callback callback : mCallbacks) {
+                        callback.onManagedProfileChanged();
+                    }
+                }
+
+                @Override
+                public void onProfilesChanged(@NonNull List<UserInfo> profiles) {
+                    reloadManagedProfiles();
+                    for (Callback callback : mCallbacks) {
+                        callback.onManagedProfileChanged();
+                    }
+                }
+            };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
index a6c2b2c..11bc490 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewController.kt
@@ -15,14 +15,20 @@
  */
 package com.android.systemui.statusbar.phone
 
+import android.app.StatusBarManager.WINDOW_STATE_SHOWING
+import android.app.StatusBarManager.WINDOW_STATUS_BAR
 import android.content.res.Configuration
 import android.graphics.Point
+import android.util.Log
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import com.android.systemui.R
+import com.android.systemui.shade.ShadeController
+import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator
+import com.android.systemui.statusbar.phone.PhoneStatusBarView.TouchEventHandler
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UNFOLD_STATUS_BAR
@@ -35,14 +41,18 @@
 import javax.inject.Inject
 import javax.inject.Named
 
+private const val TAG = "PhoneStatusBarViewController"
+
 /** Controller for [PhoneStatusBarView].  */
 class PhoneStatusBarViewController private constructor(
     view: PhoneStatusBarView,
     @Named(UNFOLD_STATUS_BAR) private val progressProvider: ScopedUnfoldTransitionProgressProvider?,
+    private val centralSurfaces: CentralSurfaces,
+    private val shadeController: ShadeController,
+    private val shadeLogger: ShadeLogger,
     private val moveFromCenterAnimationController: StatusBarMoveFromCenterAnimationController?,
     private val userChipViewModel: StatusBarUserChipViewModel,
     private val viewUtil: ViewUtil,
-    touchEventHandler: PhoneStatusBarView.TouchEventHandler,
     private val configurationController: ConfigurationController
 ) : ViewController<PhoneStatusBarView>(view) {
 
@@ -90,7 +100,7 @@
     }
 
     init {
-        mView.setTouchEventHandler(touchEventHandler)
+        mView.setTouchEventHandler(PhoneStatusBarViewTouchHandler())
         mView.init(userChipViewModel)
     }
 
@@ -120,6 +130,54 @@
         return viewUtil.touchIsWithinView(mView, x, y)
     }
 
+    /** Called when a touch event occurred on {@link PhoneStatusBarView}. */
+    fun onTouchEvent(event: MotionEvent) {
+        if (centralSurfaces.statusBarWindowState == WINDOW_STATE_SHOWING) {
+            val upOrCancel =
+                    event.action == MotionEvent.ACTION_UP ||
+                    event.action == MotionEvent.ACTION_CANCEL
+            centralSurfaces.setInteracting(WINDOW_STATUS_BAR,
+                    !upOrCancel || shadeController.isExpandedVisible)
+        }
+    }
+
+    inner class PhoneStatusBarViewTouchHandler : TouchEventHandler {
+        override fun onInterceptTouchEvent(event: MotionEvent) {
+            onTouchEvent(event)
+        }
+
+        override fun handleTouchEvent(event: MotionEvent): Boolean {
+            onTouchEvent(event)
+
+            // If panels aren't enabled, ignore the gesture and don't pass it down to the
+            // panel view.
+            if (!centralSurfaces.commandQueuePanelsEnabled) {
+                if (event.action == MotionEvent.ACTION_DOWN) {
+                    Log.v(TAG, String.format("onTouchForwardedFromStatusBar: panel disabled, " +
+                            "ignoring touch at (${event.x.toInt()},${event.y.toInt()})"))
+                }
+                return false
+            }
+
+            if (event.action == MotionEvent.ACTION_DOWN) {
+                // If the view that would receive the touch is disabled, just have status
+                // bar eat the gesture.
+                if (!centralSurfaces.notificationPanelViewController.isViewEnabled) {
+                    shadeLogger.logMotionEvent(event,
+                            "onTouchForwardedFromStatusBar: panel view disabled")
+                    return true
+                }
+                if (centralSurfaces.notificationPanelViewController.isFullyCollapsed &&
+                        event.y < 1f) {
+                    // b/235889526 Eat events on the top edge of the phone when collapsed
+                    shadeLogger.logMotionEvent(event, "top edge touch ignored")
+                    return true
+                }
+            }
+            return centralSurfaces.notificationPanelViewController.sendTouchEventToView(event)
+        }
+    }
+
     class StatusBarViewsCenterProvider : UnfoldMoveFromCenterAnimator.ViewCenterProvider {
         override fun getViewCenter(view: View, outPoint: Point) =
             when (view.id) {
@@ -157,20 +215,24 @@
         @Named(UNFOLD_STATUS_BAR)
         private val progressProvider: Optional<ScopedUnfoldTransitionProgressProvider>,
         private val userChipViewModel: StatusBarUserChipViewModel,
+        private val centralSurfaces: CentralSurfaces,
+        private val shadeController: ShadeController,
+        private val shadeLogger: ShadeLogger,
         private val viewUtil: ViewUtil,
         private val configurationController: ConfigurationController,
     ) {
         fun create(
-            view: PhoneStatusBarView,
-            touchEventHandler: PhoneStatusBarView.TouchEventHandler
+            view: PhoneStatusBarView
         ) =
             PhoneStatusBarViewController(
                 view,
                 progressProvider.getOrNull(),
+                centralSurfaces,
+                shadeController,
+                shadeLogger,
                 unfoldComponent.getOrNull()?.getStatusBarMoveFromCenterAnimationController(),
                 userChipViewModel,
                 viewUtil,
-                touchEventHandler,
                 configurationController
             )
     }
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 fb0d3e4..d500f99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -352,6 +352,11 @@
                 .getBoolean(R.bool.notification_scrim_transparent);
         updateScrims();
         mKeyguardUpdateMonitor.registerCallback(mKeyguardVisibilityCallback);
+
+        // prepare() sets proper initial values for most states
+        for (ScrimState state : ScrimState.values()) {
+            state.prepare(state);
+        }
     }
 
     /**
@@ -641,10 +646,6 @@
     private void setTransitionToFullShade(boolean transitioning) {
         if (transitioning != mTransitioningToFullShade) {
             mTransitioningToFullShade = transitioning;
-            if (transitioning) {
-                // Let's make sure the shade locked is ready
-                ScrimState.SHADE_LOCKED.prepare(mState);
-            }
         }
     }
 
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 52430d3..0e9d3ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -146,18 +146,12 @@
             mBehindAlpha = mClipQsScrim ? 1 : mDefaultScrimAlpha;
             mNotifAlpha = 1f;
             mFrontAlpha = 0f;
-            mBehindTint = Color.BLACK;
+            mBehindTint = mClipQsScrim ? Color.TRANSPARENT : Color.BLACK;
 
             if (mClipQsScrim) {
                 updateScrimColor(mScrimBehind, 1f /* alpha */, Color.BLACK);
             }
         }
-
-        // to make sure correct color is returned before "prepare" is called
-        @Override
-        public int getBehindTint() {
-            return Color.BLACK;
-        }
     },
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 44ad604..aafcddd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -19,9 +19,6 @@
 import static android.view.WindowInsets.Type.navigationBars;
 
 import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
-import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_DISMISS_BOUNCER;
-import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_SHOW_BOUNCER;
-import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_COLLAPSING;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
 import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
 
@@ -140,6 +137,10 @@
     private final BouncerView mPrimaryBouncerView;
     private final Lazy<com.android.systemui.shade.ShadeController> mShadeController;
 
+    // Local cache of expansion events, to avoid duplicates
+    private float mFraction = -1f;
+    private boolean mTracking = false;
+
     private final PrimaryBouncerExpansionCallback mExpansionCallback =
             new PrimaryBouncerExpansionCallback() {
             private boolean mPrimaryBouncerAnimating;
@@ -440,77 +441,68 @@
         hideBouncer(true /* destroyView */);
     }
 
-    @Override
-    public void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
-        float fraction = event.getFraction();
-        boolean tracking = event.getTracking();
+    private boolean beginShowingBouncer(ShadeExpansionChangeEvent event) {
         // Avoid having the shade and the bouncer open at the same time over a dream.
         final boolean hideBouncerOverDream =
                 mDreamOverlayStateController.isOverlayActive()
                         && (mNotificationPanelViewController.isExpanded()
                         || mNotificationPanelViewController.isExpanding());
 
-        // We don't want to translate the bounce when:
-        // • device is dozing and not pulsing
-        // • Keyguard is occluded, because we're in a FLAG_SHOW_WHEN_LOCKED activity and need to
-        //   conserve the original animation.
-        // • The user quickly taps on the display and we show "swipe up to unlock."
-        // • Keyguard will be dismissed by an action. a.k.a: FLAG_DISMISS_KEYGUARD_ACTIVITY
-        // • Full-screen user switcher is displayed.
-        if (mDozing && !mPulsing) {
+        final boolean isUserTrackingStarted =
+                event.getFraction() != KeyguardBouncer.EXPANSION_HIDDEN && event.getTracking();
+
+        return mKeyguardStateController.isShowing()
+                && !primaryBouncerIsOrWillBeShowing()
+                && isUserTrackingStarted
+                && !hideBouncerOverDream
+                && !mKeyguardStateController.isOccluded()
+                && !mKeyguardStateController.canDismissLockScreen()
+                && !bouncerIsAnimatingAway()
+                && !mNotificationPanelViewController.isUnlockHintRunning()
+                && !(mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED);
+    }
+
+    @Override
+    public void onPanelExpansionChanged(ShadeExpansionChangeEvent event) {
+        float fraction = event.getFraction();
+        boolean tracking = event.getTracking();
+
+        if (mFraction == fraction && mTracking == tracking) {
+            // Ignore duplicate events, as they will cause confusion with bouncer expansion
             return;
-        } else if (mNotificationPanelViewController.isUnlockHintRunning()) {
+        }
+        mFraction = fraction;
+        mTracking = tracking;
+
+        /*
+         * The bouncer may have received a call to show(), or the following will infer it from
+         * device state and touch handling. The bouncer MUST have been notified that it is about to
+         * show if any subsequent events are to be handled.
+         */
+        if (beginShowingBouncer(event)) {
+            if (mPrimaryBouncer != null) {
+                mPrimaryBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
+            } else {
+                mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
+            }
+        }
+
+        if (!primaryBouncerIsOrWillBeShowing()) {
+            return;
+        }
+
+        if (mKeyguardStateController.isShowing()) {
+            if (mPrimaryBouncer != null) {
+                mPrimaryBouncer.setExpansion(fraction);
+            } else {
+                mPrimaryBouncerInteractor.setPanelExpansion(fraction);
+            }
+        } else {
             if (mPrimaryBouncer != null) {
                 mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
             } else {
                 mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
             }
-        } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
-            // Don't expand to the bouncer. Instead transition back to the lock screen (see
-            // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
-            return;
-        } else if (needsFullscreenBouncer()) {
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
-            } else {
-                mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
-            }
-        } else if (mKeyguardStateController.isShowing() && !hideBouncerOverDream) {
-            if (!isWakeAndUnlocking()
-                    && !(mBiometricUnlockController.getMode() == MODE_DISMISS_BOUNCER)
-                    && !(mBiometricUnlockController.getMode() == MODE_SHOW_BOUNCER)
-                    && !isUnlockCollapsing()) {
-                if (mPrimaryBouncer != null) {
-                    mPrimaryBouncer.setExpansion(fraction);
-                } else {
-                    mPrimaryBouncerInteractor.setPanelExpansion(fraction);
-                }
-            }
-            if (fraction != KeyguardBouncer.EXPANSION_HIDDEN && tracking
-                    && !mKeyguardStateController.canDismissLockScreen()
-                    && !primaryBouncerIsShowing()
-                    && !bouncerIsAnimatingAway()) {
-                if (mPrimaryBouncer != null) {
-                    mPrimaryBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
-                } else {
-                    mPrimaryBouncerInteractor.show(/* isScrimmed= */false);
-                }
-            }
-        } else if (!mKeyguardStateController.isShowing()  && isPrimaryBouncerInTransit()) {
-            // Keyguard is not visible anymore, but expansion animation was still running.
-            // We need to hide the bouncer, otherwise it will be stuck in transit.
-            if (mPrimaryBouncer != null) {
-                mPrimaryBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
-            } else {
-                mPrimaryBouncerInteractor.setPanelExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
-            }
-        } else if (mPulsing && fraction == KeyguardBouncer.EXPANSION_VISIBLE) {
-            // Panel expanded while pulsing but didn't translate the bouncer (because we are
-            // unlocked.) Let's simply wake-up to dismiss the lock screen.
-            mCentralSurfaces.wakeUpIfDozing(
-                    SystemClock.uptimeMillis(),
-                    mCentralSurfaces.getBouncerContainer(),
-                    "BOUNCER_VISIBLE");
         }
     }
 
@@ -701,11 +693,6 @@
         return mode == MODE_WAKE_AND_UNLOCK || mode == MODE_WAKE_AND_UNLOCK_PULSING;
     }
 
-    private boolean isUnlockCollapsing() {
-        int mode = mBiometricUnlockController.getMode();
-        return mode == MODE_UNLOCK_COLLAPSING;
-    }
-
     /**
      * Adds a {@param runnable} to be executed after Keyguard is gone.
      */
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 b6ae4a0..05bf860 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -260,11 +260,11 @@
 
         if (showOverLockscreen) {
             mShadeController.addPostCollapseAction(runnable);
-            mShadeController.collapsePanel(true /* animate */);
+            mShadeController.collapseShade(true /* animate */);
         } else if (mKeyguardStateController.isShowing()
                 && mCentralSurfaces.isOccluded()) {
             mStatusBarKeyguardViewManager.addAfterKeyguardGoneRunnable(runnable);
-            mShadeController.collapsePanel();
+            mShadeController.collapseShade();
         } else {
             runnable.run();
         }
@@ -406,7 +406,7 @@
 
     private void expandBubbleStack(NotificationEntry entry) {
         mBubblesManagerOptional.get().expandStackAndSelectBubble(entry);
-        mShadeController.collapsePanel();
+        mShadeController.collapseShade();
     }
 
     private void startNotificationIntent(
@@ -593,9 +593,9 @@
 
     private void collapseOnMainThread() {
         if (Looper.getMainLooper().isCurrentThread()) {
-            mShadeController.collapsePanel();
+            mShadeController.collapseShade();
         } else {
-            mMainThreadHandler.post(mShadeController::collapsePanel);
+            mMainThreadHandler.post(mShadeController::collapseShade);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 8a49850..7fe01825 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -180,7 +180,7 @@
                 }
             };
             mShadeController.postOnShadeExpanded(clickPendingViewRunnable);
-            mShadeController.instantExpandNotificationsPanel();
+            mShadeController.instantExpandShade();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
index efec270..730ecde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/dagger/StatusBarFragmentModule.java
@@ -21,7 +21,6 @@
 import com.android.systemui.R;
 import com.android.systemui.battery.BatteryMeterView;
 import com.android.systemui.dagger.qualifiers.RootView;
-import com.android.systemui.shade.NotificationPanelViewController;
 import com.android.systemui.statusbar.HeadsUpStatusBarView;
 import com.android.systemui.statusbar.phone.PhoneStatusBarTransitions;
 import com.android.systemui.statusbar.phone.PhoneStatusBarView;
@@ -127,11 +126,9 @@
     @StatusBarFragmentScope
     static PhoneStatusBarViewController providePhoneStatusBarViewController(
             PhoneStatusBarViewController.Factory phoneStatusBarViewControllerFactory,
-            @RootView PhoneStatusBarView phoneStatusBarView,
-            NotificationPanelViewController notificationPanelViewController) {
+            @RootView PhoneStatusBarView phoneStatusBarView) {
         return phoneStatusBarViewControllerFactory.create(
-                phoneStatusBarView,
-                notificationPanelViewController.getStatusBarTouchEventHandler());
+                phoneStatusBarView);
     }
 
     /** */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
index 946d7e4..4d914fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/StatusBarPipelineFlags.kt
@@ -52,6 +52,6 @@
      * Returns true if we should apply some coloring to the wifi icon that was rendered with the new
      * pipeline to help with debugging.
      */
-    // For now, just always apply the debug coloring if we've enabled the new icon.
-    fun useWifiDebugColoring(): Boolean = useNewWifiIcon()
+    fun useWifiDebugColoring(): Boolean =
+        featureFlags.isEnabled(Flags.NEW_STATUS_BAR_ICONS_DEBUG_COLORING)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
index 7aa5ee1..8ff9198 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepository.kt
@@ -23,9 +23,10 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
 import com.android.systemui.qs.SettingObserver
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
+import com.android.systemui.statusbar.pipeline.dagger.AirplaneTableLog
 import com.android.systemui.util.settings.GlobalSettings
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -58,7 +59,7 @@
 constructor(
     @Background private val bgHandler: Handler,
     private val globalSettings: GlobalSettings,
-    logger: ConnectivityPipelineLogger,
+    @AirplaneTableLog logger: TableLogBuffer,
     @Application scope: CoroutineScope,
 ) : AirplaneModeRepository {
     // TODO(b/254848912): Replace this with a generic SettingObserver coroutine once we have it.
@@ -82,7 +83,12 @@
                 awaitClose { observer.isListening = false }
             }
             .distinctUntilChanged()
-            .logInputChange(logger, "isAirplaneMode")
+            .logDiffsForTable(
+                logger,
+                columnPrefix = "",
+                columnName = "isAirplaneMode",
+                initialValue = false
+            )
             .stateIn(
                 scope,
                 started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
index fe30c01..4a5342e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModel.kt
@@ -36,16 +36,20 @@
  * [com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository] for
  * more details.
  */
+interface AirplaneModeViewModel {
+    /** True if the airplane mode icon is currently visible in the status bar. */
+    val isAirplaneModeIconVisible: StateFlow<Boolean>
+}
+
 @SysUISingleton
-class AirplaneModeViewModel
+class AirplaneModeViewModelImpl
 @Inject
 constructor(
     interactor: AirplaneModeInteractor,
     logger: ConnectivityPipelineLogger,
     @Application private val scope: CoroutineScope,
-) {
-    /** True if the airplane mode icon is currently visible in the status bar. */
-    val isAirplaneModeIconVisible: StateFlow<Boolean> =
+) : AirplaneModeViewModel {
+    override val isAirplaneModeIconVisible: StateFlow<Boolean> =
         combine(interactor.isAirplaneMode, interactor.isForceHidden) {
                 isAirplaneMode,
                 isAirplaneIconForceHidden ->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/AirplaneTableLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/AirplaneTableLog.kt
new file mode 100644
index 0000000..4f70f66
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/AirplaneTableLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Airplane mode logs in table format. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class AirplaneTableLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index fcd1b8a..fb67f1a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -16,8 +16,13 @@
 
 package com.android.systemui.statusbar.pipeline.dagger
 
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepositoryImpl
+import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
+import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryImpl
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
@@ -30,8 +35,11 @@
 import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
 import dagger.Binds
 import dagger.Module
+import dagger.Provides
 
 @Module
 abstract class StatusBarPipelineModule {
@@ -39,12 +47,18 @@
     abstract fun airplaneModeRepository(impl: AirplaneModeRepositoryImpl): AirplaneModeRepository
 
     @Binds
+    abstract fun airplaneModeViewModel(impl: AirplaneModeViewModelImpl): AirplaneModeViewModel
+
+    @Binds
     abstract fun connectivityRepository(impl: ConnectivityRepositoryImpl): ConnectivityRepository
 
     @Binds
     abstract fun wifiRepository(impl: WifiRepositoryImpl): WifiRepository
 
     @Binds
+    abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
+
+    @Binds
     abstract fun mobileConnectionsRepository(
         impl: MobileConnectionsRepositoryImpl
     ): MobileConnectionsRepository
@@ -57,4 +71,23 @@
 
     @Binds
     abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor
+
+    @Module
+    companion object {
+        @JvmStatic
+        @Provides
+        @SysUISingleton
+        @WifiTableLog
+        fun provideWifiTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
+            return factory.create("WifiTableLog", 100)
+        }
+
+        @JvmStatic
+        @Provides
+        @SysUISingleton
+        @AirplaneTableLog
+        fun provideAirplaneTableLogBuffer(factory: TableLogBufferFactory): TableLogBuffer {
+            return factory.create("AirplaneTableLog", 30)
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTableLog.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTableLog.kt
new file mode 100644
index 0000000..ac395a9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/WifiTableLog.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pipeline.dagger
+
+import javax.inject.Qualifier
+
+/** Wifi logs in table format. */
+@Qualifier
+@MustBeDocumented
+@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
+annotation class WifiTableLog
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
index 062c3d1..a682a57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModel.kt
@@ -17,12 +17,34 @@
 package com.android.systemui.statusbar.pipeline.wifi.data.model
 
 import androidx.annotation.VisibleForTesting
+import com.android.systemui.log.table.TableRowLogger
+import com.android.systemui.log.table.Diffable
 
 /** Provides information about the current wifi network. */
-sealed class WifiNetworkModel {
+sealed class WifiNetworkModel : Diffable<WifiNetworkModel> {
+
     /** A model representing that we have no active wifi network. */
     object Inactive : WifiNetworkModel() {
         override fun toString() = "WifiNetwork.Inactive"
+
+        override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
+            if (prevVal is Inactive) {
+                return
+            }
+
+            if (prevVal is CarrierMerged) {
+                // The only difference between CarrierMerged and Inactive is the type
+                row.logChange(COL_NETWORK_TYPE, TYPE_INACTIVE)
+                return
+            }
+
+            // When changing from Active to Inactive, we need to log diffs to all the fields.
+            logFullNonActiveNetwork(TYPE_INACTIVE, row)
+        }
+
+        override fun logFull(row: TableRowLogger) {
+            logFullNonActiveNetwork(TYPE_INACTIVE, row)
+        }
     }
 
     /**
@@ -33,6 +55,21 @@
      */
     object CarrierMerged : WifiNetworkModel() {
         override fun toString() = "WifiNetwork.CarrierMerged"
+
+        override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
+            if (prevVal is CarrierMerged) {
+                return
+            }
+
+            if (prevVal is Inactive) {
+                // The only difference between CarrierMerged and Inactive is the type.
+                row.logChange(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED)
+                return
+            }
+
+            // When changing from Active to CarrierMerged, we need to log diffs to all the fields.
+            logFullNonActiveNetwork(TYPE_CARRIER_MERGED, row)
+        }
     }
 
     /** Provides information about an active wifi network. */
@@ -76,6 +113,44 @@
             }
         }
 
+        override fun logDiffs(prevVal: WifiNetworkModel, row: TableRowLogger) {
+            if (prevVal !is Active) {
+                row.logChange(COL_NETWORK_TYPE, TYPE_ACTIVE)
+            }
+
+            if (prevVal !is Active || prevVal.networkId != networkId) {
+                row.logChange(COL_NETWORK_ID, networkId)
+            }
+            if (prevVal !is Active || prevVal.isValidated != isValidated) {
+                row.logChange(COL_VALIDATED, isValidated)
+            }
+            if (prevVal !is Active || prevVal.level != level) {
+                if (level != null) {
+                    row.logChange(COL_LEVEL, level)
+                } else {
+                    row.logChange(COL_LEVEL, LEVEL_DEFAULT)
+                }
+            }
+            if (prevVal !is Active || prevVal.ssid != ssid) {
+                row.logChange(COL_SSID, ssid)
+            }
+
+            // TODO(b/238425913): The passpoint-related values are frequently never used, so it
+            //   would be great to not log them when they're not used.
+            if (prevVal !is Active || prevVal.isPasspointAccessPoint != isPasspointAccessPoint) {
+                row.logChange(COL_PASSPOINT_ACCESS_POINT, isPasspointAccessPoint)
+            }
+            if (prevVal !is Active ||
+                prevVal.isOnlineSignUpForPasspointAccessPoint !=
+                isOnlineSignUpForPasspointAccessPoint) {
+                row.logChange(COL_ONLINE_SIGN_UP, isOnlineSignUpForPasspointAccessPoint)
+            }
+            if (prevVal !is Active ||
+                prevVal.passpointProviderFriendlyName != passpointProviderFriendlyName) {
+                row.logChange(COL_PASSPOINT_NAME, passpointProviderFriendlyName)
+            }
+        }
+
         override fun toString(): String {
             // Only include the passpoint-related values in the string if we have them. (Most
             // networks won't have them so they'll be mostly clutter.)
@@ -101,4 +176,31 @@
             internal const val MAX_VALID_LEVEL = 4
         }
     }
+
+    internal fun logFullNonActiveNetwork(type: String, row: TableRowLogger) {
+        row.logChange(COL_NETWORK_TYPE, type)
+        row.logChange(COL_NETWORK_ID, NETWORK_ID_DEFAULT)
+        row.logChange(COL_VALIDATED, false)
+        row.logChange(COL_LEVEL, LEVEL_DEFAULT)
+        row.logChange(COL_SSID, null)
+        row.logChange(COL_PASSPOINT_ACCESS_POINT, false)
+        row.logChange(COL_ONLINE_SIGN_UP, false)
+        row.logChange(COL_PASSPOINT_NAME, null)
+    }
 }
+
+const val TYPE_CARRIER_MERGED = "CarrierMerged"
+const val TYPE_INACTIVE = "Inactive"
+const val TYPE_ACTIVE = "Active"
+
+const val COL_NETWORK_TYPE = "type"
+const val COL_NETWORK_ID = "networkId"
+const val COL_VALIDATED = "isValidated"
+const val COL_LEVEL = "level"
+const val COL_SSID = "ssid"
+const val COL_PASSPOINT_ACCESS_POINT = "isPasspointAccessPoint"
+const val COL_ONLINE_SIGN_UP = "isOnlineSignUpForPasspointAccessPoint"
+const val COL_PASSPOINT_NAME = "passpointProviderFriendlyName"
+
+val LEVEL_DEFAULT: String? = null
+val NETWORK_ID_DEFAULT: String? = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
index 93448c1d..0c9c1cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepository.kt
@@ -36,10 +36,14 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.dagger.WifiTableLog
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.SB_LOGGING_TAG
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger.Companion.logInputChange
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.ACTIVITY_PREFIX
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import java.util.concurrent.Executor
 import javax.inject.Inject
@@ -82,6 +86,7 @@
     broadcastDispatcher: BroadcastDispatcher,
     connectivityManager: ConnectivityManager,
     logger: ConnectivityPipelineLogger,
+    @WifiTableLog wifiTableLogBuffer: TableLogBuffer,
     @Main mainExecutor: Executor,
     @Application scope: CoroutineScope,
     wifiManager: WifiManager?,
@@ -105,7 +110,12 @@
             merge(wifiNetworkChangeEvents, wifiStateChangeEvents)
                 .mapLatest { wifiManager.isWifiEnabled }
                 .distinctUntilChanged()
-                .logInputChange(logger, "enabled")
+                .logDiffsForTable(
+                    wifiTableLogBuffer,
+                    columnPrefix = "",
+                    columnName = "isWifiEnabled",
+                    initialValue = wifiManager.isWifiEnabled,
+                )
                 .stateIn(
                     scope = scope,
                     started = SharingStarted.WhileSubscribed(),
@@ -139,7 +149,12 @@
         awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
     }
         .distinctUntilChanged()
-        .logInputChange(logger, "isWifiDefault")
+        .logDiffsForTable(
+            wifiTableLogBuffer,
+            columnPrefix = "",
+            columnName = "isWifiDefault",
+            initialValue = false,
+        )
         .stateIn(
             scope,
             started = SharingStarted.WhileSubscribed(),
@@ -199,6 +214,12 @@
 
         awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
     }
+        .distinctUntilChanged()
+        .logDiffsForTable(
+            wifiTableLogBuffer,
+            columnPrefix = "wifiNetwork",
+            initialValue = WIFI_NETWORK_DEFAULT,
+        )
         // There will be multiple wifi icons in different places that will frequently
         // subscribe/unsubscribe to flows as the views attach/detach. Using [stateIn] ensures that
         // new subscribes will get the latest value immediately upon subscription. Otherwise, the
@@ -223,6 +244,11 @@
                     awaitClose { wifiManager.unregisterTrafficStateCallback(callback) }
                 }
             }
+                .logDiffsForTable(
+                    wifiTableLogBuffer,
+                    columnPrefix = ACTIVITY_PREFIX,
+                    initialValue = ACTIVITY_DEFAULT,
+                )
                 .stateIn(
                     scope,
                     started = SharingStarted.WhileSubscribed(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
index 3a3e611..ec935fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractor.kt
@@ -34,16 +34,36 @@
  * This interactor processes information from our data layer into information that the UI layer can
  * use.
  */
-@SysUISingleton
-class WifiInteractor @Inject constructor(
-    connectivityRepository: ConnectivityRepository,
-    wifiRepository: WifiRepository,
-) {
+interface WifiInteractor {
     /**
      * The SSID (service set identifier) of the wifi network. Null if we don't have a network, or
      * have a network but no valid SSID.
      */
-    val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
+    val ssid: Flow<String?>
+
+    /** Our current enabled status. */
+    val isEnabled: Flow<Boolean>
+
+    /** Our current default status. */
+    val isDefault: Flow<Boolean>
+
+    /** Our current wifi network. See [WifiNetworkModel]. */
+    val wifiNetwork: Flow<WifiNetworkModel>
+
+    /** Our current wifi activity. See [WifiActivityModel]. */
+    val activity: StateFlow<WifiActivityModel>
+
+    /** True if we're configured to force-hide the wifi icon and false otherwise. */
+    val isForceHidden: Flow<Boolean>
+}
+
+@SysUISingleton
+class WifiInteractorImpl @Inject constructor(
+    connectivityRepository: ConnectivityRepository,
+    wifiRepository: WifiRepository,
+) : WifiInteractor {
+
+    override val ssid: Flow<String?> = wifiRepository.wifiNetwork.map { info ->
         when (info) {
             is WifiNetworkModel.Inactive -> null
             is WifiNetworkModel.CarrierMerged -> null
@@ -56,20 +76,15 @@
         }
     }
 
-    /** Our current enabled status. */
-    val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled
+    override val isEnabled: Flow<Boolean> = wifiRepository.isWifiEnabled
 
-    /** Our current default status. */
-    val isDefault: Flow<Boolean> = wifiRepository.isWifiDefault
+    override val isDefault: Flow<Boolean> = wifiRepository.isWifiDefault
 
-    /** Our current wifi network. See [WifiNetworkModel]. */
-    val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
+    override val wifiNetwork: Flow<WifiNetworkModel> = wifiRepository.wifiNetwork
 
-    /** Our current wifi activity. See [WifiActivityModel]. */
-    val activity: StateFlow<WifiActivityModel> = wifiRepository.wifiActivity
+    override val activity: StateFlow<WifiActivityModel> = wifiRepository.wifiActivity
 
-    /** True if we're configured to force-hide the wifi icon and false otherwise. */
-    val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
+    override val isForceHidden: Flow<Boolean> = connectivityRepository.forceHiddenSlots.map {
         it.contains(ConnectivitySlot.WIFI)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
index 5746106..a4ca41c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/shared/model/WifiActivityModel.kt
@@ -16,10 +16,32 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.shared.model
 
+import com.android.systemui.log.table.Diffable
+import com.android.systemui.log.table.TableRowLogger
+
 /** Provides information on the current wifi activity. */
 data class WifiActivityModel(
     /** True if the wifi has activity in (download). */
     val hasActivityIn: Boolean,
     /** True if the wifi has activity out (upload). */
     val hasActivityOut: Boolean,
-)
+) : Diffable<WifiActivityModel> {
+
+    override fun logDiffs(prevVal: WifiActivityModel, row: TableRowLogger) {
+        if (prevVal.hasActivityIn != hasActivityIn) {
+            row.logChange(COL_ACTIVITY_IN, hasActivityIn)
+        }
+        if (prevVal.hasActivityOut != hasActivityOut) {
+            row.logChange(COL_ACTIVITY_OUT, hasActivityOut)
+        }
+    }
+
+    override fun logFull(row: TableRowLogger) {
+        row.logChange(COL_ACTIVITY_IN, hasActivityIn)
+        row.logChange(COL_ACTIVITY_OUT, hasActivityOut)
+    }
+}
+
+const val ACTIVITY_PREFIX = "wifiActivity"
+private const val COL_ACTIVITY_IN = "in"
+private const val COL_ACTIVITY_OUT = "out"
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 d84cbcc..6875b52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -120,6 +120,7 @@
                 @Override
                 public void onUserChanged(int newUser, @NonNull Context userContext) {
                     mCurrentUserId = newUser;
+                    updateClock();
                 }
             };
 
@@ -190,7 +191,6 @@
             filter.addAction(Intent.ACTION_TIME_CHANGED);
             filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
             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.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
index b234e9c..63b9ff9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NextAlarmControllerImpl.java
@@ -28,11 +28,14 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.dump.DumpManager;
+import com.android.systemui.settings.UserTracker;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.concurrent.Executor;
 
 import javax.inject.Inject;
 
@@ -45,22 +48,34 @@
 
     private final ArrayList<NextAlarmChangeCallback> mChangeCallbacks = new ArrayList<>();
 
+    private final UserTracker mUserTracker;
     private AlarmManager mAlarmManager;
     private AlarmManager.AlarmClockInfo mNextAlarm;
 
+    private final UserTracker.Callback mUserChangedCallback =
+            new UserTracker.Callback() {
+                @Override
+                public void onUserChanged(int newUser, @NonNull Context userContext) {
+                    updateNextAlarm();
+                }
+            };
+
     /**
      */
     @Inject
     public NextAlarmControllerImpl(
+            @Main Executor mainExecutor,
             AlarmManager alarmManager,
             BroadcastDispatcher broadcastDispatcher,
-            DumpManager dumpManager) {
+            DumpManager dumpManager,
+            UserTracker userTracker) {
         dumpManager.registerDumpable("NextAlarmController", this);
         mAlarmManager = alarmManager;
+        mUserTracker = userTracker;
         IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_USER_SWITCHED);
         filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);
         broadcastDispatcher.registerReceiver(this, filter, null, UserHandle.ALL);
+        mUserTracker.addCallback(mUserChangedCallback, mainExecutor);
         updateNextAlarm();
     }
 
@@ -98,14 +113,13 @@
 
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
-        if (action.equals(Intent.ACTION_USER_SWITCHED)
-                || action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
+        if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) {
             updateNextAlarm();
         }
     }
 
     private void updateNextAlarm() {
-        mNextAlarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);
+        mNextAlarm = mAlarmManager.getNextAlarmClock(mUserTracker.getUserId());
         fireNextAlarmChanged();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt b/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
deleted file mode 100644
index f558fee..0000000
--- a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/MultiRippleView.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.surfaceeffects.ripple
-
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.util.AttributeSet
-import android.util.Log
-import android.view.View
-
-/**
- * A view that allows multiple ripples to play.
- *
- * Use [MultiRippleController] to play ripple animations.
- */
-class MultiRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
-
-    internal val ripples = ArrayList<RippleAnimation>()
-    private val listeners = ArrayList<RipplesFinishedListener>()
-    private val ripplePaint = Paint()
-    private var isWarningLogged = false
-
-    companion object {
-        private const val TAG = "MultiRippleView"
-
-        interface RipplesFinishedListener {
-            /** Triggered when all the ripples finish running. */
-            fun onRipplesFinish()
-        }
-    }
-
-    fun addRipplesFinishedListener(listener: RipplesFinishedListener) {
-        listeners.add(listener)
-    }
-
-    override fun onDraw(canvas: Canvas?) {
-        if (canvas == null || !canvas.isHardwareAccelerated) {
-            // Drawing with the ripple shader requires hardware acceleration, so skip
-            // if it's unsupported.
-            if (!isWarningLogged) {
-                // Only log once to not spam.
-                Log.w(
-                    TAG,
-                    "Can't draw ripple shader. $canvas does not support hardware acceleration."
-                )
-                isWarningLogged = true
-            }
-            return
-        }
-
-        var shouldInvalidate = false
-
-        ripples.forEach { anim ->
-            ripplePaint.shader = anim.rippleShader
-            canvas.drawPaint(ripplePaint)
-
-            shouldInvalidate = shouldInvalidate || anim.isPlaying()
-        }
-
-        if (shouldInvalidate) {
-            invalidate()
-        } else { // Nothing is playing.
-            listeners.forEach { listener -> listener.onRipplesFinish() }
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt b/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt
deleted file mode 100644
index b2f8994..0000000
--- a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleAnimation.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.surfaceeffects.ripple
-
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ValueAnimator
-import androidx.core.graphics.ColorUtils
-
-/** A single ripple animation. */
-class RippleAnimation(private val config: RippleAnimationConfig) {
-    internal val rippleShader: RippleShader = RippleShader(config.rippleShape)
-    private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
-
-    init {
-        applyConfigToShader()
-    }
-
-    /** Updates the ripple color during the animation. */
-    fun updateColor(color: Int) {
-        config.apply { config.color = color }
-        applyConfigToShader()
-    }
-
-    @JvmOverloads
-    fun play(onAnimationEnd: Runnable? = null) {
-        if (isPlaying()) {
-            return // Ignore if ripple effect is already playing
-        }
-
-        animator.duration = config.duration
-        animator.addUpdateListener { updateListener ->
-            val now = updateListener.currentPlayTime
-            val progress = updateListener.animatedValue as Float
-            rippleShader.progress = progress
-            rippleShader.distortionStrength = if (config.shouldDistort) 1 - progress else 0f
-            rippleShader.time = now.toFloat()
-        }
-        animator.addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationEnd(animation: Animator?) {
-                    onAnimationEnd?.run()
-                }
-            }
-        )
-        animator.start()
-    }
-
-    /** Indicates whether the animation is playing. */
-    fun isPlaying(): Boolean = animator.isRunning
-
-    private fun applyConfigToShader() {
-        rippleShader.setCenter(config.centerX, config.centerY)
-        rippleShader.setMaxSize(config.maxWidth, config.maxHeight)
-        rippleShader.rippleFill = config.shouldFillRipple
-        rippleShader.pixelDensity = config.pixelDensity
-        rippleShader.color = ColorUtils.setAlphaComponent(config.color, config.opacity)
-        rippleShader.sparkleStrength = config.sparkleStrength
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt b/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
deleted file mode 100644
index a950d34..0000000
--- a/packages/SystemUI/src/com/android/systemui/surfaceeffects/ripple/RippleShader.kt
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.surfaceeffects.ripple
-
-import android.graphics.PointF
-import android.graphics.RuntimeShader
-import android.util.MathUtils
-import com.android.systemui.surfaceeffects.shaderutil.SdfShaderLibrary
-import com.android.systemui.surfaceeffects.shaderutil.ShaderUtilLibrary
-
-/**
- * Shader class that renders an expanding ripple effect. The ripple contains three elements:
- *
- * 1. an expanding filled [RippleShape] that appears in the beginning and quickly fades away
- * 2. an expanding ring that appears throughout the effect
- * 3. an expanding ring-shaped area that reveals noise over #2.
- *
- * The ripple shader will be default to the circle shape if not specified.
- *
- * Modeled after frameworks/base/graphics/java/android/graphics/drawable/RippleShader.java.
- */
-class RippleShader internal constructor(rippleShape: RippleShape = RippleShape.CIRCLE) :
-    RuntimeShader(buildShader(rippleShape)) {
-
-    /** Shapes that the [RippleShader] supports. */
-    enum class RippleShape {
-        CIRCLE,
-        ROUNDED_BOX,
-        ELLIPSE
-    }
-    // language=AGSL
-    companion object {
-        private const val SHADER_UNIFORMS =
-            """
-            uniform vec2 in_center;
-            uniform vec2 in_size;
-            uniform float in_progress;
-            uniform float in_cornerRadius;
-            uniform float in_thickness;
-            uniform float in_time;
-            uniform float in_distort_radial;
-            uniform float in_distort_xy;
-            uniform float in_fadeSparkle;
-            uniform float in_fadeFill;
-            uniform float in_fadeRing;
-            uniform float in_blur;
-            uniform float in_pixelDensity;
-            layout(color) uniform vec4 in_color;
-            uniform float in_sparkle_strength;
-        """
-
-        private const val SHADER_CIRCLE_MAIN =
-            """
-            vec4 main(vec2 p) {
-                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);
-                float radius = in_size.x * 0.5;
-                float sparkleRing = soften(circleRing(p_distorted-in_center, radius), in_blur);
-                float inside = soften(sdCircle(p_distorted-in_center, radius * 1.2), in_blur);
-                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
-                    * (1.-sparkleRing) * in_fadeSparkle;
-
-                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
-                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
-                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
-                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
-                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
-            }
-        """
-
-        private const val SHADER_ROUNDED_BOX_MAIN =
-            """
-            vec4 main(vec2 p) {
-                float sparkleRing = soften(roundedBoxRing(p-in_center, in_size, in_cornerRadius,
-                    in_thickness), in_blur);
-                float inside = soften(sdRoundedBox(p-in_center, in_size * 1.2, in_cornerRadius),
-                    in_blur);
-                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
-                    * (1.-sparkleRing) * in_fadeSparkle;
-
-                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
-                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
-                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
-                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
-                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
-            }
-        """
-
-        private const val SHADER_ELLIPSE_MAIN =
-            """
-            vec4 main(vec2 p) {
-                vec2 p_distorted = distort(p, in_time, in_distort_radial, in_distort_xy);
-
-                float sparkleRing = soften(ellipseRing(p_distorted-in_center, in_size), in_blur);
-                float inside = soften(sdEllipse(p_distorted-in_center, in_size * 1.2), in_blur);
-                float sparkle = sparkles(p - mod(p, in_pixelDensity * 0.8), in_time * 0.00175)
-                    * (1.-sparkleRing) * in_fadeSparkle;
-
-                float rippleInsideAlpha = (1.-inside) * in_fadeFill;
-                float rippleRingAlpha = (1.-sparkleRing) * in_fadeRing;
-                float rippleAlpha = max(rippleInsideAlpha, rippleRingAlpha) * in_color.a;
-                vec4 ripple = vec4(in_color.rgb, 1.0) * rippleAlpha;
-                return mix(ripple, vec4(sparkle), sparkle * in_sparkle_strength);
-            }
-        """
-
-        private const val CIRCLE_SHADER =
-            SHADER_UNIFORMS +
-                ShaderUtilLibrary.SHADER_LIB +
-                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
-                SdfShaderLibrary.CIRCLE_SDF +
-                SHADER_CIRCLE_MAIN
-        private const val ROUNDED_BOX_SHADER =
-            SHADER_UNIFORMS +
-                ShaderUtilLibrary.SHADER_LIB +
-                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
-                SdfShaderLibrary.ROUNDED_BOX_SDF +
-                SHADER_ROUNDED_BOX_MAIN
-        private const val ELLIPSE_SHADER =
-            SHADER_UNIFORMS +
-                ShaderUtilLibrary.SHADER_LIB +
-                SdfShaderLibrary.SHADER_SDF_OPERATION_LIB +
-                SdfShaderLibrary.ELLIPSE_SDF +
-                SHADER_ELLIPSE_MAIN
-
-        private fun buildShader(rippleShape: RippleShape): String =
-            when (rippleShape) {
-                RippleShape.CIRCLE -> CIRCLE_SHADER
-                RippleShape.ROUNDED_BOX -> ROUNDED_BOX_SHADER
-                RippleShape.ELLIPSE -> ELLIPSE_SHADER
-            }
-
-        private fun subProgress(start: Float, end: Float, progress: Float): Float {
-            val min = Math.min(start, end)
-            val max = Math.max(start, end)
-            val sub = Math.min(Math.max(progress, min), max)
-            return (sub - start) / (end - start)
-        }
-    }
-
-    /** Sets the center position of the ripple. */
-    fun setCenter(x: Float, y: Float) {
-        setFloatUniform("in_center", x, y)
-    }
-
-    /** Max width of the ripple. */
-    private var maxSize: PointF = PointF()
-    fun setMaxSize(width: Float, height: Float) {
-        maxSize.x = width
-        maxSize.y = height
-    }
-
-    /** Progress of the ripple. Float value between [0, 1]. */
-    var progress: Float = 0.0f
-        set(value) {
-            field = value
-            setFloatUniform("in_progress", value)
-            val curvedProg = 1 - (1 - value) * (1 - value) * (1 - value)
-
-            setFloatUniform(
-                "in_size",
-                /* width= */ maxSize.x * curvedProg,
-                /* height= */ maxSize.y * curvedProg
-            )
-            setFloatUniform("in_thickness", maxSize.y * curvedProg * 0.5f)
-            // radius should not exceed width and height values.
-            setFloatUniform("in_cornerRadius", Math.min(maxSize.x, maxSize.y) * curvedProg)
-
-            setFloatUniform("in_blur", MathUtils.lerp(1.25f, 0.5f, value))
-
-            val fadeIn = subProgress(0f, 0.1f, value)
-            val fadeOutNoise = subProgress(0.4f, 1f, value)
-            var fadeOutRipple = 0f
-            var fadeFill = 0f
-            if (!rippleFill) {
-                fadeFill = subProgress(0f, 0.6f, value)
-                fadeOutRipple = subProgress(0.3f, 1f, value)
-            }
-            setFloatUniform("in_fadeSparkle", Math.min(fadeIn, 1 - fadeOutNoise))
-            setFloatUniform("in_fadeFill", 1 - fadeFill)
-            setFloatUniform("in_fadeRing", Math.min(fadeIn, 1 - fadeOutRipple))
-        }
-
-    /** Play time since the start of the effect. */
-    var time: Float = 0.0f
-        set(value) {
-            field = value
-            setFloatUniform("in_time", value)
-        }
-
-    /** A hex value representing the ripple color, in the format of ARGB */
-    var color: Int = 0xffffff
-        set(value) {
-            field = value
-            setColorUniform("in_color", value)
-        }
-
-    /**
-     * Noise sparkle intensity. Expected value between [0, 1]. The sparkle is white, and thus with
-     * strength 0 it's transparent, leaving the ripple fully smooth, while with strength 1 it's
-     * opaque white and looks the most grainy.
-     */
-    var sparkleStrength: Float = 0.0f
-        set(value) {
-            field = value
-            setFloatUniform("in_sparkle_strength", value)
-        }
-
-    /** Distortion strength of the ripple. Expected value between[0, 1]. */
-    var distortionStrength: Float = 0.0f
-        set(value) {
-            field = value
-            setFloatUniform("in_distort_radial", 75 * progress * value)
-            setFloatUniform("in_distort_xy", 75 * value)
-        }
-
-    var pixelDensity: Float = 1.0f
-        set(value) {
-            field = value
-            setFloatUniform("in_pixelDensity", value)
-        }
-
-    /**
-     * True if the ripple should stayed filled in as it expands to give a filled-in circle effect.
-     * False for a ring effect.
-     */
-    var rippleFill: Boolean = false
-}
diff --git a/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt b/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
deleted file mode 100644
index 8649d59..0000000
--- a/packages/SystemUI/src/com/android/systemui/surfaceeffects/turbulencenoise/TurbulenceNoiseView.kt
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.surfaceeffects.turbulencenoise
-
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.ValueAnimator
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Paint
-import android.util.AttributeSet
-import android.view.View
-import androidx.annotation.VisibleForTesting
-import androidx.core.graphics.ColorUtils
-import java.util.Random
-import kotlin.math.sin
-
-/** View that renders turbulence noise effect. */
-class TurbulenceNoiseView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
-
-    companion object {
-        private const val MS_TO_SEC = 0.001f
-        private const val TWO_PI = Math.PI.toFloat() * 2f
-    }
-
-    @VisibleForTesting val turbulenceNoiseShader = TurbulenceNoiseShader()
-    private val paint = Paint().apply { this.shader = turbulenceNoiseShader }
-    private val random = Random()
-    private val animator: ValueAnimator = ValueAnimator.ofFloat(0f, 1f)
-    private var config: TurbulenceNoiseAnimationConfig? = null
-
-    val isPlaying: Boolean
-        get() = animator.isRunning
-
-    init {
-        // Only visible during the animation.
-        visibility = INVISIBLE
-    }
-
-    /** Updates the color during the animation. No-op if there's no animation playing. */
-    fun updateColor(color: Int) {
-        config?.let {
-            it.color = color
-            applyConfig(it)
-        }
-    }
-
-    override fun onDraw(canvas: Canvas?) {
-        if (canvas == null || !canvas.isHardwareAccelerated) {
-            // Drawing with the turbulence noise shader requires hardware acceleration, so skip
-            // if it's unsupported.
-            return
-        }
-
-        canvas.drawPaint(paint)
-    }
-
-    internal fun play(config: TurbulenceNoiseAnimationConfig) {
-        if (isPlaying) {
-            return // Ignore if the animation is playing.
-        }
-        visibility = VISIBLE
-        applyConfig(config)
-
-        // Add random offset to avoid same patterned noise.
-        val offsetX = random.nextFloat()
-        val offsetY = random.nextFloat()
-
-        animator.duration = config.duration.toLong()
-        animator.addUpdateListener { updateListener ->
-            val timeInSec = updateListener.currentPlayTime * MS_TO_SEC
-            // Remap [0,1] to [0, 2*PI]
-            val progress = TWO_PI * updateListener.animatedValue as Float
-
-            turbulenceNoiseShader.setNoiseMove(
-                offsetX + timeInSec * config.noiseMoveSpeedX,
-                offsetY + timeInSec * config.noiseMoveSpeedY,
-                timeInSec * config.noiseMoveSpeedZ
-            )
-
-            // Fade in and out the noise as the animation progress.
-            // TODO: replace it with a better curve
-            turbulenceNoiseShader.setOpacity(sin(TWO_PI - progress) * config.luminosityMultiplier)
-
-            invalidate()
-        }
-
-        animator.addListener(
-            object : AnimatorListenerAdapter() {
-                override fun onAnimationEnd(animation: Animator) {
-                    visibility = INVISIBLE
-                    config.onAnimationEnd?.run()
-                }
-            }
-        )
-        animator.start()
-    }
-
-    private fun applyConfig(config: TurbulenceNoiseAnimationConfig) {
-        this.config = config
-        with(turbulenceNoiseShader) {
-            setGridCount(config.gridCount)
-            setColor(ColorUtils.setAlphaComponent(config.color, config.opacity))
-            setBackgroundColor(config.backgroundColor)
-            setSize(config.width, config.height)
-            setPixelDensity(config.pixelDensity)
-        }
-        paint.blendMode = config.blendMode
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index ae30ca0..162c915 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -22,6 +22,8 @@
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener
 import android.hardware.display.DisplayManager
 import android.hardware.input.InputManager
+import android.os.Handler
+import android.os.Looper
 import android.os.Trace
 import android.view.Choreographer
 import android.view.Display
@@ -32,6 +34,7 @@
 import android.view.SurfaceSession
 import android.view.WindowManager
 import android.view.WindowlessWindowManager
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dagger.qualifiers.UiBackground
 import com.android.systemui.statusbar.LightRevealEffect
@@ -40,6 +43,7 @@
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
 import com.android.systemui.unfold.updates.RotationChangeProvider
 import com.android.systemui.unfold.util.ScaleAwareTransitionProgressProvider.Companion.areAnimationsEnabled
+import com.android.systemui.util.Assert.isMainThread
 import com.android.systemui.util.traceSection
 import com.android.wm.shell.displayareahelper.DisplayAreaHelper
 import java.util.Optional
@@ -59,6 +63,7 @@
     private val displayAreaHelper: Optional<DisplayAreaHelper>,
     @Main private val executor: Executor,
     @UiBackground private val backgroundExecutor: Executor,
+    @Background private val bgHandler: Handler,
     private val rotationChangeProvider: RotationChangeProvider,
 ) {
 
@@ -120,11 +125,11 @@
         try {
             // Add the view only if we are unfolding and this is the first screen on
             if (!isFolded && !isUnfoldHandled && contentResolver.areAnimationsEnabled()) {
-                addView(onOverlayReady)
+                executeInBackground { addView(onOverlayReady) }
                 isUnfoldHandled = true
             } else {
                 // No unfold transition, immediately report that overlay is ready
-                ensureOverlayRemoved()
+                executeInBackground { ensureOverlayRemoved() }
                 onOverlayReady.run()
             }
         } finally {
@@ -139,6 +144,7 @@
             return
         }
 
+        ensureInBackground()
         ensureOverlayRemoved()
 
         val newRoot = SurfaceControlViewHost(context, context.display!!, wwm)
@@ -152,7 +158,7 @@
         val params = getLayoutParams()
         newRoot.setView(newView, params)
 
-        onOverlayReady?.let { callback ->
+        if (onOverlayReady != null) {
             Trace.beginAsyncSection("UnfoldLightRevealOverlayAnimation#relayout", 0)
 
             newRoot.relayout(params) { transaction ->
@@ -170,7 +176,7 @@
                     .setFrameTimelineVsync(vsyncId + 1)
                     .addTransactionCommittedListener(backgroundExecutor) {
                         Trace.endAsyncSection("UnfoldLightRevealOverlayAnimation#relayout", 0)
-                        callback.run()
+                        onOverlayReady.run()
                     }
                     .apply()
             }
@@ -213,9 +219,12 @@
     }
 
     private fun ensureOverlayRemoved() {
-        root?.release()
-        root = null
-        scrimView = null
+        ensureInBackground()
+        traceSection("ensureOverlayRemoved") {
+            root?.release()
+            root = null
+            scrimView = null
+        }
     }
 
     private fun getUnfoldedDisplayInfo(): DisplayInfo =
@@ -228,17 +237,17 @@
     private inner class TransitionListener : TransitionProgressListener {
 
         override fun onTransitionProgress(progress: Float) {
-            scrimView?.revealAmount = progress
+            executeInBackground { scrimView?.revealAmount = progress }
         }
 
         override fun onTransitionFinished() {
-            ensureOverlayRemoved()
+            executeInBackground { ensureOverlayRemoved() }
         }
 
         override fun onTransitionStarted() {
             // Add view for folding case (when unfolding the view is added earlier)
             if (scrimView == null) {
-                addView()
+                executeInBackground { addView() }
             }
             // Disable input dispatching during transition.
             InputManager.getInstance().cancelCurrentTouch()
@@ -250,19 +259,35 @@
             traceSection("UnfoldLightRevealOverlayAnimation#onRotationChanged") {
                 if (currentRotation != newRotation) {
                     currentRotation = newRotation
-                    scrimView?.revealEffect = createLightRevealEffect()
-                    root?.relayout(getLayoutParams())
+                    executeInBackground {
+                        scrimView?.revealEffect = createLightRevealEffect()
+                        root?.relayout(getLayoutParams())
+                    }
                 }
             }
         }
     }
 
+    private fun executeInBackground(f: () -> Unit) {
+        ensureInMainThread()
+        // The UiBackground executor is not used as it doesn't have a prepared looper.
+        bgHandler.post(f)
+    }
+
+    private fun ensureInBackground() {
+        check(Looper.myLooper() == bgHandler.looper) { "Not being executed in the background!" }
+    }
+
+    private fun ensureInMainThread() {
+        isMainThread()
+    }
+
     private inner class FoldListener :
         FoldStateListener(
             context,
             Consumer { isFolded ->
                 if (isFolded) {
-                    ensureOverlayRemoved()
+                    executeInBackground { ensureOverlayRemoved() }
                     isUnfoldHandled = false
                 }
                 this.isFolded = isFolded
diff --git a/packages/SystemUI/src/com/android/systemui/user/UserModule.java b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
index 0c72b78..2b29885 100644
--- a/packages/SystemUI/src/com/android/systemui/user/UserModule.java
+++ b/packages/SystemUI/src/com/android/systemui/user/UserModule.java
@@ -17,6 +17,7 @@
 package com.android.systemui.user;
 
 import android.app.Activity;
+import android.os.UserHandle;
 
 import com.android.settingslib.users.EditUserInfoController;
 import com.android.systemui.user.data.repository.UserRepositoryModule;
@@ -51,4 +52,22 @@
     @IntoMap
     @ClassKey(UserSwitcherActivity.class)
     public abstract Activity provideUserSwitcherActivity(UserSwitcherActivity activity);
+
+    /**
+     * Provides the {@link UserHandle} for the user associated with this System UI process.
+     *
+     * <p>Note that this is static and unchanging for the life-time of the process we are running
+     * in. It can be <i>different</i> from the user that is the currently-selected user, which may
+     * be associated with a different System UI process.
+     *
+     * <p>For example, the System UI process which creates all the windows and renders UI is always
+     * the one associated with the primary user on the device. However, if the user is switched to
+     * another, non-primary user (for example user "X"), then a secondary System UI process will be
+     * spawned. While the original primary user process continues to be the only one rendering UI,
+     * the new system UI process may be used for things like file or content access.
+     */
+    @Provides
+    public static UserHandle provideUserHandle() {
+        return new UserHandle(UserHandle.myUserId());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
index 4c9b8e4..c0f0390 100644
--- a/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/data/repository/UserRepository.kt
@@ -242,7 +242,15 @@
             val isUserSwitcherEnabled =
                 globalSettings.getIntForUser(
                     Settings.Global.USER_SWITCHER_ENABLED,
-                    0,
+                    if (
+                        appContext.resources.getBoolean(
+                            com.android.internal.R.bool.config_showUserSwitcherByDefault
+                        )
+                    ) {
+                        1
+                    } else {
+                        0
+                    },
                     UserHandle.USER_SYSTEM,
                 ) != 0
 
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
index c5b697c..512fadf 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/interactor/UserInteractor.kt
@@ -114,9 +114,9 @@
 
     private val callbackMutex = Mutex()
     private val callbacks = mutableSetOf<UserCallback>()
-    private val userInfos =
-        combine(repository.userSwitcherSettings, repository.userInfos) { settings, userInfos ->
-            userInfos.filter { !it.isGuest || canCreateGuestUser(settings) }.filter { it.isFull }
+    private val userInfos: Flow<List<UserInfo>> =
+        repository.userInfos.map { userInfos ->
+            userInfos.filter { it.isFull }
         }
 
     /** List of current on-device users to select from. */
@@ -493,7 +493,7 @@
 
     fun showUserSwitcher(context: Context, expandable: Expandable) {
         if (!featureFlags.isEnabled(Flags.FULL_SCREEN_USER_SWITCHER)) {
-            showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog)
+            showDialog(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable))
             return
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt
index 85c2964..14cc3e7 100644
--- a/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/domain/model/ShowDialogRequestModel.kt
@@ -18,11 +18,13 @@
 package com.android.systemui.user.domain.model
 
 import android.os.UserHandle
+import com.android.systemui.animation.Expandable
 import com.android.systemui.qs.user.UserSwitchDialogController
 
 /** Encapsulates a request to show a dialog. */
 sealed class ShowDialogRequestModel(
     open val dialogShower: UserSwitchDialogController.DialogShower? = null,
+    open val expandable: Expandable? = null,
 ) {
     data class ShowAddUserDialog(
         val userHandle: UserHandle,
@@ -45,5 +47,7 @@
     ) : ShowDialogRequestModel(dialogShower)
 
     /** Show the user switcher dialog */
-    object ShowUserSwitcherDialog : ShowDialogRequestModel()
+    data class ShowUserSwitcherDialog(
+        override val expandable: Expandable?,
+    ) : ShowDialogRequestModel()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/DialogShowerImpl.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/DialogShowerImpl.kt
new file mode 100644
index 0000000..3fe2a7b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/DialogShowerImpl.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.user.ui.dialog
+
+import android.app.Dialog
+import android.content.DialogInterface
+import com.android.systemui.animation.DialogCuj
+import com.android.systemui.animation.DialogLaunchAnimator
+import com.android.systemui.qs.user.UserSwitchDialogController.DialogShower
+
+/** Extracted from [UserSwitchDialogController] */
+class DialogShowerImpl(
+    private val animateFrom: Dialog,
+    private val dialogLaunchAnimator: DialogLaunchAnimator,
+) : DialogInterface by animateFrom, DialogShower {
+    override fun showDialog(dialog: Dialog, cuj: DialogCuj) {
+        dialogLaunchAnimator.showFromDialog(dialog, animateFrom = animateFrom, cuj)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitchDialog.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitchDialog.kt
index ed25898..b8ae257 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitchDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitchDialog.kt
@@ -60,6 +60,7 @@
         setView(gridFrame)
 
         adapter.linkToViewGroup(gridFrame.findViewById(R.id.grid))
+        adapter.injectDialogShower(DialogShowerImpl(this, dialogLaunchAnimator))
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt
index 4141054..d451230 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/dialog/UserSwitcherDialogCoordinator.kt
@@ -133,7 +133,10 @@
                     }
                 currentDialog = dialog
 
-                if (request.dialogShower != null && dialogCuj != null) {
+                val controller = request.expandable?.dialogLaunchController(dialogCuj)
+                if (controller != null) {
+                    dialogLaunchAnimator.get().show(dialog, controller)
+                } else if (request.dialogShower != null && dialogCuj != null) {
                     request.dialogShower?.showDialog(dialog, dialogCuj)
                 } else {
                     dialog.show()
diff --git a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
index 0910ea3..37115ad 100644
--- a/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModel.kt
@@ -19,6 +19,8 @@
 
 import androidx.lifecycle.ViewModel
 import androidx.lifecycle.ViewModelProvider
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.Text
 import com.android.systemui.common.ui.drawable.CircularDrawable
 import com.android.systemui.power.domain.interactor.PowerInteractor
 import com.android.systemui.user.domain.interactor.GuestUserInteractor
@@ -144,7 +146,12 @@
     ): UserViewModel {
         return UserViewModel(
             viewKey = model.id,
-            name = model.name,
+            name =
+                if (model.isGuest && model.isSelected) {
+                    Text.Resource(R.string.guest_exit_quick_settings_button)
+                } else {
+                    model.name
+                },
             image = CircularDrawable(model.image),
             isSelectionMarkerVisible = model.isSelected,
             alpha =
diff --git a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
index 5b16ae9..b311318 100644
--- a/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/TraceUtils.kt
@@ -22,11 +22,22 @@
  * Run a block within a [Trace] section.
  * Calls [Trace.beginSection] before and [Trace.endSection] after the passed block.
  */
-inline fun <T> traceSection(tag: String, block: () -> T): T {
-    Trace.beginSection(tag)
-    try {
-        return block()
-    } finally {
-        Trace.endSection()
+inline fun <T> traceSection(tag: String, block: () -> T): T =
+        if (Trace.isTagEnabled(Trace.TRACE_TAG_APP)) {
+            Trace.traceBegin(Trace.TRACE_TAG_APP, tag)
+            try {
+                block()
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_APP)
+            }
+        } else {
+            block()
+        }
+
+class TraceUtils {
+    companion object {
+        inline fun traceRunnable(tag: String, crossinline block: () -> Unit): Runnable {
+            return Runnable { traceSection(tag) { block() } }
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index f71d596..b61b2e6 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -20,7 +20,6 @@
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.onStart
@@ -58,6 +57,22 @@
     onStart { emit(initialValue) }.pairwiseBy(transform)
 
 /**
+ * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
+ *
+ *
+ * The output of [getInitialValue] will be used as the "old" value for the first emission. As
+ * opposed to the initial value in the above [pairwiseBy], [getInitialValue] can do some work before
+ * returning the initial value.
+ *
+ * Useful for code that needs to compare the current value to the previous value.
+ */
+fun <T, R> Flow<T>.pairwiseBy(
+    getInitialValue: suspend () -> T,
+    transform: suspend (previousValue: T, newValue: T) -> R,
+): Flow<R> =
+    onStart { emit(getInitialValue()) }.pairwiseBy(transform)
+
+/**
  * Returns a new [Flow] that produces the two most recent emissions from [this]. Note that the new
  * Flow will not start emitting until it has received two emissions from the upstream Flow.
  *
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
index 33c00fb..9349966 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogControllerImpl.java
@@ -432,6 +432,11 @@
                             AudioManager.DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
                             AudioManager.DEVICE_OUT_BLE_HEADSET)) != 0;
             changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
+        } else if (stream == AudioManager.STREAM_VOICE_CALL) {
+            final boolean routedToBluetooth =
+                    (mAudio.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)
+                            & AudioManager.DEVICE_OUT_BLE_HEADSET) != 0;
+            changed |= updateStreamRoutedToBluetoothW(stream, routedToBluetooth);
         }
         return changed;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 833a6a4..1bc0d08 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1771,6 +1771,7 @@
         if (ss.level == row.requestedLevel) {
             row.requestedLevel = -1;
         }
+        final boolean isVoiceCallStream = row.stream == AudioManager.STREAM_VOICE_CALL;
         final boolean isA11yStream = row.stream == STREAM_ACCESSIBILITY;
         final boolean isRingStream = row.stream == AudioManager.STREAM_RING;
         final boolean isSystemStream = row.stream == AudioManager.STREAM_SYSTEM;
@@ -1815,8 +1816,12 @@
         } else if (isRingSilent || zenMuted) {
             iconRes = row.iconMuteRes;
         } else if (ss.routedToBluetooth) {
-            iconRes = isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute
-                                        : R.drawable.ic_volume_media_bt;
+            if (isVoiceCallStream) {
+                iconRes = R.drawable.ic_volume_bt_sco;
+            } else {
+                iconRes = isStreamMuted(ss) ? R.drawable.ic_volume_media_bt_mute
+                                            : R.drawable.ic_volume_media_bt;
+            }
         } else if (isStreamMuted(ss)) {
             iconRes = ss.muted ? R.drawable.ic_volume_media_off : row.iconMuteRes;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
index ad97ef4..5df4a5b 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpapers/ImageWallpaper.java
@@ -29,6 +29,7 @@
 import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.Looper;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -102,6 +103,15 @@
     }
 
     @Override
+    public Looper onProvideEngineLooper() {
+        // Receive messages on mWorker thread instead of SystemUI's main handler.
+        // All other wallpapers have their own process, and they can receive messages on their own
+        // main handler without any delay. But since ImageWallpaper lives in SystemUI, performance
+        // of the image wallpaper could be negatively affected when SystemUI's main handler is busy.
+        return mWorker != null ? mWorker.getLooper() : super.onProvideEngineLooper();
+    }
+
+    @Override
     public void onCreate() {
         super.onCreate();
         mWorker = new HandlerThread(TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index a4384d5..7033ccd 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -549,7 +549,7 @@
         } catch (RemoteException e) {
             Log.e(TAG, e.getMessage());
         }
-        mShadeController.collapsePanel(true);
+        mShadeController.collapseShade(true);
         if (entry.getRow() != null) {
             entry.getRow().updateBubbleButton();
         }
@@ -597,7 +597,7 @@
         }
 
         if (shouldBubble) {
-            mShadeController.collapsePanel(true);
+            mShadeController.collapseShade(true);
             if (entry.getRow() != null) {
                 entry.getRow().updateBubbleButton();
             }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
index 8839662..fa8c8982 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardListenQueueTest.kt
@@ -63,7 +63,6 @@
     credentialAttempted = false,
     deviceInteractive = false,
     dreaming = false,
-    encryptedOrLockdown = false,
     fingerprintDisabled = false,
     fingerprintLockedOut = false,
     goingToSleep = false,
@@ -74,6 +73,7 @@
     primaryUser = false,
     shouldListenSfpsState = false,
     shouldListenForFingerprintAssistant = false,
+    strongerAuthRequired = false,
     switchingUser = false,
     udfps = false,
     userDoesNotHaveTrust = false
@@ -87,17 +87,17 @@
     biometricSettingEnabledForUser = false,
     bouncerFullyShown = false,
     faceAndFpNotAuthenticated = false,
+    faceAuthAllowed = true,
     faceDisabled = false,
     faceLockedOut = false,
-    fpLockedOut = false,
     goingToSleep = false,
     keyguardAwake = false,
     keyguardGoingAway = false,
     listeningForFaceAssistant = false,
     occludingAppRequestingFaceAuth = false,
     primaryUser = false,
-    scanningAllowedByStrongAuth = false,
     secureCameraLaunched = false,
+    supportsDetect = true,
     switchingUser = false,
     udfpsBouncerShowing = false,
     udfpsFingerDown = false,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index 4d58b09..84f6d91 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -379,9 +379,9 @@
     }
 
     @Test
-    public void onBouncerVisibilityChanged_needsStrongAuth_sideFpsHintHidden() {
+    public void onBouncerVisibilityChanged_unlockingWithFingerprintNotAllowed_sideFpsHintHidden() {
         setupConditionsToEnableSideFpsHint();
-        setNeedsStrongAuth(true);
+        setUnlockingWithFingerprintAllowed(false);
         reset(mSideFpsController);
 
         mKeyguardSecurityContainerController.onBouncerVisibilityChanged(View.VISIBLE);
@@ -558,11 +558,40 @@
         configurationListenerArgumentCaptor.getValue().onDensityOrFontScaleChanged();
 
         verify(mView).onDensityOrFontScaleChanged();
-        verify(mKeyguardSecurityViewFlipperController).onDensityOrFontScaleChanged();
+        verify(mKeyguardSecurityViewFlipperController).clearViews();
         verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
                 any(KeyguardSecurityCallback.class));
     }
 
+    @Test
+    public void onThemeChanged() {
+        ArgumentCaptor<ConfigurationController.ConfigurationListener>
+                configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
+                ConfigurationController.ConfigurationListener.class);
+        mKeyguardSecurityContainerController.onViewAttached();
+        verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+        configurationListenerArgumentCaptor.getValue().onThemeChanged();
+
+        verify(mView).reloadColors();
+        verify(mKeyguardSecurityViewFlipperController).clearViews();
+        verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
+                any(KeyguardSecurityCallback.class));
+    }
+
+    @Test
+    public void onUiModeChanged() {
+        ArgumentCaptor<ConfigurationController.ConfigurationListener>
+                configurationListenerArgumentCaptor = ArgumentCaptor.forClass(
+                ConfigurationController.ConfigurationListener.class);
+        mKeyguardSecurityContainerController.onViewAttached();
+        verify(mConfigurationController).addCallback(configurationListenerArgumentCaptor.capture());
+        configurationListenerArgumentCaptor.getValue().onUiModeChanged();
+
+        verify(mView).reloadColors();
+        verify(mKeyguardSecurityViewFlipperController).clearViews();
+        verify(mKeyguardSecurityViewFlipperController).getSecurityView(any(SecurityMode.class),
+                any(KeyguardSecurityCallback.class));
+    }
 
     private KeyguardSecurityContainer.SwipeListener getRegisteredSwipeListener() {
         mKeyguardSecurityContainerController.onViewAttached();
@@ -574,7 +603,7 @@
         attachView();
         setSideFpsHintEnabledFromResources(true);
         setFingerprintDetectionRunning(true);
-        setNeedsStrongAuth(false);
+        setUnlockingWithFingerprintAllowed(true);
     }
 
     private void attachView() {
@@ -593,9 +622,8 @@
                 enabled);
     }
 
-    private void setNeedsStrongAuth(boolean needed) {
-        when(mKeyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(needed);
-        mKeyguardUpdateMonitorCallback.getValue().onStrongAuthStateChanged(/* userId= */ 0);
+    private void setUnlockingWithFingerprintAllowed(boolean allowed) {
+        when(mKeyguardUpdateMonitor.isUnlockingWithFingerprintAllowed()).thenReturn(allowed);
     }
 
     private void setupGetSecurityView() {
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
index fd02ac9..1614b57 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityViewFlipperControllerTest.java
@@ -109,7 +109,7 @@
 
     @Test
     public void onDensityOrFontScaleChanged() {
-        mKeyguardSecurityViewFlipperController.onDensityOrFontScaleChanged();
+        mKeyguardSecurityViewFlipperController.clearViews();
         verify(mView).removeAllViews();
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 7231b34..002da55 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -27,7 +27,9 @@
 
 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_BOOT;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN;
 import static com.android.keyguard.FaceAuthApiRequestReason.NOTIFICATION_PANEL_CLICKED;
+import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_STATE_CANCELLING_RESTARTING;
 import static com.android.keyguard.KeyguardUpdateMonitor.DEFAULT_CANCEL_SIGNAL_TIMEOUT;
 import static com.android.keyguard.KeyguardUpdateMonitor.getCurrentUser;
 
@@ -100,6 +102,8 @@
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
+import androidx.annotation.NonNull;
+
 import com.android.dx.mockito.inline.extended.ExtendedMockito;
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.internal.logging.InstanceId;
@@ -266,21 +270,8 @@
 
         // IBiometricsFace@1.0 does not support detection, only authentication.
         when(mFaceSensorProperties.isEmpty()).thenReturn(false);
-
-        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
-        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
-                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
-                "00000001" /* serialNumber */, "" /* softwareVersion */));
-        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
-                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
-                "vendor/version/revision" /* softwareVersion */));
-
-        when(mFaceSensorProperties.get(anyInt())).thenReturn(new FaceSensorPropertiesInternal(
-                0 /* id */,
-                FaceSensorProperties.STRENGTH_STRONG, 1 /* maxTemplatesAllowed */,
-                componentInfo, FaceSensorProperties.TYPE_UNKNOWN,
-                false /* supportsFaceDetection */, true /* supportsSelfIllumination */,
-                false /* resetLockoutRequiresChallenge */));
+        when(mFaceSensorProperties.get(anyInt())).thenReturn(
+                createFaceSensorProperties(/* supportsFaceDetection = */ false));
 
         when(mFingerprintManager.isHardwareDetected()).thenReturn(true);
         when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
@@ -354,6 +345,28 @@
         when(mAuthController.areAllFingerprintAuthenticatorsRegistered()).thenReturn(true);
     }
 
+    @NonNull
+    private FaceSensorPropertiesInternal createFaceSensorProperties(boolean supportsFaceDetection) {
+        final List<ComponentInfoInternal> componentInfo = new ArrayList<>();
+        componentInfo.add(new ComponentInfoInternal("faceSensor" /* componentId */,
+                "vendor/model/revision" /* hardwareVersion */, "1.01" /* firmwareVersion */,
+                "00000001" /* serialNumber */, "" /* softwareVersion */));
+        componentInfo.add(new ComponentInfoInternal("matchingAlgorithm" /* componentId */,
+                "" /* hardwareVersion */, "" /* firmwareVersion */, "" /* serialNumber */,
+                "vendor/version/revision" /* softwareVersion */));
+
+
+        return new FaceSensorPropertiesInternal(
+                0 /* id */,
+                FaceSensorProperties.STRENGTH_STRONG,
+                1 /* maxTemplatesAllowed */,
+                componentInfo,
+                FaceSensorProperties.TYPE_UNKNOWN,
+                supportsFaceDetection /* supportsFaceDetection */,
+                true /* supportsSelfIllumination */,
+                false /* resetLockoutRequiresChallenge */);
+    }
+
     @After
     public void tearDown() {
         if (mMockitoSession != null) {
@@ -594,30 +607,13 @@
     }
 
     @Test
-    public void testFingerprintDoesNotAuth_whenEncrypted() {
-        testFingerprintWhenStrongAuth(
-                STRONG_AUTH_REQUIRED_AFTER_BOOT);
-    }
-
-    @Test
-    public void testFingerprintDoesNotAuth_whenDpmLocked() {
-        testFingerprintWhenStrongAuth(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW);
-    }
-
-    @Test
-    public void testFingerprintDoesNotAuth_whenUserLockdown() {
-        testFingerprintWhenStrongAuth(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
-    }
-
-    private void testFingerprintWhenStrongAuth(int strongAuth) {
+    public void testOnlyDetectFingerprint_whenFingerprintUnlockNotAllowed() {
         // Clear invocations, since previous setup (e.g. registering BiometricManager callbacks)
         // will trigger updateBiometricListeningState();
         clearInvocations(mFingerprintManager);
         mKeyguardUpdateMonitor.resetBiometricListeningState();
 
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
         mKeyguardUpdateMonitor.dispatchStartedGoingToSleep(0 /* why */);
         mTestableLooper.processAllMessages();
 
@@ -626,6 +622,64 @@
     }
 
     @Test
+    public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricAllowed() {
+        // GIVEN unlocking with biometric is allowed
+        strongAuthNotRequired();
+
+        // THEN unlocking with face and fp is allowed
+        Assert.assertTrue(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FACE));
+        Assert.assertTrue(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FINGERPRINT));
+    }
+
+    @Test
+    public void testUnlockingWithFaceAllowed_strongAuthTrackerUnlockingWithBiometricNotAllowed() {
+        // GIVEN unlocking with biometric is not allowed
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+
+        // THEN unlocking with face is not allowed
+        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FACE));
+    }
+
+    @Test
+    public void testUnlockingWithFaceAllowed_fingerprintLockout() {
+        // GIVEN unlocking with biometric is allowed
+        strongAuthNotRequired();
+
+        // WHEN fingerprint is locked out
+        fingerprintErrorLockedOut();
+
+        // THEN unlocking with face is not allowed
+        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FACE));
+    }
+
+    @Test
+    public void testUnlockingWithFpAllowed_strongAuthTrackerUnlockingWithBiometricNotAllowed() {
+        // GIVEN unlocking with biometric is not allowed
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+
+        // THEN unlocking with fingerprint is not allowed
+        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FINGERPRINT));
+    }
+
+    @Test
+    public void testUnlockingWithFpAllowed_fingerprintLockout() {
+        // GIVEN unlocking with biometric is allowed
+        strongAuthNotRequired();
+
+        // WHEN fingerprint is locked out
+        fingerprintErrorLockedOut();
+
+        // THEN unlocking with fingeprint is not allowed
+        Assert.assertFalse(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FINGERPRINT));
+    }
+
+    @Test
     public void testTriesToAuthenticate_whenBouncer() {
         setKeyguardBouncerVisibility(true);
 
@@ -669,10 +723,9 @@
     }
 
     @Test
-    public void skipsAuthentication_whenEncryptedKeyguard() {
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
-                STRONG_AUTH_REQUIRED_AFTER_BOOT);
-        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
+    public void skipsAuthentication_whenStrongAuthRequired_nonBypass() {
+        lockscreenBypassIsNotAllowed();
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         mTestableLooper.processAllMessages();
@@ -682,15 +735,48 @@
     }
 
     @Test
-    public void requiresAuthentication_whenEncryptedKeyguard_andBypass() {
-        testStrongAuthExceptOnBouncer(
-                STRONG_AUTH_REQUIRED_AFTER_BOOT);
+    public void faceDetect_whenStrongAuthRequiredAndBypass() {
+        // GIVEN bypass is enabled, face detection is supported and strong auth is required
+        lockscreenBypassIsAllowed();
+        supportsFaceDetection();
+        strongAuthRequiredEncrypted();
+        keyguardIsVisible();
+
+        // WHEN the device wakes up
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+
+        // FACE detect is triggered, not authenticate
+        verify(mFaceManager).detectFace(any(), any(), anyInt());
+        verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+                anyBoolean());
+
+        // WHEN bouncer becomes visible
+        setKeyguardBouncerVisibility(true);
+        clearInvocations(mFaceManager);
+
+        // THEN face scanning is not run
+        mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
+        verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+                anyBoolean());
+        verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
     }
 
     @Test
-    public void requiresAuthentication_whenTimeoutKeyguard_andBypass() {
-        testStrongAuthExceptOnBouncer(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_TIMEOUT);
+    public void noFaceDetect_whenStrongAuthRequiredAndBypass_faceDetectionUnsupported() {
+        // GIVEN bypass is enabled, face detection is NOT supported and strong auth is required
+        lockscreenBypassIsAllowed();
+        strongAuthRequiredEncrypted();
+        keyguardIsVisible();
+
+        // WHEN the device wakes up
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+
+        // FACE detect and authenticate are NOT triggered
+        verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
+        verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
+                anyBoolean());
     }
 
     @Test
@@ -723,24 +809,6 @@
         assertThat(didFaceAuthRun).isFalse();
     }
 
-    private void testStrongAuthExceptOnBouncer(int strongAuth) {
-        when(mKeyguardBypassController.canBypass()).thenReturn(true);
-        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(strongAuth);
-
-        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
-        mTestableLooper.processAllMessages();
-        keyguardIsVisible();
-        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
-
-        // Stop scanning when bouncer becomes visible
-        setKeyguardBouncerVisibility(true);
-        clearInvocations(mFaceManager);
-        mKeyguardUpdateMonitor.requestFaceAuth(FaceAuthApiRequestReason.UDFPS_POINTER_DOWN);
-        verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
-                anyBoolean());
-    }
-
     @Test
     public void testTriesToAuthenticate_whenAssistant() {
         mKeyguardUpdateMonitor.setKeyguardShowing(true, true);
@@ -751,10 +819,9 @@
 
     @Test
     public void testTriesToAuthenticate_whenTrustOnAgentKeyguard_ifBypass() {
-        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         mTestableLooper.processAllMessages();
-        when(mKeyguardBypassController.canBypass()).thenReturn(true);
+        lockscreenBypassIsAllowed();
         mKeyguardUpdateMonitor.onTrustChanged(true /* enabled */,
                 KeyguardUpdateMonitor.getCurrentUser(), 0 /* flags */,
                 new ArrayList<>());
@@ -774,26 +841,26 @@
     }
 
     @Test
-    public void testIgnoresAuth_whenLockdown() {
-        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
-        mTestableLooper.processAllMessages();
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+    public void testNoFaceAuth_whenLockDown() {
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        userDeviceLockDown();
 
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         keyguardIsVisible();
+        mTestableLooper.processAllMessages();
+
         verify(mFaceManager, never()).authenticate(any(), any(), any(), any(), anyInt(),
                 anyBoolean());
+        verify(mFaceManager, never()).detectFace(any(), any(), anyInt());
     }
 
     @Test
-    public void testTriesToAuthenticate_whenLockout() {
-        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
-        mTestableLooper.processAllMessages();
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
+    public void testFingerprintPowerPressed_restartsFingerprintListeningStateImmediately() {
+        mKeyguardUpdateMonitor.mFingerprintAuthenticationCallback
+                .onAuthenticationError(FingerprintManager.BIOMETRIC_ERROR_POWER_PRESSED, "");
 
-        keyguardIsVisible();
-        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+        verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+                anyInt());
     }
 
     @Test
@@ -928,10 +995,6 @@
                 faceLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
         final boolean fpLocked =
                 fingerprintLockoutMode != BiometricConstants.BIOMETRIC_LOCKOUT_NONE;
-        when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser)))
-                .thenReturn(fingerprintLockoutMode);
-        when(mFaceManager.getLockoutModeForUser(eq(FACE_SENSOR_ID), eq(newUser)))
-                .thenReturn(faceLockoutMode);
 
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
         mTestableLooper.processAllMessages();
@@ -941,6 +1004,10 @@
         verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
                 anyInt());
 
+        when(mFingerprintManager.getLockoutModeForUser(eq(FINGERPRINT_SENSOR_ID), eq(newUser)))
+                .thenReturn(fingerprintLockoutMode);
+        when(mFaceManager.getLockoutModeForUser(eq(FACE_SENSOR_ID), eq(newUser)))
+                .thenReturn(faceLockoutMode);
         final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
         final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal);
         mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
@@ -951,14 +1018,22 @@
         mKeyguardUpdateMonitor.handleUserSwitchComplete(newUser);
         mTestableLooper.processAllMessages();
 
-        verify(faceCancel, faceLocked ? times(1) : never()).cancel();
-        verify(fpCancel, fpLocked ? times(1) : never()).cancel();
-        verify(callback, faceLocked ? times(1) : never()).onBiometricRunningStateChanged(
+        // THEN face and fingerprint listening are always cancelled immediately
+        verify(faceCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
                 eq(false), eq(BiometricSourceType.FACE));
-        verify(callback, fpLocked ? times(1) : never()).onBiometricRunningStateChanged(
+        verify(fpCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
                 eq(false), eq(BiometricSourceType.FINGERPRINT));
+
+        // THEN locked out states are updated
         assertThat(mKeyguardUpdateMonitor.isFingerprintLockedOut()).isEqualTo(fpLocked);
         assertThat(mKeyguardUpdateMonitor.isFaceLockedOut()).isEqualTo(faceLocked);
+
+        // Fingerprint should be restarted once its cancelled bc on lockout, the device
+        // can still detectFingerprint (and if it's not locked out, fingerprint can listen)
+        assertThat(mKeyguardUpdateMonitor.mFingerprintRunningState)
+                .isEqualTo(BIOMETRIC_STATE_CANCELLING_RESTARTING);
     }
 
     @Test
@@ -1144,9 +1219,8 @@
         // GIVEN status bar state is on the keyguard
         mStatusBarStateListener.onStateChanged(StatusBarState.KEYGUARD);
 
-        // WHEN user hasn't authenticated since last boot
-        when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
-                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT);
+        // WHEN user hasn't authenticated since last boot, cannot unlock with FP
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
 
         // THEN we shouldn't listen for udfps
         assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false);
@@ -1258,8 +1332,7 @@
         when(mStrongAuthTracker.hasUserAuthenticatedSinceBoot()).thenReturn(true);
 
         // WHEN device in lock down
-        when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
-                KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
 
         // THEN we shouldn't listen for udfps
         assertThat(mKeyguardUpdateMonitor.shouldListenForFingerprint(true)).isEqualTo(false);
@@ -1272,7 +1345,7 @@
         mStatusBarStateListener.onStateChanged(StatusBarState.SHADE_LOCKED);
         setKeyguardBouncerVisibility(false /* isVisible */);
         mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
-        when(mKeyguardBypassController.canBypass()).thenReturn(true);
+        lockscreenBypassIsAllowed();
         keyguardIsVisible();
 
         // WHEN status bar state reports a change to the keyguard that would normally indicate to
@@ -1293,6 +1366,24 @@
     }
 
     @Test
+    public void testRequestFaceAuthFromOccludingApp_whenInvoked_startsFaceAuth() {
+        mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
+
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isTrue();
+    }
+
+    @Test
+    public void testRequestFaceAuthFromOccludingApp_whenInvoked_stopsFaceAuth() {
+        mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(true);
+
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isTrue();
+
+        mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
+
+        assertThat(mKeyguardUpdateMonitor.isFaceDetectionRunning()).isFalse();
+    }
+
+    @Test
     public void testRequireUnlockForNfc_Broadcast() {
         KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
         mKeyguardUpdateMonitor.registerCallback(callback);
@@ -1438,11 +1529,9 @@
         userNotCurrentlySwitching();
 
         // This disables face auth
-        when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
-                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT);
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
         mTestableLooper.processAllMessages();
 
-
         assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
     }
 
@@ -1906,6 +1995,109 @@
         );
     }
 
+    @Test
+    public void testStrongAuthChange_lockDown_stopsFpAndFaceListeningState() {
+        // GIVEN device is listening for face and fingerprint
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+        keyguardIsVisible();
+
+        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+        verify(mFingerprintManager).authenticate(any(), any(), any(), any(), anyInt(), anyInt(),
+                anyInt());
+
+        final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
+        final CancellationSignal fpCancel = spy(mKeyguardUpdateMonitor.mFingerprintCancelSignal);
+        mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
+        mKeyguardUpdateMonitor.mFingerprintCancelSignal = fpCancel;
+        KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+        mKeyguardUpdateMonitor.registerCallback(callback);
+
+        // WHEN strong auth changes and device is in user lockdown
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        userDeviceLockDown();
+        mKeyguardUpdateMonitor.notifyStrongAuthAllowedChanged(getCurrentUser());
+        mTestableLooper.processAllMessages();
+
+        // THEN face and fingerprint listening are cancelled
+        verify(faceCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
+                eq(false), eq(BiometricSourceType.FACE));
+        verify(fpCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
+                eq(false), eq(BiometricSourceType.FINGERPRINT));
+    }
+
+    @Test
+    public void testNonStrongBiometricAllowedChanged_stopsFaceListeningState() {
+        // GIVEN device is listening for face and fingerprint
+        mKeyguardUpdateMonitor.dispatchStartedWakingUp(PowerManager.WAKE_REASON_POWER_BUTTON);
+        mTestableLooper.processAllMessages();
+        keyguardIsVisible();
+
+        verify(mFaceManager).authenticate(any(), any(), any(), any(), anyInt(), anyBoolean());
+
+        final CancellationSignal faceCancel = spy(mKeyguardUpdateMonitor.mFaceCancelSignal);
+        mKeyguardUpdateMonitor.mFaceCancelSignal = faceCancel;
+        KeyguardUpdateMonitorCallback callback = mock(KeyguardUpdateMonitorCallback.class);
+        mKeyguardUpdateMonitor.registerCallback(callback);
+
+        // WHEN non-strong biometric allowed changes
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        mKeyguardUpdateMonitor.notifyNonStrongBiometricAllowedChanged(getCurrentUser());
+        mTestableLooper.processAllMessages();
+
+        // THEN face and fingerprint listening are cancelled
+        verify(faceCancel).cancel();
+        verify(callback).onBiometricRunningStateChanged(
+                eq(false), eq(BiometricSourceType.FACE));
+    }
+
+    @Test
+    public void testShouldListenForFace_withLockedDown_returnsFalse()
+            throws RemoteException {
+        keyguardNotGoingAway();
+        bouncerFullyVisibleAndNotGoingToSleep();
+        currentUserIsPrimary();
+        currentUserDoesNotHaveTrust();
+        biometricsNotDisabledThroughDevicePolicyManager();
+        biometricsEnabledForCurrentUser();
+        userNotCurrentlySwitching();
+        supportsFaceDetection();
+        mTestableLooper.processAllMessages();
+
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isTrue();
+
+        userDeviceLockDown();
+
+        assertThat(mKeyguardUpdateMonitor.shouldListenForFace()).isFalse();
+    }
+
+    private void userDeviceLockDown() {
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+        when(mStrongAuthTracker.getStrongAuthForUser(mCurrentUserId))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
+    }
+
+    private void supportsFaceDetection() {
+        when(mFaceSensorProperties.get(anyInt()))
+                .thenReturn(createFaceSensorProperties(
+                        /* supportsFaceDetection = */ true));
+    }
+
+    private void lockscreenBypassIsAllowed() {
+        mockCanBypassLockscreen(true);
+    }
+
+    private void mockCanBypassLockscreen(boolean canBypass) {
+        mKeyguardUpdateMonitor.setKeyguardBypassController(mKeyguardBypassController);
+        when(mKeyguardBypassController.canBypass()).thenReturn(canBypass);
+    }
+
+    private void lockscreenBypassIsNotAllowed() {
+        mockCanBypassLockscreen(false);
+    }
+
     private void cleanupKeyguardUpdateMonitor() {
         if (mKeyguardUpdateMonitor != null) {
             mKeyguardUpdateMonitor.removeCallback(mTestCallback);
@@ -1999,9 +2191,16 @@
         );
     }
 
+    private void strongAuthRequiredEncrypted() {
+        when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
+                .thenReturn(STRONG_AUTH_REQUIRED_AFTER_BOOT);
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false);
+    }
+
     private void strongAuthNotRequired() {
         when(mStrongAuthTracker.getStrongAuthForUser(KeyguardUpdateMonitor.getCurrentUser()))
                 .thenReturn(0);
+        when(mStrongAuthTracker.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true);
     }
 
     private void currentUserDoesNotHaveTrust() {
@@ -2042,6 +2241,10 @@
         setKeyguardBouncerVisibility(true);
     }
 
+    private void bouncerNotVisible() {
+        setKeyguardBouncerVisibility(false);
+    }
+
     private void setKeyguardBouncerVisibility(boolean isVisible) {
         mKeyguardUpdateMonitor.sendPrimaryBouncerChanged(isVisible, isVisible);
         mTestableLooper.processAllMessages();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 181839a..0627fc6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -77,7 +77,6 @@
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.biometrics.AuthController;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.decor.CornerDecorProvider;
 import com.android.systemui.decor.CutoutDecorProviderFactory;
 import com.android.systemui.decor.CutoutDecorProviderImpl;
@@ -132,8 +131,6 @@
     @Mock
     private TunerService mTunerService;
     @Mock
-    private BroadcastDispatcher mBroadcastDispatcher;
-    @Mock
     private UserTracker mUserTracker;
     @Mock
     private PrivacyDotViewController mDotViewController;
@@ -223,8 +220,8 @@
                 mExecutor));
 
         mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings,
-                mBroadcastDispatcher, mTunerService, mUserTracker, mDotViewController,
-                mThreadFactory, mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory) {
+                mTunerService, mUserTracker, mDotViewController, mThreadFactory,
+                mPrivacyDotDecorProviderFactory, mFaceScanningProviderFactory) {
             @Override
             public void start() {
                 super.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 57ca9c0..9d39a8c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -34,7 +34,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -88,6 +87,8 @@
 import com.android.systemui.util.leak.ReferenceTestUtils;
 import com.android.systemui.utils.os.FakeHandler;
 
+import com.google.common.util.concurrent.AtomicDouble;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -710,7 +711,7 @@
     }
 
     @Test
-    public void onSingleTap_enabled_scaleIsChanged() {
+    public void onSingleTap_enabled_scaleAnimates() {
         mInstrumentation.runOnMainSync(() -> {
             mWindowMagnificationController.enableWindowMagnificationInternal(Float.NaN, Float.NaN,
                     Float.NaN);
@@ -721,14 +722,28 @@
         });
 
         final View mirrorView = mWindowManager.getAttachedView();
+
         final long timeout = SystemClock.uptimeMillis() + 1000;
-        while (SystemClock.uptimeMillis() < timeout) {
-            SystemClock.sleep(10);
-            if (Float.compare(1.0f, mirrorView.getScaleX()) < 0) {
-                return;
+        final AtomicDouble maxScaleX = new AtomicDouble();
+        final Runnable onAnimationFrame = new Runnable() {
+            @Override
+            public void run() {
+                // For some reason the fancy way doesn't compile...
+//                maxScaleX.getAndAccumulate(mirrorView.getScaleX(), Math::max);
+                final double oldMax = maxScaleX.get();
+                final double newMax = Math.max(mirrorView.getScaleX(), oldMax);
+                assertTrue(maxScaleX.compareAndSet(oldMax, newMax));
+
+                if (SystemClock.uptimeMillis() < timeout) {
+                    mirrorView.postOnAnimation(this);
+                }
             }
-        }
-        fail("MirrorView scale is not changed");
+        };
+        mirrorView.postOnAnimation(onAnimationFrame);
+
+        waitForIdleSync();
+
+        ReferenceTestUtils.waitForCondition(() -> maxScaleX.get() > 1.0);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 0b528a5..b765ab3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -26,6 +26,7 @@
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.LightRevealScrim
@@ -37,7 +38,7 @@
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.leak.RotationUtils
-import javax.inject.Provider
+import com.android.systemui.util.mockito.any
 import org.junit.After
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
@@ -46,15 +47,16 @@
 import org.junit.runner.RunWith
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
-import org.mockito.Mockito.any
+import org.mockito.Mockito.`when`
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when`
 import org.mockito.MockitoAnnotations
 import org.mockito.MockitoSession
 import org.mockito.quality.Strictness
+import javax.inject.Provider
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -76,6 +78,7 @@
     @Mock private lateinit var udfpsControllerProvider: Provider<UdfpsController>
     @Mock private lateinit var udfpsController: UdfpsController
     @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var featureFlags: FeatureFlags
     @Mock private lateinit var lightRevealScrim: LightRevealScrim
     @Mock private lateinit var fpSensorProp: FingerprintSensorPropertiesInternal
 
@@ -105,6 +108,7 @@
             biometricUnlockController,
             udfpsControllerProvider,
             statusBarStateController,
+            featureFlags,
             rippleView
         )
         controller.init()
@@ -118,12 +122,13 @@
 
     @Test
     fun testFingerprintTrigger_KeyguardShowing_Ripple() {
-        // GIVEN fp exists, keyguard is showing, user doesn't need strong auth
+        // GIVEN fp exists, keyguard is showing, unlocking with fp allowed
         val fpsLocation = Point(5, 5)
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardStateController.isShowing).thenReturn(true)
-        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
 
         // WHEN fingerprint authenticated
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
@@ -140,11 +145,12 @@
 
     @Test
     fun testFingerprintTrigger_KeyguardNotShowing_NoRipple() {
-        // GIVEN fp exists & user doesn't need strong auth
+        // GIVEN fp exists & unlocking with fp allowed
         val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
-        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                eq(BiometricSourceType.FINGERPRINT))).thenReturn(true)
 
         // WHEN keyguard is NOT showing & fingerprint authenticated
         `when`(keyguardStateController.isShowing).thenReturn(false)
@@ -160,15 +166,16 @@
     }
 
     @Test
-    fun testFingerprintTrigger_StrongAuthRequired_NoRipple() {
+    fun testFingerprintTrigger_biometricUnlockNotAllowed_NoRipple() {
         // GIVEN fp exists & keyguard is showing
         val fpsLocation = Point(5, 5)
         `when`(authController.udfpsLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardStateController.isShowing).thenReturn(true)
 
-        // WHEN user needs strong auth & fingerprint authenticated
-        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(true)
+        // WHEN unlocking with fingerprint is NOT allowed & fingerprint authenticated
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                eq(BiometricSourceType.FINGERPRINT))).thenReturn(false)
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
         verify(keyguardUpdateMonitor).registerCallback(captor.capture())
         captor.value.onBiometricAuthenticated(
@@ -182,13 +189,14 @@
 
     @Test
     fun testFaceTriggerBypassEnabled_Ripple() {
-        // GIVEN face auth sensor exists, keyguard is showing & strong auth isn't required
+        // GIVEN face auth sensor exists, keyguard is showing & unlocking with face is allowed
         val faceLocation = Point(5, 5)
         `when`(authController.faceSensorLocation).thenReturn(faceLocation)
         controller.onViewAttached()
 
         `when`(keyguardStateController.isShowing).thenReturn(true)
-        `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FACE)).thenReturn(true)
 
         // WHEN bypass is enabled & face authenticated
         `when`(bypassController.canBypass()).thenReturn(true)
@@ -275,6 +283,8 @@
         `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardStateController.isShowing).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                BiometricSourceType.FINGERPRINT)).thenReturn(true)
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
 
         controller.showUnlockRipple(BiometricSourceType.FINGERPRINT)
@@ -295,6 +305,8 @@
         `when`(keyguardStateController.isShowing).thenReturn(true)
         `when`(biometricUnlockController.isWakeAndUnlock).thenReturn(true)
         `when`(authController.isUdfpsFingerDown).thenReturn(true)
+        `when`(keyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+                eq(BiometricSourceType.FACE))).thenReturn(true)
 
         controller.showUnlockRipple(BiometricSourceType.FACE)
         assertTrue("reveal didn't start on keyguardFadingAway",
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
index e7d5632..3c40835 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/SideFpsControllerTest.kt
@@ -47,6 +47,7 @@
 import android.view.WindowManager
 import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
 import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_TRUSTED_OVERLAY
+import android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
 import android.view.WindowMetrics
 import androidx.test.filters.SmallTest
 import com.airbnb.lottie.LottieAnimationView
@@ -423,6 +424,21 @@
     }
 
     @Test
+    fun testLayoutParams_isKeyguardDialogType() =
+        testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
+            sideFpsController.overlayOffsets = sensorLocation
+            sideFpsController.updateOverlayParams(windowManager.defaultDisplay, indicatorBounds)
+            overlayController.show(SENSOR_ID, REASON_UNKNOWN)
+            executor.runAllReady()
+
+            verify(windowManager).updateViewLayout(any(), overlayViewParamsCaptor.capture())
+
+            val lpType = overlayViewParamsCaptor.value.type
+
+            assertThat((lpType and TYPE_KEYGUARD_DIALOG) != 0).isTrue()
+        }
+
+    @Test
     fun testLayoutParams_hasNoMoveAnimationWindowFlag() =
         testWithDisplay(deviceConfig = DeviceConfig.Y_ALIGNED_UNFOLDED) {
             sideFpsController.overlayOffsets = sensorLocation
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index acdafe3..b267a5c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -70,8 +70,13 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.biometrics.udfps.InteractionEvent;
+import com.android.systemui.biometrics.udfps.NormalizedTouchData;
+import com.android.systemui.biometrics.udfps.SinglePointerTouchProcessor;
+import com.android.systemui.biometrics.udfps.TouchProcessorResult;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.flags.Flags;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.domain.interactor.PrimaryBouncerInteractor;
 import com.android.systemui.plugins.FalsingManager;
@@ -190,6 +195,8 @@
     private AlternateUdfpsTouchProvider mAlternateTouchProvider;
     @Mock
     private PrimaryBouncerInteractor mPrimaryBouncerInteractor;
+    @Mock
+    private SinglePointerTouchProcessor mSinglePointerTouchProcessor;
 
     // Capture listeners so that they can be used to send events
     @Captor
@@ -275,7 +282,7 @@
                 mDisplayManager, mHandler, mConfigurationController, mSystemClock,
                 mUnlockedScreenOffAnimationController, mSystemUIDialogManager, mLatencyTracker,
                 mActivityLaunchAnimator, alternateTouchProvider, mBiometricsExecutor,
-                mPrimaryBouncerInteractor);
+                mPrimaryBouncerInteractor, mSinglePointerTouchProcessor);
         verify(mFingerprintManager).setUdfpsOverlayController(mOverlayCaptor.capture());
         mOverlayController = mOverlayCaptor.getValue();
         verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture());
@@ -1086,4 +1093,100 @@
                 anyString(),
                 any());
     }
+
+    @Test
+    public void onTouch_withoutNewTouchDetection_shouldCallOldFingerprintManagerPath()
+            throws RemoteException {
+        // Disable new touch detection.
+        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(false);
+
+        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
+        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+
+        // Configure UdfpsView to accept the ACTION_DOWN event
+        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+        // WHEN ACTION_DOWN is received
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        mBiometricsExecutor.runAllReady();
+        downEvent.recycle();
+
+        // AND ACTION_MOVE is received
+        MotionEvent moveEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_MOVE, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+        mBiometricsExecutor.runAllReady();
+        moveEvent.recycle();
+
+        // AND ACTION_UP is received
+        MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+        mBiometricsExecutor.runAllReady();
+        upEvent.recycle();
+
+        // THEN the old FingerprintManager path is invoked.
+        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyInt(),
+                anyFloat(), anyFloat());
+        verify(mFingerprintManager).onPointerUp(anyLong(), anyInt());
+    }
+
+    @Test
+    public void onTouch_withNewTouchDetection_shouldCallOldFingerprintManagerPath()
+            throws RemoteException {
+        final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+                0L);
+        final TouchProcessorResult processorResultDown = new TouchProcessorResult.ProcessedTouch(
+                InteractionEvent.DOWN, 1 /* pointerId */, touchData);
+        final TouchProcessorResult processorResultUp = new TouchProcessorResult.ProcessedTouch(
+                InteractionEvent.UP, 1 /* pointerId */, touchData);
+
+        // Enable new touch detection.
+        when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
+
+        // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
+        initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+
+        // Configure UdfpsView to accept the ACTION_DOWN event
+        when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+        when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+        // GIVEN that the overlay is showing and a11y touch exploration NOT enabled
+        when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+        mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+                BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+        mFgExecutor.runAllReady();
+
+        verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+        // WHEN ACTION_DOWN is received
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                processorResultDown);
+        MotionEvent downEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, downEvent);
+        mBiometricsExecutor.runAllReady();
+        downEvent.recycle();
+
+        // AND ACTION_UP is received
+        when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+                processorResultUp);
+        MotionEvent upEvent = MotionEvent.obtain(0, 0, MotionEvent.ACTION_UP, 0, 0, 0);
+        mTouchListenerCaptor.getValue().onTouch(mUdfpsView, upEvent);
+        mBiometricsExecutor.runAllReady();
+        upEvent.recycle();
+
+        // THEN the new FingerprintManager path is invoked.
+        verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+        verify(mFingerprintManager).onPointerUp(anyLong(), anyInt(), anyInt(), anyFloat(),
+                anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(), anyBoolean());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsEnrollViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsEnrollViewTest.java
new file mode 100644
index 0000000..60a0258
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsEnrollViewTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.res.Configuration;
+import android.graphics.Color;
+import android.testing.AndroidTestingRunner;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class UdfpsEnrollViewTest extends SysuiTestCase {
+
+    private static String ENROLL_PROGRESS_COLOR_LIGHT = "#699FF3";
+    private static String ENROLL_PROGRESS_COLOR_DARK = "#7DA7F1";
+
+    @Test
+    public void fingerprintUdfpsEnroll_usesCorrectThemeCheckmarkFillColor() {
+        final Configuration config = mContext.getResources().getConfiguration();
+        final boolean isDarkThemeOn = (config.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        final int currentColor = mContext.getColor(R.color.udfps_enroll_progress);
+
+        assertThat(currentColor).isEqualTo(Color.parseColor(isDarkThemeOn
+                ? ENROLL_PROGRESS_COLOR_DARK : ENROLL_PROGRESS_COLOR_LIGHT));
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
new file mode 100644
index 0000000..4f89b69
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/BoundingBoxOverlapDetectorTest.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+
+@SmallTest
+@RunWith(Parameterized::class)
+class BoundingBoxOverlapDetectorTest(val testCase: TestCase) : SysuiTestCase() {
+    val underTest = BoundingBoxOverlapDetector()
+
+    @Test
+    fun isGoodOverlap() {
+        val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat())
+        val actual = underTest.isGoodOverlap(touchData, SENSOR)
+
+        assertThat(actual).isEqualTo(testCase.expected)
+    }
+
+    data class TestCase(val x: Int, val y: Int, val expected: Boolean)
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): List<TestCase> =
+            listOf(
+                    genPositiveTestCases(
+                        validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
+                        validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
+                    ),
+                    genNegativeTestCases(
+                        invalidXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
+                        invalidYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
+                        validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
+                        validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
+                    )
+                )
+                .flatten()
+    }
+}
+
+/* Placeholder touch parameters. */
+private const val POINTER_ID = 42
+private const val NATIVE_MINOR = 2.71828f
+private const val NATIVE_MAJOR = 3.14f
+private const val ORIENTATION = 1.23f
+private const val TIME = 12345699L
+private const val GESTURE_START = 12345600L
+
+/* Template [NormalizedTouchData]. */
+private val TOUCH_DATA =
+    NormalizedTouchData(
+        POINTER_ID,
+        x = 0f,
+        y = 0f,
+        NATIVE_MINOR,
+        NATIVE_MAJOR,
+        ORIENTATION,
+        TIME,
+        GESTURE_START
+    )
+
+private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 500 /* bottom */)
+
+private fun genTestCases(
+    xs: List<Int>,
+    ys: List<Int>,
+    expected: Boolean
+): List<BoundingBoxOverlapDetectorTest.TestCase> {
+    return xs.flatMap { x ->
+        ys.map { y -> BoundingBoxOverlapDetectorTest.TestCase(x, y, expected) }
+    }
+}
+
+private fun genPositiveTestCases(
+    validXs: List<Int>,
+    validYs: List<Int>,
+) = genTestCases(validXs, validYs, expected = true)
+
+private fun genNegativeTestCases(
+    invalidXs: List<Int>,
+    invalidYs: List<Int>,
+    validXs: List<Int>,
+    validYs: List<Int>,
+): List<BoundingBoxOverlapDetectorTest.TestCase> {
+    return genTestCases(invalidXs, validYs, expected = false) +
+        genTestCases(validXs, invalidYs, expected = false)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt
new file mode 100644
index 0000000..834d0a6
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/NormalizedTouchDataTest.kt
@@ -0,0 +1,90 @@
+package com.android.systemui.biometrics.udfps
+
+import android.graphics.Rect
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+
+@SmallTest
+@RunWith(Parameterized::class)
+class NormalizedTouchDataTest(val testCase: TestCase) : SysuiTestCase() {
+
+    @Test
+    fun isWithinSensor() {
+        val touchData = TOUCH_DATA.copy(x = testCase.x.toFloat(), y = testCase.y.toFloat())
+        val actual = touchData.isWithinSensor(SENSOR)
+
+        assertThat(actual).isEqualTo(testCase.expected)
+    }
+
+    data class TestCase(val x: Int, val y: Int, val expected: Boolean)
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): List<TestCase> =
+            listOf(
+                    genPositiveTestCases(
+                        validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
+                        validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
+                    ),
+                    genNegativeTestCases(
+                        invalidXs = listOf(SENSOR.left - 1, SENSOR.right + 1),
+                        invalidYs = listOf(SENSOR.top - 1, SENSOR.bottom + 1),
+                        validXs = listOf(SENSOR.left, SENSOR.right, SENSOR.centerX()),
+                        validYs = listOf(SENSOR.top, SENSOR.bottom, SENSOR.centerY())
+                    )
+                )
+                .flatten()
+    }
+}
+
+/* Placeholder touch parameters. */
+private const val POINTER_ID = 42
+private const val NATIVE_MINOR = 2.71828f
+private const val NATIVE_MAJOR = 3.14f
+private const val ORIENTATION = 1.23f
+private const val TIME = 12345699L
+private const val GESTURE_START = 12345600L
+
+/* Template [NormalizedTouchData]. */
+private val TOUCH_DATA =
+    NormalizedTouchData(
+        POINTER_ID,
+        x = 0f,
+        y = 0f,
+        NATIVE_MINOR,
+        NATIVE_MAJOR,
+        ORIENTATION,
+        TIME,
+        GESTURE_START
+    )
+
+private val SENSOR = Rect(100 /* left */, 200 /* top */, 300 /* right */, 500 /* bottom */)
+
+private fun genTestCases(
+    xs: List<Int>,
+    ys: List<Int>,
+    expected: Boolean
+): List<NormalizedTouchDataTest.TestCase> {
+    return xs.flatMap { x -> ys.map { y -> NormalizedTouchDataTest.TestCase(x, y, expected) } }
+}
+
+private fun genPositiveTestCases(
+    validXs: List<Int>,
+    validYs: List<Int>,
+) = genTestCases(validXs, validYs, expected = true)
+
+private fun genNegativeTestCases(
+    invalidXs: List<Int>,
+    invalidYs: List<Int>,
+    validXs: List<Int>,
+    validYs: List<Int>,
+): List<NormalizedTouchDataTest.TestCase> {
+    return genTestCases(invalidXs, validYs, expected = false) +
+        genTestCases(validXs, invalidYs, expected = false)
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
new file mode 100644
index 0000000..95c53b4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/udfps/SinglePointerTouchProcessorTest.kt
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+import android.view.MotionEvent
+import android.view.MotionEvent.INVALID_POINTER_ID
+import android.view.MotionEvent.PointerProperties
+import android.view.Surface
+import android.view.Surface.Rotation
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.UdfpsOverlayParams
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+
+@SmallTest
+@RunWith(Parameterized::class)
+class SinglePointerTouchProcessorTest(val testCase: TestCase) : SysuiTestCase() {
+    private val overlapDetector = FakeOverlapDetector()
+    private val underTest = SinglePointerTouchProcessor(overlapDetector)
+
+    @Test
+    fun processTouch() {
+        overlapDetector.shouldReturn = testCase.isGoodOverlap
+
+        val actual =
+            underTest.processTouch(
+                testCase.event,
+                testCase.previousPointerOnSensorId,
+                testCase.overlayParams,
+            )
+
+        assertThat(actual).isInstanceOf(testCase.expected.javaClass)
+        if (actual is TouchProcessorResult.ProcessedTouch) {
+            assertThat(actual).isEqualTo(testCase.expected)
+        }
+    }
+
+    data class TestCase(
+        val event: MotionEvent,
+        val isGoodOverlap: Boolean,
+        val previousPointerOnSensorId: Int,
+        val overlayParams: UdfpsOverlayParams,
+        val expected: TouchProcessorResult,
+    ) {
+        override fun toString(): String {
+            val expectedOutput =
+                if (expected is TouchProcessorResult.ProcessedTouch) {
+                    expected.event.toString() +
+                        ", (x: ${expected.touchData.x}, y: ${expected.touchData.y})" +
+                        ", pointerOnSensorId: ${expected.pointerOnSensorId}" +
+                        ", ..."
+                } else {
+                    TouchProcessorResult.Failure().toString()
+                }
+            return "{" +
+                MotionEvent.actionToString(event.action) +
+                ", (x: ${event.x}, y: ${event.y})" +
+                ", scale: ${overlayParams.scaleFactor}" +
+                ", rotation: " +
+                Surface.rotationToString(overlayParams.rotation) +
+                ", previousPointerOnSensorId: $previousPointerOnSensorId" +
+                ", ...} expected: {$expectedOutput}"
+        }
+    }
+
+    companion object {
+        @Parameters(name = "{0}")
+        @JvmStatic
+        fun data(): List<TestCase> =
+            listOf(
+                    // MotionEvent.ACTION_DOWN
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_DOWN,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.DOWN,
+                        expectedPointerOnSensorId = POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_DOWN,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.DOWN,
+                        expectedPointerOnSensorId = POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_DOWN,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UNCHANGED,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_DOWN,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UP,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    // MotionEvent.ACTION_MOVE
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_MOVE,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.DOWN,
+                        expectedPointerOnSensorId = POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_MOVE,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.UNCHANGED,
+                        expectedPointerOnSensorId = POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_MOVE,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UNCHANGED,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_MOVE,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UP,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    // MotionEvent.ACTION_UP
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_UP,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.UP,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_UP,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.UP,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_UP,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UNCHANGED,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_UP,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.UP,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    // MotionEvent.ACTION_CANCEL
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_CANCEL,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.CANCEL,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_CANCEL,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = true,
+                        expectedInteractionEvent = InteractionEvent.CANCEL,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_CANCEL,
+                        previousPointerOnSensorId = INVALID_POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.CANCEL,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                    genPositiveTestCases(
+                        motionEventAction = MotionEvent.ACTION_CANCEL,
+                        previousPointerOnSensorId = POINTER_ID,
+                        isGoodOverlap = false,
+                        expectedInteractionEvent = InteractionEvent.CANCEL,
+                        expectedPointerOnSensorId = INVALID_POINTER_ID,
+                    ),
+                )
+                .flatten() +
+                listOf(
+                        // Unsupported MotionEvent actions.
+                        genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_DOWN),
+                        genTestCasesForUnsupportedAction(MotionEvent.ACTION_POINTER_UP),
+                        genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_ENTER),
+                        genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_MOVE),
+                        genTestCasesForUnsupportedAction(MotionEvent.ACTION_HOVER_EXIT),
+                    )
+                    .flatten()
+    }
+}
+
+/* Display dimensions in native resolution and natural orientation. */
+private const val ROTATION_0_NATIVE_DISPLAY_WIDTH = 400
+private const val ROTATION_0_NATIVE_DISPLAY_HEIGHT = 600
+
+/*
+ * ROTATION_0 map:
+ * _ _ _ _
+ * _ _ O _
+ * _ _ _ _
+ * _ S _ _
+ * _ S _ _
+ * _ _ _ _
+ *
+ * (_) empty space
+ * (S) sensor
+ * (O) touch outside of the sensor
+ */
+private val ROTATION_0_NATIVE_SENSOR_BOUNDS =
+    Rect(
+        100, /* left */
+        300, /* top */
+        200, /* right */
+        500, /* bottom */
+    )
+private val ROTATION_0_INPUTS =
+    OrientationBasedInputs(
+        rotation = Surface.ROTATION_0,
+        nativeXWithinSensor = ROTATION_0_NATIVE_SENSOR_BOUNDS.exactCenterX(),
+        nativeYWithinSensor = ROTATION_0_NATIVE_SENSOR_BOUNDS.exactCenterY(),
+        nativeXOutsideSensor = 250f,
+        nativeYOutsideSensor = 150f,
+    )
+
+/*
+ * ROTATION_90 map:
+ * _ _ _ _ _ _
+ * _ O _ _ _ _
+ * _ _ _ S S _
+ * _ _ _ _ _ _
+ *
+ * (_) empty space
+ * (S) sensor
+ * (O) touch outside of the sensor
+ */
+private val ROTATION_90_NATIVE_SENSOR_BOUNDS =
+    Rect(
+        300, /* left */
+        200, /* top */
+        500, /* right */
+        300, /* bottom */
+    )
+private val ROTATION_90_INPUTS =
+    OrientationBasedInputs(
+        rotation = Surface.ROTATION_90,
+        nativeXWithinSensor = ROTATION_90_NATIVE_SENSOR_BOUNDS.exactCenterX(),
+        nativeYWithinSensor = ROTATION_90_NATIVE_SENSOR_BOUNDS.exactCenterY(),
+        nativeXOutsideSensor = 150f,
+        nativeYOutsideSensor = 150f,
+    )
+
+/* ROTATION_180 is not supported. It's treated the same as ROTATION_0. */
+private val ROTATION_180_INPUTS =
+    ROTATION_0_INPUTS.copy(
+        rotation = Surface.ROTATION_180,
+    )
+
+/*
+ * ROTATION_270 map:
+ * _ _ _ _ _ _
+ * _ S S _ _ _
+ * _ _ _ _ O _
+ * _ _ _ _ _ _
+ *
+ * (_) empty space
+ * (S) sensor
+ * (O) touch outside of the sensor
+ */
+private val ROTATION_270_NATIVE_SENSOR_BOUNDS =
+    Rect(
+        100, /* left */
+        100, /* top */
+        300, /* right */
+        200, /* bottom */
+    )
+private val ROTATION_270_INPUTS =
+    OrientationBasedInputs(
+        rotation = Surface.ROTATION_270,
+        nativeXWithinSensor = ROTATION_270_NATIVE_SENSOR_BOUNDS.exactCenterX(),
+        nativeYWithinSensor = ROTATION_270_NATIVE_SENSOR_BOUNDS.exactCenterY(),
+        nativeXOutsideSensor = 450f,
+        nativeYOutsideSensor = 250f,
+    )
+
+/* Placeholder touch parameters. */
+private const val POINTER_ID = 42
+private const val NATIVE_MINOR = 2.71828f
+private const val NATIVE_MAJOR = 3.14f
+private const val ORIENTATION = 1.23f
+private const val TIME = 12345699L
+private const val GESTURE_START = 12345600L
+
+/* Template [MotionEvent]. */
+private val MOTION_EVENT =
+    obtainMotionEvent(
+        action = 0,
+        pointerId = POINTER_ID,
+        x = 0f,
+        y = 0f,
+        minor = 0f,
+        major = 0f,
+        orientation = ORIENTATION,
+        time = TIME,
+        gestureStart = GESTURE_START,
+    )
+
+/* Template [NormalizedTouchData]. */
+private val NORMALIZED_TOUCH_DATA =
+    NormalizedTouchData(
+        POINTER_ID,
+        x = 0f,
+        y = 0f,
+        NATIVE_MINOR,
+        NATIVE_MAJOR,
+        ORIENTATION,
+        TIME,
+        GESTURE_START
+    )
+
+/*
+ * Contains test inputs that are tied to a particular device orientation.
+ *
+ * "native" means in native resolution (not scaled).
+ */
+private data class OrientationBasedInputs(
+    @Rotation val rotation: Int,
+    val nativeXWithinSensor: Float,
+    val nativeYWithinSensor: Float,
+    val nativeXOutsideSensor: Float,
+    val nativeYOutsideSensor: Float,
+) {
+
+    fun toOverlayParams(scaleFactor: Float): UdfpsOverlayParams =
+        UdfpsOverlayParams(
+            sensorBounds = ROTATION_0_NATIVE_SENSOR_BOUNDS.scaled(scaleFactor),
+            overlayBounds = ROTATION_0_NATIVE_SENSOR_BOUNDS.scaled(scaleFactor),
+            naturalDisplayHeight = (ROTATION_0_NATIVE_DISPLAY_HEIGHT * scaleFactor).toInt(),
+            naturalDisplayWidth = (ROTATION_0_NATIVE_DISPLAY_WIDTH * scaleFactor).toInt(),
+            scaleFactor = scaleFactor,
+            rotation = rotation
+        )
+
+    fun getNativeX(isWithinSensor: Boolean): Float {
+        return if (isWithinSensor) nativeXWithinSensor else nativeXOutsideSensor
+    }
+
+    fun getNativeY(isWithinSensor: Boolean): Float {
+        return if (isWithinSensor) nativeYWithinSensor else nativeYOutsideSensor
+    }
+}
+
+private fun genPositiveTestCases(
+    motionEventAction: Int,
+    previousPointerOnSensorId: Int,
+    isGoodOverlap: Boolean,
+    expectedInteractionEvent: InteractionEvent,
+    expectedPointerOnSensorId: Int
+): List<SinglePointerTouchProcessorTest.TestCase> {
+    val scaleFactors = listOf(0.75f, 1f, 1.5f)
+    val orientations =
+        listOf(
+            ROTATION_0_INPUTS,
+            ROTATION_90_INPUTS,
+            ROTATION_180_INPUTS,
+            ROTATION_270_INPUTS,
+        )
+    return scaleFactors.flatMap { scaleFactor ->
+        orientations.map { orientation ->
+            val overlayParams = orientation.toOverlayParams(scaleFactor)
+            val nativeX = orientation.getNativeX(isGoodOverlap)
+            val nativeY = orientation.getNativeY(isGoodOverlap)
+            val event =
+                MOTION_EVENT.copy(
+                    action = motionEventAction,
+                    x = nativeX * scaleFactor,
+                    y = nativeY * scaleFactor,
+                    minor = NATIVE_MINOR * scaleFactor,
+                    major = NATIVE_MAJOR * scaleFactor,
+                )
+            val expectedTouchData =
+                NORMALIZED_TOUCH_DATA.copy(
+                    x = ROTATION_0_INPUTS.getNativeX(isGoodOverlap),
+                    y = ROTATION_0_INPUTS.getNativeY(isGoodOverlap),
+                )
+            val expected =
+                TouchProcessorResult.ProcessedTouch(
+                    event = expectedInteractionEvent,
+                    pointerOnSensorId = expectedPointerOnSensorId,
+                    touchData = expectedTouchData,
+                )
+            SinglePointerTouchProcessorTest.TestCase(
+                event = event,
+                isGoodOverlap = isGoodOverlap,
+                previousPointerOnSensorId = previousPointerOnSensorId,
+                overlayParams = overlayParams,
+                expected = expected,
+            )
+        }
+    }
+}
+
+private fun genTestCasesForUnsupportedAction(
+    motionEventAction: Int
+): List<SinglePointerTouchProcessorTest.TestCase> {
+    val isGoodOverlap = true
+    val previousPointerOnSensorIds = listOf(INVALID_POINTER_ID, POINTER_ID)
+    return previousPointerOnSensorIds.map { previousPointerOnSensorId ->
+        val overlayParams = ROTATION_0_INPUTS.toOverlayParams(scaleFactor = 1f)
+        val nativeX = ROTATION_0_INPUTS.getNativeX(isGoodOverlap)
+        val nativeY = ROTATION_0_INPUTS.getNativeY(isGoodOverlap)
+        val event =
+            MOTION_EVENT.copy(
+                action = motionEventAction,
+                x = nativeX,
+                y = nativeY,
+                minor = NATIVE_MINOR,
+                major = NATIVE_MAJOR,
+            )
+        SinglePointerTouchProcessorTest.TestCase(
+            event = event,
+            isGoodOverlap = isGoodOverlap,
+            previousPointerOnSensorId = previousPointerOnSensorId,
+            overlayParams = overlayParams,
+            expected = TouchProcessorResult.Failure(),
+        )
+    }
+}
+
+private fun obtainMotionEvent(
+    action: Int,
+    pointerId: Int,
+    x: Float,
+    y: Float,
+    minor: Float,
+    major: Float,
+    orientation: Float,
+    time: Long,
+    gestureStart: Long,
+): MotionEvent {
+    val pp = PointerProperties()
+    pp.id = pointerId
+    val pc = MotionEvent.PointerCoords()
+    pc.x = x
+    pc.y = y
+    pc.touchMinor = minor
+    pc.touchMajor = major
+    pc.orientation = orientation
+    return MotionEvent.obtain(
+        gestureStart /* downTime */,
+        time /* eventTime */,
+        action /* action */,
+        1 /* pointerCount */,
+        arrayOf(pp) /* pointerProperties */,
+        arrayOf(pc) /* pointerCoords */,
+        0 /* metaState */,
+        0 /* buttonState */,
+        1f /* xPrecision */,
+        1f /* yPrecision */,
+        0 /* deviceId */,
+        0 /* edgeFlags */,
+        0 /* source */,
+        0 /* flags */
+    )
+}
+
+private fun MotionEvent.copy(
+    action: Int = this.action,
+    pointerId: Int = this.getPointerId(0),
+    x: Float = this.rawX,
+    y: Float = this.rawY,
+    minor: Float = this.touchMinor,
+    major: Float = this.touchMajor,
+    orientation: Float = this.orientation,
+    time: Long = this.eventTime,
+    gestureStart: Long = this.downTime,
+) = obtainMotionEvent(action, pointerId, x, y, minor, major, orientation, time, gestureStart)
+
+private fun Rect.scaled(scaleFactor: Float) = Rect(this).apply { scale(scaleFactor) }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/ControlsSettingsRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/ControlsSettingsRepositoryImplTest.kt
new file mode 100644
index 0000000..4b88b44
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/ControlsSettingsRepositoryImplTest.kt
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls
+
+import android.content.pm.UserInfo
+import android.provider.Settings
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.util.settings.FakeSettings
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+
+@SmallTest
+@RunWith(JUnit4::class)
+@OptIn(ExperimentalCoroutinesApi::class)
+class ControlsSettingsRepositoryImplTest : SysuiTestCase() {
+
+    companion object {
+        private const val LOCKSCREEN_SHOW = Settings.Secure.LOCKSCREEN_SHOW_CONTROLS
+        private const val LOCKSCREEN_ACTION = Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS
+
+        private fun createUser(id: Int): UserInfo {
+            return UserInfo(id, "user_$id", 0)
+        }
+
+        private val ALL_USERS = (0..1).map { it to createUser(it) }.toMap()
+    }
+
+    private lateinit var underTest: ControlsSettingsRepository
+
+    private lateinit var testScope: TestScope
+    private lateinit var secureSettings: FakeSettings
+    private lateinit var userRepository: FakeUserRepository
+
+    @Before
+    fun setUp() {
+        secureSettings = FakeSettings()
+        userRepository = FakeUserRepository()
+        userRepository.setUserInfos(ALL_USERS.values.toList())
+
+        val coroutineDispatcher = UnconfinedTestDispatcher()
+        testScope = TestScope(coroutineDispatcher)
+
+        underTest =
+            ControlsSettingsRepositoryImpl(
+                scope = testScope.backgroundScope,
+                backgroundDispatcher = coroutineDispatcher,
+                userRepository = userRepository,
+                secureSettings = secureSettings,
+            )
+    }
+
+    @Test
+    fun showInLockScreen() =
+        testScope.runTest {
+            setUser(0)
+            val values = mutableListOf<Boolean>()
+            val job =
+                launch(UnconfinedTestDispatcher()) {
+                    underTest.canShowControlsInLockscreen.toList(values)
+                }
+            assertThat(values.last()).isFalse()
+
+            secureSettings.putBool(LOCKSCREEN_SHOW, true)
+            assertThat(values.last()).isTrue()
+
+            secureSettings.putBool(LOCKSCREEN_SHOW, false)
+            assertThat(values.last()).isFalse()
+
+            secureSettings.putBoolForUser(LOCKSCREEN_SHOW, true, 1)
+            assertThat(values.last()).isFalse()
+
+            setUser(1)
+            assertThat(values.last()).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun showInLockScreen_changesInOtherUsersAreNotQueued() =
+        testScope.runTest {
+            setUser(0)
+
+            val values = mutableListOf<Boolean>()
+            val job =
+                launch(UnconfinedTestDispatcher()) {
+                    underTest.canShowControlsInLockscreen.toList(values)
+                }
+
+            secureSettings.putBoolForUser(LOCKSCREEN_SHOW, true, 1)
+            secureSettings.putBoolForUser(LOCKSCREEN_SHOW, false, 1)
+
+            setUser(1)
+            assertThat(values.last()).isFalse()
+            assertThat(values).containsNoneIn(listOf(true))
+
+            job.cancel()
+        }
+
+    @Test
+    fun actionInLockScreen() =
+        testScope.runTest {
+            setUser(0)
+            val values = mutableListOf<Boolean>()
+            val job =
+                launch(UnconfinedTestDispatcher()) {
+                    underTest.allowActionOnTrivialControlsInLockscreen.toList(values)
+                }
+            assertThat(values.last()).isFalse()
+
+            secureSettings.putBool(LOCKSCREEN_ACTION, true)
+            assertThat(values.last()).isTrue()
+
+            secureSettings.putBool(LOCKSCREEN_ACTION, false)
+            assertThat(values.last()).isFalse()
+
+            secureSettings.putBoolForUser(LOCKSCREEN_ACTION, true, 1)
+            assertThat(values.last()).isFalse()
+
+            setUser(1)
+            assertThat(values.last()).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun actionInLockScreen_changesInOtherUsersAreNotQueued() =
+        testScope.runTest {
+            setUser(0)
+
+            val values = mutableListOf<Boolean>()
+            val job =
+                launch(UnconfinedTestDispatcher()) {
+                    underTest.allowActionOnTrivialControlsInLockscreen.toList(values)
+                }
+
+            secureSettings.putBoolForUser(LOCKSCREEN_ACTION, true, 1)
+            secureSettings.putBoolForUser(LOCKSCREEN_ACTION, false, 1)
+
+            setUser(1)
+            assertThat(values.last()).isFalse()
+            assertThat(values).containsNoneIn(listOf(true))
+
+            job.cancel()
+        }
+
+    @Test
+    fun valueIsUpdatedWhenNotSubscribed() =
+        testScope.runTest {
+            setUser(0)
+            assertThat(underTest.canShowControlsInLockscreen.value).isFalse()
+
+            secureSettings.putBool(LOCKSCREEN_SHOW, true)
+
+            assertThat(underTest.canShowControlsInLockscreen.value).isTrue()
+        }
+
+    private suspend fun setUser(id: Int) {
+        secureSettings.userId = id
+        userRepository.setSelectedUserInfo(ALL_USERS[id]!!)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/FakeControlsSettingsRepository.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/FakeControlsSettingsRepository.kt
new file mode 100644
index 0000000..8a1bed2
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/FakeControlsSettingsRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.controls
+
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+class FakeControlsSettingsRepository : ControlsSettingsRepository {
+    private val _canShowControlsInLockscreen = MutableStateFlow(false)
+    override val canShowControlsInLockscreen = _canShowControlsInLockscreen.asStateFlow()
+    private val _allowActionOnTrivialControlsInLockscreen = MutableStateFlow(false)
+    override val allowActionOnTrivialControlsInLockscreen =
+        _allowActionOnTrivialControlsInLockscreen.asStateFlow()
+
+    fun setCanShowControlsInLockscreen(value: Boolean) {
+        _canShowControlsInLockscreen.value = value
+    }
+
+    fun setAllowActionOnTrivialControlsInLockscreen(value: Boolean) {
+        _allowActionOnTrivialControlsInLockscreen.value = value
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
index 4ed5649c..1d00d6b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlActionCoordinatorImplTest.kt
@@ -18,30 +18,24 @@
 
 import android.content.Context
 import android.content.SharedPreferences
-import android.database.ContentObserver
-import android.net.Uri
-import android.os.Handler
-import android.os.UserHandle
-import android.provider.Settings
 import android.test.suitebuilder.annotation.SmallTest
 import android.testing.AndroidTestingRunner
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastSender
 import com.android.systemui.controls.ControlsMetricsLogger
+import com.android.systemui.controls.FakeControlsSettingsRepository
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserContextProvider
 import com.android.systemui.statusbar.VibratorHelper
 import com.android.systemui.statusbar.policy.DeviceControlsControllerImpl
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.mockito.any
 import com.android.systemui.util.settings.SecureSettings
 import com.android.wm.shell.TaskViewFactory
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Answers
-import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.Mockito.`when`
@@ -79,8 +73,6 @@
     @Mock
     private lateinit var secureSettings: SecureSettings
     @Mock
-    private lateinit var mainHandler: Handler
-    @Mock
     private lateinit var userContextProvider: UserContextProvider
 
     companion object {
@@ -91,17 +83,15 @@
 
     private lateinit var coordinator: ControlActionCoordinatorImpl
     private lateinit var action: ControlActionCoordinatorImpl.Action
+    private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        `when`(secureSettings.getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS))
-                .thenReturn(Settings.Secure
-                        .getUriFor(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS))
-        `when`(secureSettings.getIntForUser(Settings.Secure.LOCKSCREEN_ALLOW_TRIVIAL_CONTROLS,
-                0, UserHandle.USER_CURRENT))
-                .thenReturn(1)
+        controlsSettingsRepository = FakeControlsSettingsRepository()
+        controlsSettingsRepository.setAllowActionOnTrivialControlsInLockscreen(true)
+        controlsSettingsRepository.setCanShowControlsInLockscreen(true)
 
         coordinator = spy(ControlActionCoordinatorImpl(
                 mContext,
@@ -115,7 +105,7 @@
                 vibratorHelper,
                 secureSettings,
                 userContextProvider,
-                mainHandler
+                controlsSettingsRepository
         ))
 
         val userContext = mock(Context::class.java)
@@ -128,9 +118,6 @@
         `when`(pref.getInt(DeviceControlsControllerImpl.PREFS_SETTINGS_DIALOG_ATTEMPTS, 0))
                 .thenReturn(2)
 
-        verify(secureSettings).registerContentObserverForUser(any(Uri::class.java),
-                anyBoolean(), any(ContentObserver::class.java), anyInt())
-
         `when`(cvh.cws.ci.controlId).thenReturn(ID)
         `when`(cvh.cws.control?.isAuthRequired()).thenReturn(true)
         action = spy(coordinator.Action(ID, {}, false, true))
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
index c31fd82..1b34706 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.controls.controller
 
 import android.app.PendingIntent
-import android.content.BroadcastReceiver
 import android.content.ComponentName
 import android.content.Context
 import android.content.ContextWrapper
@@ -31,7 +30,6 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.backup.BackupHelper
-import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.controls.ControlStatus
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.controls.management.ControlsListingController
@@ -85,10 +83,8 @@
     @Mock
     private lateinit var auxiliaryPersistenceWrapper: AuxiliaryPersistenceWrapper
     @Mock
-    private lateinit var broadcastDispatcher: BroadcastDispatcher
-    @Mock
     private lateinit var listingController: ControlsListingController
-    @Mock(stubOnly = true)
+    @Mock
     private lateinit var userTracker: UserTracker
     @Mock
     private lateinit var userFileManager: UserFileManager
@@ -104,7 +100,7 @@
             ArgumentCaptor<ControlsBindingController.LoadCallback>
 
     @Captor
-    private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
+    private lateinit var userTrackerCallbackCaptor: ArgumentCaptor<UserTracker.Callback>
     @Captor
     private lateinit var listingCallbackCaptor:
             ArgumentCaptor<ControlsListingController.ControlsListingCallback>
@@ -170,16 +166,15 @@
                 uiController,
                 bindingController,
                 listingController,
-                broadcastDispatcher,
                 userFileManager,
+                userTracker,
                 Optional.of(persistenceWrapper),
-                mock(DumpManager::class.java),
-                userTracker
+                mock(DumpManager::class.java)
         )
         controller.auxiliaryPersistenceWrapper = auxiliaryPersistenceWrapper
 
-        verify(broadcastDispatcher).registerReceiver(
-            capture(broadcastReceiverCaptor), any(), any(), eq(UserHandle.ALL), anyInt(), any()
+        verify(userTracker).addCallback(
+            capture(userTrackerCallbackCaptor), any()
         )
 
         verify(listingController).addCallback(capture(listingCallbackCaptor))
@@ -227,11 +222,10 @@
                 uiController,
                 bindingController,
                 listingController,
-                broadcastDispatcher,
                 userFileManager,
+                userTracker,
                 Optional.of(persistenceWrapper),
-                mock(DumpManager::class.java),
-                userTracker
+                mock(DumpManager::class.java)
         )
         assertEquals(listOf(TEST_STRUCTURE_INFO), controller_other.getFavorites())
     }
@@ -518,14 +512,8 @@
         delayableExecutor.runAllReady()
 
         reset(persistenceWrapper)
-        val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
-            putExtra(Intent.EXTRA_USER_HANDLE, otherUser)
-        }
-        val pendingResult = mock(BroadcastReceiver.PendingResult::class.java)
-        `when`(pendingResult.sendingUserId).thenReturn(otherUser)
-        broadcastReceiverCaptor.value.pendingResult = pendingResult
 
-        broadcastReceiverCaptor.value.onReceive(mContext, intent)
+        userTrackerCallbackCaptor.value.onUserChanged(otherUser, mContext)
 
         verify(persistenceWrapper).changeFileAndBackupManager(any(), any())
         verify(persistenceWrapper).readFavorites()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
index 77f451f..48fc46b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt
@@ -17,19 +17,18 @@
 package com.android.systemui.controls.dagger
 
 import android.testing.AndroidTestingRunner
-import android.provider.Settings
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED
 import com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.FakeControlsSettingsRepository
 import com.android.systemui.controls.controller.ControlsController
 import com.android.systemui.controls.controller.ControlsTileResourceConfiguration
 import com.android.systemui.controls.management.ControlsListingController
 import com.android.systemui.controls.ui.ControlsUiController
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.util.settings.SecureSettings
 import dagger.Lazy
 import java.util.Optional
 import org.junit.Assert.assertEquals
@@ -63,13 +62,13 @@
     @Mock
     private lateinit var lockPatternUtils: LockPatternUtils
     @Mock
-    private lateinit var secureSettings: SecureSettings
-    @Mock
     private lateinit var optionalControlsTileResourceConfiguration:
             Optional<ControlsTileResourceConfiguration>
     @Mock
     private lateinit var controlsTileResourceConfiguration: ControlsTileResourceConfiguration
 
+    private lateinit var controlsSettingsRepository: FakeControlsSettingsRepository
+
     companion object {
         fun <T> eq(value: T): T = Mockito.eq(value) ?: value
     }
@@ -78,6 +77,8 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
+        controlsSettingsRepository = FakeControlsSettingsRepository()
+
         `when`(userTracker.userHandle.identifier).thenReturn(0)
         `when`(optionalControlsTileResourceConfiguration.orElse(any()))
             .thenReturn(controlsTileResourceConfiguration)
@@ -125,8 +126,7 @@
         `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
             .thenReturn(STRONG_AUTH_NOT_REQUIRED)
         `when`(keyguardStateController.isUnlocked()).thenReturn(false)
-        `when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt()))
-            .thenReturn(0)
+        controlsSettingsRepository.setCanShowControlsInLockscreen(false)
         val component = setupComponent(true)
 
         assertEquals(ControlsComponent.Visibility.AVAILABLE_AFTER_UNLOCK, component.getVisibility())
@@ -137,9 +137,7 @@
         `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
             .thenReturn(STRONG_AUTH_NOT_REQUIRED)
         `when`(keyguardStateController.isUnlocked()).thenReturn(false)
-        `when`(secureSettings.getIntForUser(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS),
-                anyInt(), anyInt()))
-            .thenReturn(1)
+        controlsSettingsRepository.setCanShowControlsInLockscreen(true)
         val component = setupComponent(true)
 
         assertEquals(ControlsComponent.Visibility.AVAILABLE, component.getVisibility())
@@ -147,8 +145,7 @@
 
     @Test
     fun testFeatureEnabledAndCanShowWhileUnlockedVisibility() {
-        `when`(secureSettings.getInt(eq(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS), anyInt()))
-            .thenReturn(0)
+        controlsSettingsRepository.setCanShowControlsInLockscreen(false)
         `when`(lockPatternUtils.getStrongAuthForUser(anyInt()))
             .thenReturn(STRONG_AUTH_NOT_REQUIRED)
         `when`(keyguardStateController.isUnlocked()).thenReturn(true)
@@ -187,7 +184,7 @@
             lockPatternUtils,
             keyguardStateController,
             userTracker,
-            secureSettings,
+            controlsSettingsRepository,
             optionalControlsTileResourceConfiguration
         )
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index 98ff8d1..c677f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -31,6 +31,7 @@
 import android.testing.AndroidTestingRunner
 import androidx.test.filters.SmallTest
 import com.android.settingslib.applications.ServiceListing
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.controls.ControlsServiceInfo
 import com.android.systemui.dump.DumpManager
@@ -110,6 +111,12 @@
                 .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED)
         mContext.setMockPackageManager(packageManager)
 
+        mContext.orCreateTestableResources
+                .addOverride(
+                        R.array.config_controlsPreferredPackages,
+                        arrayOf(componentName.packageName)
+                )
+
         // Return true by default, we'll test the false path
         `when`(featureFlags.isEnabled(USE_APP_PANELS)).thenReturn(true)
 
@@ -482,6 +489,35 @@
     }
 
     @Test
+    fun testPackageNotPreferred_nullPanel() {
+        mContext.orCreateTestableResources
+                .addOverride(R.array.config_controlsPreferredPackages, arrayOf<String>())
+
+        val serviceInfo = ServiceInfo(
+                componentName,
+                activityName
+        )
+
+        `when`(packageManager.getComponentEnabledSetting(eq(activityName)))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
+
+        setUpQueryResult(listOf(
+                ActivityInfo(
+                        activityName,
+                        exported = true,
+                        permission = Manifest.permission.BIND_CONTROLS
+                )
+        ))
+
+        val list = listOf(serviceInfo)
+        serviceListingCallbackCaptor.value.onServicesReloaded(list)
+
+        executor.runAllReady()
+
+        assertNull(controller.getCurrentServices()[0].panelActivity)
+    }
+
+    @Test
     fun testListingsNotModifiedByCallback() {
         // This test checks that if the list passed to the callback is modified, it has no effect
         // in the resulting services
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
index 7a2ba95..06a944e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutEngineTest.java
@@ -361,8 +361,7 @@
             assertThat(lp.getMarginEnd()).isEqualTo(margin);
         });
 
-        // The third view should be at the top end corner. No margin should be applied if not
-        // specified.
+        // The third view should be at the top end corner. No margin should be applied.
         verifyChange(thirdViewInfo, true, lp -> {
             assertThat(lp.topToTop == ConstraintLayout.LayoutParams.PARENT_ID).isTrue();
             assertThat(lp.endToEnd == ConstraintLayout.LayoutParams.PARENT_ID).isTrue();
@@ -442,65 +441,129 @@
     }
 
     /**
-     * Ensures the root complication applies margin if specified.
+     * Ensures layout sets correct max width constraint.
      */
     @Test
-    public void testRootComplicationSpecifiedMargin() {
-        final int defaultMargin = 5;
-        final int complicationMargin = 10;
+    public void testWidthConstraint() {
+        final int maxWidth = 20;
         final ComplicationLayoutEngine engine =
-                new ComplicationLayoutEngine(mLayout, defaultMargin, mTouchSession, 0, 0);
+                new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
 
-        final ViewInfo firstViewInfo = new ViewInfo(
+        final ViewInfo viewStartDirection = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_START,
+                        0,
+                        5,
+                        maxWidth),
+                Complication.CATEGORY_STANDARD,
+                mLayout);
+        final ViewInfo viewEndDirection = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_TOP
+                                | ComplicationLayoutParams.POSITION_START,
+                        ComplicationLayoutParams.DIRECTION_END,
+                        0,
+                        5,
+                        maxWidth),
+                Complication.CATEGORY_STANDARD,
+                mLayout);
+
+        addComplication(engine, viewStartDirection);
+        addComplication(engine, viewEndDirection);
+
+        // Verify both horizontal direction views have max width set correctly, and max height is
+        // not set.
+        verifyChange(viewStartDirection, false, lp -> {
+            assertThat(lp.matchConstraintMaxWidth).isEqualTo(maxWidth);
+            assertThat(lp.matchConstraintMaxHeight).isEqualTo(0);
+        });
+        verifyChange(viewEndDirection, false, lp -> {
+            assertThat(lp.matchConstraintMaxWidth).isEqualTo(maxWidth);
+            assertThat(lp.matchConstraintMaxHeight).isEqualTo(0);
+        });
+    }
+
+    /**
+     * Ensures layout sets correct max height constraint.
+     */
+    @Test
+    public void testHeightConstraint() {
+        final int maxHeight = 20;
+        final ComplicationLayoutEngine engine =
+                new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
+
+        final ViewInfo viewUpDirection = new ViewInfo(
+                new ComplicationLayoutParams(
+                        100,
+                        100,
+                        ComplicationLayoutParams.POSITION_BOTTOM
+                                | ComplicationLayoutParams.POSITION_END,
+                        ComplicationLayoutParams.DIRECTION_UP,
+                        0,
+                        5,
+                        maxHeight),
+                Complication.CATEGORY_STANDARD,
+                mLayout);
+        final ViewInfo viewDownDirection = new ViewInfo(
                 new ComplicationLayoutParams(
                         100,
                         100,
                         ComplicationLayoutParams.POSITION_TOP
                                 | ComplicationLayoutParams.POSITION_END,
                         ComplicationLayoutParams.DIRECTION_DOWN,
-                        0),
+                        0,
+                        5,
+                        maxHeight),
                 Complication.CATEGORY_STANDARD,
                 mLayout);
 
-        addComplication(engine, firstViewInfo);
+        addComplication(engine, viewUpDirection);
+        addComplication(engine, viewDownDirection);
 
-        final ViewInfo secondViewInfo = new ViewInfo(
+        // Verify both vertical direction views have max height set correctly, and max width is
+        // not set.
+        verifyChange(viewUpDirection, false, lp -> {
+            assertThat(lp.matchConstraintMaxHeight).isEqualTo(maxHeight);
+            assertThat(lp.matchConstraintMaxWidth).isEqualTo(0);
+        });
+        verifyChange(viewDownDirection, false, lp -> {
+            assertThat(lp.matchConstraintMaxHeight).isEqualTo(maxHeight);
+            assertThat(lp.matchConstraintMaxWidth).isEqualTo(0);
+        });
+    }
+
+    /**
+     * Ensures layout does not set any constraint if not specified.
+     */
+    @Test
+    public void testConstraintNotSetWhenNotSpecified() {
+        final ComplicationLayoutEngine engine =
+                new ComplicationLayoutEngine(mLayout, 0, mTouchSession, 0, 0);
+
+        final ViewInfo view = new ViewInfo(
                 new ComplicationLayoutParams(
                         100,
                         100,
                         ComplicationLayoutParams.POSITION_TOP
                                 | ComplicationLayoutParams.POSITION_END,
-                        ComplicationLayoutParams.DIRECTION_START,
-                        0),
-                Complication.CATEGORY_SYSTEM,
+                        ComplicationLayoutParams.DIRECTION_DOWN,
+                        0,
+                        5),
+                Complication.CATEGORY_STANDARD,
                 mLayout);
 
-        addComplication(engine, secondViewInfo);
+        addComplication(engine, view);
 
-        firstViewInfo.clearInvocations();
-        secondViewInfo.clearInvocations();
-
-        final ViewInfo thirdViewInfo = new ViewInfo(
-                new ComplicationLayoutParams(
-                        100,
-                        100,
-                        ComplicationLayoutParams.POSITION_TOP
-                                | ComplicationLayoutParams.POSITION_END,
-                        ComplicationLayoutParams.DIRECTION_START,
-                        1,
-                        complicationMargin),
-                Complication.CATEGORY_SYSTEM,
-                mLayout);
-
-        addComplication(engine, thirdViewInfo);
-
-        // The third view is the root view and has specified margin, which should be applied based
-        // on its direction.
-        verifyChange(thirdViewInfo, true, lp -> {
-            assertThat(lp.getMarginStart()).isEqualTo(0);
-            assertThat(lp.getMarginEnd()).isEqualTo(complicationMargin);
-            assertThat(lp.topMargin).isEqualTo(0);
-            assertThat(lp.bottomMargin).isEqualTo(0);
+        // Verify neither max height nor max width set.
+        verifyChange(view, false, lp -> {
+            assertThat(lp.matchConstraintMaxHeight).isEqualTo(0);
+            assertThat(lp.matchConstraintMaxWidth).isEqualTo(0);
         });
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
index ce7561e..fdb4cc4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/ComplicationLayoutParamsTest.java
@@ -97,35 +97,10 @@
     }
 
     /**
-     * Ensures ComplicationLayoutParams correctly returns whether the complication specified margin.
-     */
-    @Test
-    public void testIsMarginSpecified() {
-        final ComplicationLayoutParams paramsNoMargin = new ComplicationLayoutParams(
-                100,
-                100,
-                ComplicationLayoutParams.POSITION_TOP
-                        | ComplicationLayoutParams.POSITION_START,
-                ComplicationLayoutParams.DIRECTION_DOWN,
-                0);
-        assertThat(paramsNoMargin.isMarginSpecified()).isFalse();
-
-        final ComplicationLayoutParams paramsWithMargin = new ComplicationLayoutParams(
-                100,
-                100,
-                ComplicationLayoutParams.POSITION_TOP
-                        | ComplicationLayoutParams.POSITION_START,
-                ComplicationLayoutParams.DIRECTION_DOWN,
-                0,
-                20 /*margin*/);
-        assertThat(paramsWithMargin.isMarginSpecified()).isTrue();
-    }
-
-    /**
      * Ensures unspecified margin uses default.
      */
     @Test
-    public void testUnspecifiedMarginUsesDefault() {
+    public void testDefaultMargin() {
         final ComplicationLayoutParams params = new ComplicationLayoutParams(
                 100,
                 100,
@@ -161,13 +136,15 @@
                 ComplicationLayoutParams.POSITION_TOP,
                 ComplicationLayoutParams.DIRECTION_DOWN,
                 3,
-                10);
+                10,
+                20);
         final ComplicationLayoutParams copy = new ComplicationLayoutParams(params);
 
         assertThat(copy.getDirection() == params.getDirection()).isTrue();
         assertThat(copy.getPosition() == params.getPosition()).isTrue();
         assertThat(copy.getWeight() == params.getWeight()).isTrue();
         assertThat(copy.getMargin(0) == params.getMargin(1)).isTrue();
+        assertThat(copy.getConstraint() == params.getConstraint()).isTrue();
         assertThat(copy.height == params.height).isTrue();
         assertThat(copy.width == params.width).isTrue();
     }
@@ -193,4 +170,31 @@
         assertThat(copy.height == params.height).isTrue();
         assertThat(copy.width == params.width).isTrue();
     }
+
+    /**
+     * Ensures that constraint is set correctly.
+     */
+    @Test
+    public void testConstraint() {
+        final ComplicationLayoutParams paramsWithoutConstraint = new ComplicationLayoutParams(
+                100,
+                100,
+                ComplicationLayoutParams.POSITION_TOP,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                3,
+                10);
+        assertThat(paramsWithoutConstraint.constraintSpecified()).isFalse();
+
+        final int constraint = 10;
+        final ComplicationLayoutParams paramsWithConstraint = new ComplicationLayoutParams(
+                100,
+                100,
+                ComplicationLayoutParams.POSITION_TOP,
+                ComplicationLayoutParams.DIRECTION_DOWN,
+                3,
+                10,
+                constraint);
+        assertThat(paramsWithConstraint.constraintSpecified()).isTrue();
+        assertThat(paramsWithConstraint.getConstraint()).isEqualTo(constraint);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
index 30ad485..e6d3a69 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/complication/DreamHomeControlsComplicationTest.java
@@ -35,6 +35,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.controls.ControlsServiceInfo;
 import com.android.systemui.controls.controller.ControlsController;
@@ -84,7 +85,10 @@
     private ArgumentCaptor<ControlsListingController.ControlsListingCallback> mCallbackCaptor;
 
     @Mock
-    private ImageView mView;
+    private View mView;
+
+    @Mock
+    private ImageView mHomeControlsView;
 
     @Mock
     private ActivityStarter mActivityStarter;
@@ -105,6 +109,7 @@
         when(mControlsComponent.getControlsListingController()).thenReturn(
                 Optional.of(mControlsListingController));
         when(mControlsComponent.getVisibility()).thenReturn(AVAILABLE);
+        when(mView.findViewById(R.id.home_controls_chip)).thenReturn(mHomeControlsView);
     }
 
     @Test
@@ -206,9 +211,9 @@
 
         final ArgumentCaptor<View.OnClickListener> clickListenerCaptor =
                 ArgumentCaptor.forClass(View.OnClickListener.class);
-        verify(mView).setOnClickListener(clickListenerCaptor.capture());
+        verify(mHomeControlsView).setOnClickListener(clickListenerCaptor.capture());
 
-        clickListenerCaptor.getValue().onClick(mView);
+        clickListenerCaptor.getValue().onClick(mHomeControlsView);
         verify(mUiEventLogger).log(
                 DreamHomeControlsComplication.DreamHomeControlsChipViewController
                         .DreamOverlayEvent.DREAM_HOME_CONTROLS_TAPPED);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt
index cedde58..cef452b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardQuickAffordanceProviderTest.kt
@@ -20,6 +20,7 @@
 import android.content.ContentValues
 import android.content.pm.PackageManager
 import android.content.pm.ProviderInfo
+import android.os.UserHandle
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SystemUIAppComponentFactoryBase
@@ -27,8 +28,10 @@
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
@@ -36,8 +39,8 @@
 import com.android.systemui.plugins.ActivityStarter
 import com.android.systemui.settings.UserFileManager
 import com.android.systemui.settings.UserTracker
-import com.android.systemui.shared.keyguard.data.content.KeyguardQuickAffordanceProviderContract as Contract
 import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderContract as Contract
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.mock
@@ -74,8 +77,8 @@
 
         underTest = KeyguardQuickAffordanceProvider()
         val scope = CoroutineScope(IMMEDIATE)
-        val selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+        val localUserSelectionManager =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock<UserFileManager>().apply {
@@ -89,12 +92,22 @@
                             .thenReturn(FakeSharedPreferences())
                     },
                 userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+        val remoteUserSelectionManager =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = scope,
+                userTracker = userTracker,
+                clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker),
+                userHandle = UserHandle.SYSTEM,
             )
         val quickAffordanceRepository =
             KeyguardQuickAffordanceRepository(
                 appContext = context,
                 scope = scope,
-                selectionManager = selectionManager,
+                localUserSelectionManager = localUserSelectionManager,
+                remoteUserSelectionManager = remoteUserSelectionManager,
+                userTracker = userTracker,
                 configs =
                     setOf(
                         FakeKeyguardQuickAffordanceConfig(
@@ -113,9 +126,10 @@
                         scope = scope,
                         backgroundDispatcher = IMMEDIATE,
                         secureSettings = FakeSettings(),
-                        selectionsManager = selectionManager,
+                        selectionsManager = localUserSelectionManager,
                     ),
                 dumpManager = mock(),
+                userHandle = UserHandle.SYSTEM,
             )
         underTest.interactor =
             KeyguardQuickAffordanceInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
index d17e374..798839d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardViewMediatorTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.keyguard;
 
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManagerPolicyConstants.OFF_BECAUSE_OF_USER;
 
 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
@@ -34,6 +35,7 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.IActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.os.PowerManager;
@@ -41,6 +43,11 @@
 import android.telephony.TelephonyManager;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.RemoteAnimationTarget;
+import android.view.View;
+import android.view.ViewRootImpl;
+import android.view.WindowManager;
 
 import androidx.test.filters.SmallTest;
 
@@ -52,21 +59,27 @@
 import com.android.keyguard.mediator.ScreenOnCoordinator;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.animation.ActivityLaunchAnimator;
+import com.android.systemui.biometrics.AuthController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.classifier.FalsingCollectorFake;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.dreams.DreamOverlayStateController;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shade.NotificationShadeWindowControllerImpl;
 import com.android.systemui.shade.ShadeController;
+import com.android.systemui.shade.ShadeExpansionStateManager;
 import com.android.systemui.statusbar.NotificationShadeDepthController;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
 import com.android.systemui.util.DeviceConfigProxy;
@@ -80,8 +93,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import dagger.Lazy;
-
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
 @SmallTest
@@ -96,11 +107,15 @@
     private @Mock BroadcastDispatcher mBroadcastDispatcher;
     private @Mock DismissCallbackRegistry mDismissCallbackRegistry;
     private @Mock DumpManager mDumpManager;
+    private @Mock WindowManager mWindowManager;
+    private @Mock IActivityManager mActivityManager;
+    private @Mock ConfigurationController mConfigurationController;
     private @Mock PowerManager mPowerManager;
     private @Mock TrustManager mTrustManager;
     private @Mock UserSwitcherController mUserSwitcherController;
     private @Mock NavigationModeController mNavigationModeController;
     private @Mock KeyguardDisplayManager mKeyguardDisplayManager;
+    private @Mock KeyguardBypassController mKeyguardBypassController;
     private @Mock DozeParameters mDozeParameters;
     private @Mock SysuiStatusBarStateController mStatusBarStateController;
     private @Mock KeyguardStateController mKeyguardStateController;
@@ -110,10 +125,13 @@
     private @Mock InteractionJankMonitor mInteractionJankMonitor;
     private @Mock ScreenOnCoordinator mScreenOnCoordinator;
     private @Mock ShadeController mShadeController;
-    private @Mock Lazy<NotificationShadeWindowController> mNotificationShadeWindowControllerLazy;
+    private NotificationShadeWindowController mNotificationShadeWindowController;
     private @Mock DreamOverlayStateController mDreamOverlayStateController;
     private @Mock ActivityLaunchAnimator mActivityLaunchAnimator;
     private @Mock ScrimController mScrimController;
+    private @Mock SysuiColorExtractor mColorExtractor;
+    private @Mock AuthController mAuthController;
+    private @Mock ShadeExpansionStateManager mShadeExpansionStateManager;
     private DeviceConfigProxy mDeviceConfig = new DeviceConfigProxyFake();
     private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
 
@@ -130,6 +148,14 @@
         when(mPowerManager.newWakeLock(anyInt(), any())).thenReturn(mock(WakeLock.class));
         when(mInteractionJankMonitor.begin(any(), anyInt())).thenReturn(true);
         when(mInteractionJankMonitor.end(anyInt())).thenReturn(true);
+        final ViewRootImpl testViewRoot = mock(ViewRootImpl.class);
+        when(testViewRoot.getView()).thenReturn(mock(View.class));
+        when(mStatusBarKeyguardViewManager.getViewRootImpl()).thenReturn(testViewRoot);
+        mNotificationShadeWindowController = new NotificationShadeWindowControllerImpl(mContext,
+                mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController,
+                mConfigurationController, mViewMediator, mKeyguardBypassController,
+                mColorExtractor, mDumpManager, mKeyguardStateController,
+                mScreenOffAnimationController, mAuthController, mShadeExpansionStateManager);
 
         createAndStartViewMediator();
     }
@@ -287,6 +313,23 @@
         verify(mCentralSurfaces).updateIsKeyguard();
     }
 
+    @Test
+    @TestableLooper.RunWithLooper(setAsMainLooper = true)
+    public void testStartKeyguardExitAnimation_expectSurfaceBehindRemoteAnimation() {
+        RemoteAnimationTarget[] apps = new RemoteAnimationTarget[]{
+                mock(RemoteAnimationTarget.class)
+        };
+        RemoteAnimationTarget[] wallpapers = new RemoteAnimationTarget[]{
+                mock(RemoteAnimationTarget.class)
+        };
+        IRemoteAnimationFinishedCallback callback = mock(IRemoteAnimationFinishedCallback.class);
+
+        mViewMediator.startKeyguardExitAnimation(TRANSIT_OLD_KEYGUARD_GOING_AWAY, apps, wallpapers,
+                null, callback);
+        TestableLooper.get(this).processAllMessages();
+        assertTrue(mViewMediator.isAnimatingBetweenKeyguardAndSurfaceBehind());
+    }
+
     private void createAndStartViewMediator() {
         mViewMediator = new KeyguardViewMediator(
                 mContext,
@@ -315,7 +358,7 @@
                 mInteractionJankMonitor,
                 mDreamOverlayStateController,
                 () -> mShadeController,
-                mNotificationShadeWindowControllerLazy,
+                () -> mNotificationShadeWindowController,
                 () -> mActivityLaunchAnimator,
                 () -> mScrimController);
         mViewMediator.start();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
index 623becf..7205f30 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/CameraQuickAffordanceConfigTest.kt
@@ -37,25 +37,29 @@
 
     @Mock private lateinit var cameraGestureHelper: CameraGestureHelper
     @Mock private lateinit var context: Context
+
     private lateinit var underTest: CameraQuickAffordanceConfig
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
-        underTest = CameraQuickAffordanceConfig(
+
+        underTest =
+            CameraQuickAffordanceConfig(
                 context,
-                cameraGestureHelper,
-        )
+            ) {
+                cameraGestureHelper
+            }
     }
 
     @Test
     fun `affordance triggered -- camera launch called`() {
-        //when
+        // When
         val result = underTest.onTriggered(null)
 
-        //then
+        // Then
         verify(cameraGestureHelper)
-                .launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
+            .launchCamera(StatusBarManager.CAMERA_LAUNCH_SOURCE_QUICK_AFFORDANCE)
         assertEquals(KeyguardQuickAffordanceConfig.OnTriggeredResult.Handled, result)
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
new file mode 100644
index 0000000..9fa7db1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/FlashlightQuickAffordanceConfigTest.kt
@@ -0,0 +1,215 @@
+/*
+ *  Copyright (C) 2022 The Android Open Source Project
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.Context
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.keyguard.shared.quickaffordance.ActivationState
+import com.android.systemui.statusbar.policy.FlashlightController
+import com.android.systemui.utils.leaks.FakeFlashlightController
+import com.android.systemui.utils.leaks.LeakCheckedTest
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class FlashlightQuickAffordanceConfigTest : LeakCheckedTest() {
+
+    @Mock private lateinit var context: Context
+    private lateinit var flashlightController: FakeFlashlightController
+    private lateinit var underTest: FlashlightQuickAffordanceConfig
+
+    @Before
+    fun setUp() {
+        injectLeakCheckedDependency(FlashlightController::class.java)
+        MockitoAnnotations.initMocks(this)
+
+        flashlightController =
+            SysuiLeakCheck().getLeakChecker(FlashlightController::class.java)
+                as FakeFlashlightController
+        underTest = FlashlightQuickAffordanceConfig(context, flashlightController)
+    }
+
+    @Test
+    fun `flashlight is off -- triggered -- icon is on and active`() = runTest {
+        // given
+        flashlightController.isEnabled = false
+        flashlightController.isAvailable = true
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        underTest.onTriggered(null)
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+        assertEquals(
+            R.drawable.qs_flashlight_icon_on,
+            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
+                    as? Icon.Resource)
+                ?.res
+        )
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight is on -- triggered -- icon is off and inactive`() = runTest {
+        // given
+        flashlightController.isEnabled = true
+        flashlightController.isAvailable = true
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        underTest.onTriggered(null)
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+        assertEquals(
+            R.drawable.qs_flashlight_icon_off,
+            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
+                    as? Icon.Resource)
+                ?.res
+        )
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight is on -- receives error -- icon is off and inactive`() = runTest {
+        // given
+        flashlightController.isEnabled = true
+        flashlightController.isAvailable = false
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        flashlightController.onFlashlightError()
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+        assertEquals(
+            R.drawable.qs_flashlight_icon_off,
+            ((lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).icon
+                    as? Icon.Resource)
+                ?.res
+        )
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight availability now off -- hidden`() = runTest {
+        // given
+        flashlightController.isEnabled = true
+        flashlightController.isAvailable = false
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        flashlightController.onFlashlightAvailabilityChanged(false)
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Hidden)
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight availability now on -- flashlight on -- inactive and icon off`() = runTest {
+        // given
+        flashlightController.isEnabled = true
+        flashlightController.isAvailable = false
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        flashlightController.onFlashlightAvailabilityChanged(true)
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+        assertTrue(
+            (lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState
+                is ActivationState.Active
+        )
+        assertEquals(R.drawable.qs_flashlight_icon_on, (lastValue.icon as? Icon.Resource)?.res)
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight availability now on -- flashlight off -- inactive and icon off`() = runTest {
+        // given
+        flashlightController.isEnabled = false
+        flashlightController.isAvailable = false
+        val values = mutableListOf<KeyguardQuickAffordanceConfig.LockScreenState>()
+        val job = launch(UnconfinedTestDispatcher()) { underTest.lockScreenState.toList(values) }
+
+        // when
+        flashlightController.onFlashlightAvailabilityChanged(true)
+        val lastValue = values.last()
+
+        // then
+        assertTrue(lastValue is KeyguardQuickAffordanceConfig.LockScreenState.Visible)
+        assertTrue(
+            (lastValue as KeyguardQuickAffordanceConfig.LockScreenState.Visible).activationState
+                is ActivationState.Inactive
+        )
+        assertEquals(R.drawable.qs_flashlight_icon_off, (lastValue.icon as? Icon.Resource)?.res)
+        job.cancel()
+    }
+
+    @Test
+    fun `flashlight available -- picker state default`() = runTest {
+        // given
+        flashlightController.isAvailable = true
+
+        // when
+        val result = underTest.getPickerScreenState()
+
+        // then
+        assertTrue(result is KeyguardQuickAffordanceConfig.PickerScreenState.Default)
+    }
+
+    @Test
+    fun `flashlight not available -- picker state unavailable`() = runTest {
+        // given
+        flashlightController.isAvailable = false
+
+        // when
+        val result = underTest.getPickerScreenState()
+
+        // then
+        assertTrue(result is KeyguardQuickAffordanceConfig.PickerScreenState.UnavailableOnDevice)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
index 8ef921e..3b0169d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLegacySettingSyncerTest.kt
@@ -57,7 +57,7 @@
 
     private lateinit var testScope: TestScope
     private lateinit var testDispatcher: TestDispatcher
-    private lateinit var selectionManager: KeyguardQuickAffordanceSelectionManager
+    private lateinit var selectionManager: KeyguardQuickAffordanceLocalUserSelectionManager
     private lateinit var settings: FakeSettings
 
     @Before
@@ -75,7 +75,7 @@
         testDispatcher = UnconfinedTestDispatcher()
         testScope = TestScope(testDispatcher)
         selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock {
@@ -89,6 +89,7 @@
                             .thenReturn(FakeSharedPreferences())
                     },
                 userTracker = FakeUserTracker(),
+                broadcastDispatcher = fakeBroadcastDispatcher,
             )
         settings = FakeSettings()
         settings.putInt(Settings.Secure.LOCKSCREEN_SHOW_CONTROLS, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
new file mode 100644
index 0000000..67091a9
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceLocalUserSelectionManagerTest.kt
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.UserInfo
+import androidx.test.filters.SmallTest
+import com.android.systemui.R
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.settings.UserFileManager
+import com.android.systemui.util.FakeSharedPreferences
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.resetMain
+import kotlinx.coroutines.test.runTest
+import kotlinx.coroutines.test.setMain
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.Mock
+import org.mockito.Mockito.atLeastOnce
+import org.mockito.Mockito.clearInvocations
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardQuickAffordanceLocalUserSelectionManagerTest : SysuiTestCase() {
+
+    @Mock private lateinit var userFileManager: UserFileManager
+
+    private lateinit var underTest: KeyguardQuickAffordanceLocalUserSelectionManager
+
+    private lateinit var userTracker: FakeUserTracker
+    private lateinit var sharedPrefs: MutableMap<Int, SharedPreferences>
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        sharedPrefs = mutableMapOf()
+        whenever(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())).thenAnswer {
+            val userId = it.arguments[2] as Int
+            sharedPrefs.getOrPut(userId) { FakeSharedPreferences() }
+        }
+        userTracker = FakeUserTracker()
+        val dispatcher = UnconfinedTestDispatcher()
+        Dispatchers.setMain(dispatcher)
+
+        underTest =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
+                context = context,
+                userFileManager = userFileManager,
+                userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+    }
+
+    @After
+    fun tearDown() {
+        Dispatchers.resetMain()
+    }
+
+    @Test
+    fun setSelections() = runTest {
+        overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>())
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+        val slotId1 = "slot1"
+        val slotId2 = "slot2"
+        val affordanceId1 = "affordance1"
+        val affordanceId2 = "affordance2"
+        val affordanceId3 = "affordance3"
+
+        underTest.setSelections(
+            slotId = slotId1,
+            affordanceIds = listOf(affordanceId1),
+        )
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId1),
+            ),
+        )
+
+        underTest.setSelections(
+            slotId = slotId2,
+            affordanceIds = listOf(affordanceId2),
+        )
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId1),
+                slotId2 to listOf(affordanceId2),
+            )
+        )
+
+        underTest.setSelections(
+            slotId = slotId1,
+            affordanceIds = listOf(affordanceId1, affordanceId3),
+        )
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId1, affordanceId3),
+                slotId2 to listOf(affordanceId2),
+            )
+        )
+
+        underTest.setSelections(
+            slotId = slotId1,
+            affordanceIds = listOf(affordanceId3),
+        )
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId3),
+                slotId2 to listOf(affordanceId2),
+            )
+        )
+
+        underTest.setSelections(
+            slotId = slotId2,
+            affordanceIds = listOf(),
+        )
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId3),
+                slotId2 to listOf(),
+            )
+        )
+
+        job.cancel()
+    }
+
+    @Test
+    fun `remembers selections by user`() = runTest {
+        val slot1 = "slot_1"
+        val slot2 = "slot_2"
+        val affordance1 = "affordance_1"
+        val affordance2 = "affordance_2"
+        val affordance3 = "affordance_3"
+
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+
+        val userInfos =
+            listOf(
+                UserInfo(/* id= */ 0, "zero", /* flags= */ 0),
+                UserInfo(/* id= */ 1, "one", /* flags= */ 0),
+            )
+        userTracker.set(
+            userInfos = userInfos,
+            selectedUserIndex = 0,
+        )
+        underTest.setSelections(
+            slotId = slot1,
+            affordanceIds = listOf(affordance1),
+        )
+        underTest.setSelections(
+            slotId = slot2,
+            affordanceIds = listOf(affordance2),
+        )
+
+        // Switch to user 1
+        userTracker.set(
+            userInfos = userInfos,
+            selectedUserIndex = 1,
+        )
+        // We never set selections on user 1, so it should be empty.
+        assertSelections(
+            observed = affordanceIdsBySlotId.last(),
+            expected = emptyMap(),
+        )
+        // Now, let's set selections on user 1.
+        underTest.setSelections(
+            slotId = slot1,
+            affordanceIds = listOf(affordance2),
+        )
+        underTest.setSelections(
+            slotId = slot2,
+            affordanceIds = listOf(affordance3),
+        )
+        assertSelections(
+            observed = affordanceIdsBySlotId.last(),
+            expected =
+                mapOf(
+                    slot1 to listOf(affordance2),
+                    slot2 to listOf(affordance3),
+                ),
+        )
+
+        // Switch back to user 0.
+        userTracker.set(
+            userInfos = userInfos,
+            selectedUserIndex = 0,
+        )
+        // Assert that we still remember the old selections for user 0.
+        assertSelections(
+            observed = affordanceIdsBySlotId.last(),
+            expected =
+                mapOf(
+                    slot1 to listOf(affordance1),
+                    slot2 to listOf(affordance2),
+                ),
+        )
+
+        job.cancel()
+    }
+
+    @Test
+    fun `selections respects defaults`() = runTest {
+        val slotId1 = "slot1"
+        val slotId2 = "slot2"
+        val affordanceId1 = "affordance1"
+        val affordanceId2 = "affordance2"
+        val affordanceId3 = "affordance3"
+        overrideResource(
+            R.array.config_keyguardQuickAffordanceDefaults,
+            arrayOf(
+                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
+                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
+            ),
+        )
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId1, affordanceId3),
+                slotId2 to listOf(affordanceId2),
+            ),
+        )
+
+        job.cancel()
+    }
+
+    @Test
+    fun `selections ignores defaults after selecting an affordance`() = runTest {
+        val slotId1 = "slot1"
+        val slotId2 = "slot2"
+        val affordanceId1 = "affordance1"
+        val affordanceId2 = "affordance2"
+        val affordanceId3 = "affordance3"
+        overrideResource(
+            R.array.config_keyguardQuickAffordanceDefaults,
+            arrayOf(
+                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
+                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
+            ),
+        )
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+
+        underTest.setSelections(slotId1, listOf(affordanceId2))
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(affordanceId2),
+                slotId2 to listOf(affordanceId2),
+            ),
+        )
+
+        job.cancel()
+    }
+
+    @Test
+    fun `selections ignores defaults after clearing a slot`() = runTest {
+        val slotId1 = "slot1"
+        val slotId2 = "slot2"
+        val affordanceId1 = "affordance1"
+        val affordanceId2 = "affordance2"
+        val affordanceId3 = "affordance3"
+        overrideResource(
+            R.array.config_keyguardQuickAffordanceDefaults,
+            arrayOf(
+                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
+                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
+            ),
+        )
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+
+        underTest.setSelections(slotId1, listOf())
+        assertSelections(
+            affordanceIdsBySlotId.last(),
+            mapOf(
+                slotId1 to listOf(),
+                slotId2 to listOf(affordanceId2),
+            ),
+        )
+
+        job.cancel()
+    }
+
+    @Test
+    fun `responds to backup and restore by reloading the selections from disk`() = runTest {
+        overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>())
+        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
+        val job =
+            launch(UnconfinedTestDispatcher()) {
+                underTest.selections.toList(affordanceIdsBySlotId)
+            }
+        clearInvocations(userFileManager)
+
+        fakeBroadcastDispatcher.registeredReceivers.firstOrNull()?.onReceive(context, Intent())
+
+        verify(userFileManager, atLeastOnce()).getSharedPreferences(anyString(), anyInt(), anyInt())
+        job.cancel()
+    }
+
+    private fun assertSelections(
+        observed: Map<String, List<String>>?,
+        expected: Map<String, List<String>>,
+    ) {
+        assertThat(underTest.getSelections()).isEqualTo(expected)
+        assertThat(observed).isEqualTo(expected)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
new file mode 100644
index 0000000..d7e9cf1
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceRemoteUserSelectionManagerTest.kt
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import android.content.pm.UserInfo
+import android.os.UserHandle
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.settings.FakeUserTracker
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyguardQuickAffordanceRemoteUserSelectionManagerTest : SysuiTestCase() {
+
+    @Mock private lateinit var userHandle: UserHandle
+
+    private lateinit var underTest: KeyguardQuickAffordanceRemoteUserSelectionManager
+
+    private lateinit var clientFactory: FakeKeyguardQuickAffordanceProviderClientFactory
+    private lateinit var testScope: TestScope
+    private lateinit var testDispatcher: TestDispatcher
+    private lateinit var userTracker: FakeUserTracker
+    private lateinit var client1: FakeKeyguardQuickAffordanceProviderClient
+    private lateinit var client2: FakeKeyguardQuickAffordanceProviderClient
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        whenever(userHandle.identifier).thenReturn(UserHandle.USER_SYSTEM)
+        whenever(userHandle.isSystem).thenReturn(true)
+        client1 = FakeKeyguardQuickAffordanceProviderClient()
+        client2 = FakeKeyguardQuickAffordanceProviderClient()
+
+        userTracker = FakeUserTracker()
+        userTracker.set(
+            userInfos =
+                listOf(
+                    UserInfo(
+                        UserHandle.USER_SYSTEM,
+                        "Primary",
+                        /* flags= */ 0,
+                    ),
+                    UserInfo(
+                        OTHER_USER_ID_1,
+                        "Secondary 1",
+                        /* flags= */ 0,
+                    ),
+                    UserInfo(
+                        OTHER_USER_ID_2,
+                        "Secondary 2",
+                        /* flags= */ 0,
+                    ),
+                ),
+            selectedUserIndex = 0,
+        )
+
+        clientFactory =
+            FakeKeyguardQuickAffordanceProviderClientFactory(
+                userTracker,
+            ) { selectedUserId ->
+                when (selectedUserId) {
+                    OTHER_USER_ID_1 -> client1
+                    OTHER_USER_ID_2 -> client2
+                    else -> error("No client set-up for user $selectedUserId!")
+                }
+            }
+
+        testDispatcher = StandardTestDispatcher()
+        testScope = TestScope(testDispatcher)
+
+        underTest =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = testScope.backgroundScope,
+                userTracker = userTracker,
+                clientFactory = clientFactory,
+                userHandle = userHandle,
+            )
+    }
+
+    @Test
+    fun `selections - primary user process`() =
+        testScope.runTest {
+            val values = mutableListOf<Map<String, List<String>>>()
+            val job = launch { underTest.selections.toList(values) }
+
+            runCurrent()
+            assertThat(values.last()).isEmpty()
+
+            client1.insertSelection(
+                slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
+            )
+            client2.insertSelection(
+                slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END,
+                affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2,
+            )
+
+            userTracker.set(
+                userInfos = userTracker.userProfiles,
+                selectedUserIndex = 1,
+            )
+            runCurrent()
+            assertThat(values.last())
+                .isEqualTo(
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
+                            listOf(
+                                FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
+                            ),
+                    )
+                )
+
+            userTracker.set(
+                userInfos = userTracker.userProfiles,
+                selectedUserIndex = 2,
+            )
+            runCurrent()
+            assertThat(values.last())
+                .isEqualTo(
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_END to
+                            listOf(
+                                FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2,
+                            ),
+                    )
+                )
+
+            job.cancel()
+        }
+
+    @Test
+    fun `selections - secondary user process - always empty`() =
+        testScope.runTest {
+            whenever(userHandle.isSystem).thenReturn(false)
+            val values = mutableListOf<Map<String, List<String>>>()
+            val job = launch { underTest.selections.toList(values) }
+
+            runCurrent()
+            assertThat(values.last()).isEmpty()
+
+            client1.insertSelection(
+                slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
+            )
+            userTracker.set(
+                userInfos = userTracker.userProfiles,
+                selectedUserIndex = 1,
+            )
+            runCurrent()
+            assertThat(values.last()).isEmpty()
+
+            job.cancel()
+        }
+
+    @Test
+    fun setSelections() =
+        testScope.runTest {
+            userTracker.set(
+                userInfos = userTracker.userProfiles,
+                selectedUserIndex = 1,
+            )
+            runCurrent()
+
+            underTest.setSelections(
+                slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                affordanceIds = listOf(FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1),
+            )
+            runCurrent()
+
+            assertThat(underTest.getSelections())
+                .isEqualTo(
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
+                            listOf(
+                                FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1,
+                            ),
+                    )
+                )
+        }
+
+    companion object {
+        private const val OTHER_USER_ID_1 = UserHandle.MIN_SECONDARY_USER_ID + 1
+        private const val OTHER_USER_ID_2 = UserHandle.MIN_SECONDARY_USER_ID + 2
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt
deleted file mode 100644
index d8ee9f1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/quickaffordance/KeyguardQuickAffordanceSelectionManagerTest.kt
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.keyguard.data.quickaffordance
-
-import android.content.SharedPreferences
-import android.content.pm.UserInfo
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.settings.FakeUserTracker
-import com.android.systemui.settings.UserFileManager
-import com.android.systemui.util.FakeSharedPreferences
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.toList
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.ArgumentMatchers.anyInt
-import org.mockito.ArgumentMatchers.anyString
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(JUnit4::class)
-class KeyguardQuickAffordanceSelectionManagerTest : SysuiTestCase() {
-
-    @Mock private lateinit var userFileManager: UserFileManager
-
-    private lateinit var underTest: KeyguardQuickAffordanceSelectionManager
-
-    private lateinit var userTracker: FakeUserTracker
-    private lateinit var sharedPrefs: MutableMap<Int, SharedPreferences>
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        sharedPrefs = mutableMapOf()
-        whenever(userFileManager.getSharedPreferences(anyString(), anyInt(), anyInt())).thenAnswer {
-            val userId = it.arguments[2] as Int
-            sharedPrefs.getOrPut(userId) { FakeSharedPreferences() }
-        }
-        userTracker = FakeUserTracker()
-
-        underTest =
-            KeyguardQuickAffordanceSelectionManager(
-                context = context,
-                userFileManager = userFileManager,
-                userTracker = userTracker,
-            )
-    }
-
-    @Test
-    fun setSelections() = runTest {
-        overrideResource(R.array.config_keyguardQuickAffordanceDefaults, arrayOf<String>())
-        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
-        val job =
-            launch(UnconfinedTestDispatcher()) {
-                underTest.selections.toList(affordanceIdsBySlotId)
-            }
-        val slotId1 = "slot1"
-        val slotId2 = "slot2"
-        val affordanceId1 = "affordance1"
-        val affordanceId2 = "affordance2"
-        val affordanceId3 = "affordance3"
-
-        underTest.setSelections(
-            slotId = slotId1,
-            affordanceIds = listOf(affordanceId1),
-        )
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId1),
-            ),
-        )
-
-        underTest.setSelections(
-            slotId = slotId2,
-            affordanceIds = listOf(affordanceId2),
-        )
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId1),
-                slotId2 to listOf(affordanceId2),
-            )
-        )
-
-        underTest.setSelections(
-            slotId = slotId1,
-            affordanceIds = listOf(affordanceId1, affordanceId3),
-        )
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId1, affordanceId3),
-                slotId2 to listOf(affordanceId2),
-            )
-        )
-
-        underTest.setSelections(
-            slotId = slotId1,
-            affordanceIds = listOf(affordanceId3),
-        )
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId3),
-                slotId2 to listOf(affordanceId2),
-            )
-        )
-
-        underTest.setSelections(
-            slotId = slotId2,
-            affordanceIds = listOf(),
-        )
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId3),
-                slotId2 to listOf(),
-            )
-        )
-
-        job.cancel()
-    }
-
-    @Test
-    fun `remembers selections by user`() = runTest {
-        val slot1 = "slot_1"
-        val slot2 = "slot_2"
-        val affordance1 = "affordance_1"
-        val affordance2 = "affordance_2"
-        val affordance3 = "affordance_3"
-
-        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
-        val job =
-            launch(UnconfinedTestDispatcher()) {
-                underTest.selections.toList(affordanceIdsBySlotId)
-            }
-
-        val userInfos =
-            listOf(
-                UserInfo(/* id= */ 0, "zero", /* flags= */ 0),
-                UserInfo(/* id= */ 1, "one", /* flags= */ 0),
-            )
-        userTracker.set(
-            userInfos = userInfos,
-            selectedUserIndex = 0,
-        )
-        underTest.setSelections(
-            slotId = slot1,
-            affordanceIds = listOf(affordance1),
-        )
-        underTest.setSelections(
-            slotId = slot2,
-            affordanceIds = listOf(affordance2),
-        )
-
-        // Switch to user 1
-        userTracker.set(
-            userInfos = userInfos,
-            selectedUserIndex = 1,
-        )
-        // We never set selections on user 1, so it should be empty.
-        assertSelections(
-            observed = affordanceIdsBySlotId.last(),
-            expected = emptyMap(),
-        )
-        // Now, let's set selections on user 1.
-        underTest.setSelections(
-            slotId = slot1,
-            affordanceIds = listOf(affordance2),
-        )
-        underTest.setSelections(
-            slotId = slot2,
-            affordanceIds = listOf(affordance3),
-        )
-        assertSelections(
-            observed = affordanceIdsBySlotId.last(),
-            expected =
-                mapOf(
-                    slot1 to listOf(affordance2),
-                    slot2 to listOf(affordance3),
-                ),
-        )
-
-        // Switch back to user 0.
-        userTracker.set(
-            userInfos = userInfos,
-            selectedUserIndex = 0,
-        )
-        // Assert that we still remember the old selections for user 0.
-        assertSelections(
-            observed = affordanceIdsBySlotId.last(),
-            expected =
-                mapOf(
-                    slot1 to listOf(affordance1),
-                    slot2 to listOf(affordance2),
-                ),
-        )
-
-        job.cancel()
-    }
-
-    @Test
-    fun `selections respects defaults`() = runTest {
-        val slotId1 = "slot1"
-        val slotId2 = "slot2"
-        val affordanceId1 = "affordance1"
-        val affordanceId2 = "affordance2"
-        val affordanceId3 = "affordance3"
-        overrideResource(
-            R.array.config_keyguardQuickAffordanceDefaults,
-            arrayOf(
-                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
-                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
-            ),
-        )
-        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
-        val job =
-            launch(UnconfinedTestDispatcher()) {
-                underTest.selections.toList(affordanceIdsBySlotId)
-            }
-
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId1, affordanceId3),
-                slotId2 to listOf(affordanceId2),
-            ),
-        )
-
-        job.cancel()
-    }
-
-    @Test
-    fun `selections ignores defaults after selecting an affordance`() = runTest {
-        val slotId1 = "slot1"
-        val slotId2 = "slot2"
-        val affordanceId1 = "affordance1"
-        val affordanceId2 = "affordance2"
-        val affordanceId3 = "affordance3"
-        overrideResource(
-            R.array.config_keyguardQuickAffordanceDefaults,
-            arrayOf(
-                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
-                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
-            ),
-        )
-        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
-        val job =
-            launch(UnconfinedTestDispatcher()) {
-                underTest.selections.toList(affordanceIdsBySlotId)
-            }
-
-        underTest.setSelections(slotId1, listOf(affordanceId2))
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(affordanceId2),
-                slotId2 to listOf(affordanceId2),
-            ),
-        )
-
-        job.cancel()
-    }
-
-    @Test
-    fun `selections ignores defaults after clearing a slot`() = runTest {
-        val slotId1 = "slot1"
-        val slotId2 = "slot2"
-        val affordanceId1 = "affordance1"
-        val affordanceId2 = "affordance2"
-        val affordanceId3 = "affordance3"
-        overrideResource(
-            R.array.config_keyguardQuickAffordanceDefaults,
-            arrayOf(
-                "$slotId1:${listOf(affordanceId1, affordanceId3).joinToString(",")}",
-                "$slotId2:${listOf(affordanceId2).joinToString(",")}",
-            ),
-        )
-        val affordanceIdsBySlotId = mutableListOf<Map<String, List<String>>>()
-        val job =
-            launch(UnconfinedTestDispatcher()) {
-                underTest.selections.toList(affordanceIdsBySlotId)
-            }
-
-        underTest.setSelections(slotId1, listOf())
-        assertSelections(
-            affordanceIdsBySlotId.last(),
-            mapOf(
-                slotId1 to listOf(),
-                slotId2 to listOf(affordanceId2),
-            ),
-        )
-
-        job.cancel()
-    }
-
-    private fun assertSelections(
-        observed: Map<String, List<String>>?,
-        expected: Map<String, List<String>>,
-    ) {
-        assertThat(underTest.getSelections()).isEqualTo(expected)
-        assertThat(observed).isEqualTo(expected)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
index 5c75417..c40488a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardQuickAffordanceRepositoryTest.kt
@@ -17,17 +17,23 @@
 
 package com.android.systemui.keyguard.data.repository
 
+import android.content.pm.UserInfo
+import android.os.UserHandle
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.shared.model.KeyguardQuickAffordancePickerRepresentation
 import com.android.systemui.keyguard.shared.model.KeyguardSlotPickerRepresentation
 import com.android.systemui.settings.FakeUserTracker
 import com.android.systemui.settings.UserFileManager
+import com.android.systemui.shared.keyguard.shared.model.KeyguardQuickAffordanceSlots
+import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
 import com.android.systemui.util.FakeSharedPreferences
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -39,6 +45,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,14 +62,24 @@
 
     private lateinit var config1: FakeKeyguardQuickAffordanceConfig
     private lateinit var config2: FakeKeyguardQuickAffordanceConfig
+    private lateinit var userTracker: FakeUserTracker
+    private lateinit var client1: FakeKeyguardQuickAffordanceProviderClient
+    private lateinit var client2: FakeKeyguardQuickAffordanceProviderClient
 
     @Before
     fun setUp() {
-        config1 = FakeKeyguardQuickAffordanceConfig("built_in:1")
-        config2 = FakeKeyguardQuickAffordanceConfig("built_in:2")
+        config1 =
+            FakeKeyguardQuickAffordanceConfig(
+                FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_1
+            )
+        config2 =
+            FakeKeyguardQuickAffordanceConfig(
+                FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2
+            )
         val scope = CoroutineScope(IMMEDIATE)
-        val selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+        userTracker = FakeUserTracker()
+        val localUserSelectionManager =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock<UserFileManager>().apply {
@@ -75,23 +92,45 @@
                             )
                             .thenReturn(FakeSharedPreferences())
                     },
-                userTracker = FakeUserTracker(),
+                userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+        client1 = FakeKeyguardQuickAffordanceProviderClient()
+        client2 = FakeKeyguardQuickAffordanceProviderClient()
+        val remoteUserSelectionManager =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = scope,
+                userTracker = userTracker,
+                clientFactory =
+                    FakeKeyguardQuickAffordanceProviderClientFactory(
+                        userTracker,
+                    ) { selectedUserId ->
+                        when (selectedUserId) {
+                            SECONDARY_USER_1 -> client1
+                            SECONDARY_USER_2 -> client2
+                            else -> error("No set-up client for user $selectedUserId!")
+                        }
+                    },
+                userHandle = UserHandle.SYSTEM,
             )
 
         underTest =
             KeyguardQuickAffordanceRepository(
                 appContext = context,
                 scope = scope,
-                selectionManager = selectionManager,
+                localUserSelectionManager = localUserSelectionManager,
+                remoteUserSelectionManager = remoteUserSelectionManager,
+                userTracker = userTracker,
                 legacySettingSyncer =
                     KeyguardQuickAffordanceLegacySettingSyncer(
                         scope = scope,
                         backgroundDispatcher = IMMEDIATE,
                         secureSettings = FakeSettings(),
-                        selectionsManager = selectionManager,
+                        selectionsManager = localUserSelectionManager,
                     ),
                 configs = setOf(config1, config2),
                 dumpManager = mock(),
+                userHandle = UserHandle.SYSTEM,
             )
     }
 
@@ -186,7 +225,53 @@
             )
     }
 
-    private suspend fun assertSelections(
+    @Test
+    fun `selections for secondary user`() =
+        runBlocking(IMMEDIATE) {
+            userTracker.set(
+                userInfos =
+                    listOf(
+                        UserInfo(
+                            UserHandle.USER_SYSTEM,
+                            "Primary",
+                            /* flags= */ 0,
+                        ),
+                        UserInfo(
+                            SECONDARY_USER_1,
+                            "Secondary 1",
+                            /* flags= */ 0,
+                        ),
+                        UserInfo(
+                            SECONDARY_USER_2,
+                            "Secondary 2",
+                            /* flags= */ 0,
+                        ),
+                    ),
+                selectedUserIndex = 2,
+            )
+            client2.insertSelection(
+                slotId = KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START,
+                affordanceId = FakeKeyguardQuickAffordanceProviderClient.AFFORDANCE_2,
+            )
+            val observed = mutableListOf<Map<String, List<KeyguardQuickAffordanceConfig>>>()
+            val job = underTest.selections.onEach { observed.add(it) }.launchIn(this)
+            yield()
+
+            assertSelections(
+                observed = observed.last(),
+                expected =
+                    mapOf(
+                        KeyguardQuickAffordanceSlots.SLOT_ID_BOTTOM_START to
+                            listOf(
+                                config2,
+                            ),
+                    )
+            )
+
+            job.cancel()
+        }
+
+    private fun assertSelections(
         observed: Map<String, List<KeyguardQuickAffordanceConfig>>?,
         expected: Map<String, List<KeyguardQuickAffordanceConfig>>,
     ) {
@@ -200,5 +285,7 @@
 
     companion object {
         private val IMMEDIATE = Dispatchers.Main.immediate
+        private const val SECONDARY_USER_1 = UserHandle.MIN_SECONDARY_USER_ID + 1
+        private const val SECONDARY_USER_2 = UserHandle.MIN_SECONDARY_USER_ID + 2
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 13fc9fc..5deac19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -16,10 +16,13 @@
 
 package com.android.systemui.keyguard.data.repository
 
+import android.graphics.Point
+import android.hardware.biometrics.BiometricSourceType
 import androidx.test.filters.SmallTest
 import com.android.keyguard.KeyguardUpdateMonitor
 import com.android.keyguard.KeyguardUpdateMonitorCallback
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.biometrics.AuthController
 import com.android.systemui.common.shared.model.Position
 import com.android.systemui.doze.DozeHost
 import com.android.systemui.doze.DozeMachine
@@ -27,9 +30,11 @@
 import com.android.systemui.doze.DozeTransitionListener
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.keyguard.shared.model.DozeStateModel
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.policy.KeyguardStateController
@@ -57,9 +62,10 @@
     @Mock private lateinit var dozeHost: DozeHost
     @Mock private lateinit var keyguardStateController: KeyguardStateController
     @Mock private lateinit var wakefulnessLifecycle: WakefulnessLifecycle
-    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
     @Mock private lateinit var biometricUnlockController: BiometricUnlockController
     @Mock private lateinit var dozeTransitionListener: DozeTransitionListener
+    @Mock private lateinit var authController: AuthController
+    @Mock private lateinit var keyguardUpdateMonitor: KeyguardUpdateMonitor
 
     private lateinit var underTest: KeyguardRepositoryImpl
 
@@ -76,6 +82,7 @@
                 keyguardStateController,
                 keyguardUpdateMonitor,
                 dozeTransitionListener,
+                authController,
             )
     }
 
@@ -198,7 +205,7 @@
     fun dozeAmount() =
         runTest(UnconfinedTestDispatcher()) {
             val values = mutableListOf<Float>()
-            val job = underTest.dozeAmount.onEach(values::add).launchIn(this)
+            val job = underTest.linearDozeAmount.onEach(values::add).launchIn(this)
 
             val captor = argumentCaptor<StatusBarStateController.StateListener>()
             verify(statusBarStateController).addCallback(captor.capture())
@@ -207,7 +214,7 @@
             captor.value.onDozeAmountChanged(0.498f, 0.5f)
             captor.value.onDozeAmountChanged(0.661f, 0.65f)
 
-            assertThat(values).isEqualTo(listOf(0f, 0.4f, 0.5f, 0.65f))
+            assertThat(values).isEqualTo(listOf(0f, 0.433f, 0.498f, 0.661f))
 
             job.cancel()
             verify(statusBarStateController).removeCallback(captor.value)
@@ -217,25 +224,36 @@
     fun wakefulness() =
         runTest(UnconfinedTestDispatcher()) {
             val values = mutableListOf<WakefulnessModel>()
-            val job = underTest.wakefulnessState.onEach(values::add).launchIn(this)
+            val job = underTest.wakefulness.onEach(values::add).launchIn(this)
 
             val captor = argumentCaptor<WakefulnessLifecycle.Observer>()
             verify(wakefulnessLifecycle).addObserver(captor.capture())
 
+            whenever(wakefulnessLifecycle.wakefulness)
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_WAKING)
             captor.value.onStartedWakingUp()
+
+            whenever(wakefulnessLifecycle.wakefulness)
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_AWAKE)
             captor.value.onFinishedWakingUp()
+
+            whenever(wakefulnessLifecycle.wakefulness)
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP)
             captor.value.onStartedGoingToSleep()
+
+            whenever(wakefulnessLifecycle.wakefulness)
+                .thenReturn(WakefulnessLifecycle.WAKEFULNESS_ASLEEP)
             captor.value.onFinishedGoingToSleep()
 
-            assertThat(values)
+            assertThat(values.map { it.state })
                 .isEqualTo(
                     listOf(
                         // Initial value will be ASLEEP
-                        WakefulnessModel.ASLEEP,
-                        WakefulnessModel.STARTING_TO_WAKE,
-                        WakefulnessModel.AWAKE,
-                        WakefulnessModel.STARTING_TO_SLEEP,
-                        WakefulnessModel.ASLEEP,
+                        WakefulnessState.ASLEEP,
+                        WakefulnessState.STARTING_TO_WAKE,
+                        WakefulnessState.AWAKE,
+                        WakefulnessState.STARTING_TO_SLEEP,
+                        WakefulnessState.ASLEEP,
                     )
                 )
 
@@ -329,14 +347,20 @@
             val captor = argumentCaptor<BiometricUnlockController.BiometricModeListener>()
             verify(biometricUnlockController).addBiometricModeListener(captor.capture())
 
-            captor.value.onModeChanged(BiometricUnlockController.MODE_NONE)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_SHOW_BOUNCER)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_ONLY_WAKE)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_UNLOCK_COLLAPSING)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_DISMISS_BOUNCER)
-            captor.value.onModeChanged(BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM)
+            listOf(
+                    BiometricUnlockController.MODE_NONE,
+                    BiometricUnlockController.MODE_WAKE_AND_UNLOCK,
+                    BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING,
+                    BiometricUnlockController.MODE_SHOW_BOUNCER,
+                    BiometricUnlockController.MODE_ONLY_WAKE,
+                    BiometricUnlockController.MODE_UNLOCK_COLLAPSING,
+                    BiometricUnlockController.MODE_DISMISS_BOUNCER,
+                    BiometricUnlockController.MODE_WAKE_AND_UNLOCK_FROM_DREAM,
+                )
+                .forEach {
+                    whenever(biometricUnlockController.mode).thenReturn(it)
+                    captor.value.onModeChanged(it)
+                }
 
             assertThat(values)
                 .isEqualTo(
@@ -420,4 +444,104 @@
             job.cancel()
             verify(dozeTransitionListener).removeCallback(listener)
         }
+
+    @Test
+    fun fingerprintSensorLocation() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Point?>()
+            val job = underTest.fingerprintSensorLocation.onEach(values::add).launchIn(this)
+
+            val captor = argumentCaptor<AuthController.Callback>()
+            verify(authController).addCallback(captor.capture())
+
+            // An initial, null value should be initially emitted so that flows combined with this
+            // one
+            // emit values immediately. The sensor location is expected to be nullable, so anyone
+            // consuming it should handle that properly.
+            assertThat(values).isEqualTo(listOf(null))
+
+            listOf(Point(500, 500), Point(0, 0), null, Point(250, 250))
+                .onEach {
+                    whenever(authController.fingerprintSensorLocation).thenReturn(it)
+                    captor.value.onFingerprintLocationChanged()
+                }
+                .also { dispatchedSensorLocations ->
+                    assertThat(values).isEqualTo(listOf(null) + dispatchedSensorLocations)
+                }
+
+            job.cancel()
+        }
+
+    @Test
+    fun faceSensorLocation() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Point?>()
+            val job = underTest.faceSensorLocation.onEach(values::add).launchIn(this)
+
+            val captor = argumentCaptor<AuthController.Callback>()
+            verify(authController).addCallback(captor.capture())
+
+            // An initial, null value should be initially emitted so that flows combined with this
+            // one
+            // emit values immediately. The sensor location is expected to be nullable, so anyone
+            // consuming it should handle that properly.
+            assertThat(values).isEqualTo(listOf(null))
+
+            listOf(
+                    Point(500, 500),
+                    Point(0, 0),
+                    null,
+                    Point(250, 250),
+                )
+                .onEach {
+                    whenever(authController.faceSensorLocation).thenReturn(it)
+                    captor.value.onFaceSensorLocationChanged()
+                }
+                .also { dispatchedSensorLocations ->
+                    assertThat(values).isEqualTo(listOf(null) + dispatchedSensorLocations)
+                }
+
+            job.cancel()
+        }
+
+    @Test
+    fun biometricUnlockSource() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<BiometricUnlockSource?>()
+            val job = underTest.biometricUnlockSource.onEach(values::add).launchIn(this)
+
+            val captor = argumentCaptor<KeyguardUpdateMonitorCallback>()
+            verify(keyguardUpdateMonitor).registerCallback(captor.capture())
+
+            // An initial, null value should be initially emitted so that flows combined with this
+            // one
+            // emit values immediately. The biometric unlock source is expected to be nullable, so
+            // anyone consuming it should handle that properly.
+            assertThat(values).isEqualTo(listOf(null))
+
+            listOf(
+                    BiometricSourceType.FINGERPRINT,
+                    BiometricSourceType.IRIS,
+                    null,
+                    BiometricSourceType.FACE,
+                    BiometricSourceType.FINGERPRINT,
+                )
+                .onEach { biometricSourceType ->
+                    captor.value.onBiometricAuthenticated(0, biometricSourceType, false)
+                }
+
+            assertThat(values)
+                .isEqualTo(
+                    listOf(
+                        null,
+                        BiometricUnlockSource.FINGERPRINT_SENSOR,
+                        BiometricUnlockSource.FACE_SENSOR,
+                        null,
+                        BiometricUnlockSource.FACE_SENSOR,
+                        BiometricUnlockSource.FINGERPRINT_SENSOR,
+                    )
+                )
+
+            job.cancel()
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
index 2b03722..ce9c1da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepositoryTest.kt
@@ -22,6 +22,7 @@
 import android.util.Log.TerribleFailure
 import android.util.Log.TerribleFailureHandler
 import android.view.Choreographer.FrameCallback
+import androidx.test.filters.FlakyTest
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Interpolators
@@ -97,6 +98,7 @@
         }
 
     @Test
+    @FlakyTest(bugId = 260213291)
     fun `starting second transition will cancel the first transition`() {
         runBlocking(IMMEDIATE) {
             val (animator, provider) = setupAnimator(this)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
new file mode 100644
index 0000000..d2db910
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/LightRevealScrimRepositoryTest.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.repository
+
+import android.graphics.Point
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
+import com.android.systemui.statusbar.CircleReveal
+import com.android.systemui.statusbar.LightRevealEffect
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LightRevealScrimRepositoryTest : SysuiTestCase() {
+    private lateinit var fakeKeyguardRepository: FakeKeyguardRepository
+    private lateinit var underTest: LightRevealScrimRepositoryImpl
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        fakeKeyguardRepository = FakeKeyguardRepository()
+        underTest = LightRevealScrimRepositoryImpl(fakeKeyguardRepository, context)
+    }
+
+    @Test
+    fun `nextRevealEffect - effect switches between default and biometric with no dupes`() =
+        runTest {
+            val values = mutableListOf<LightRevealEffect>()
+            val job = launch { underTest.revealEffect.collect { values.add(it) } }
+
+            // We should initially emit the default reveal effect.
+            runCurrent()
+            values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT })
+
+            // The source and sensor locations are still null, so we should still be using the
+            // default reveal despite a biometric unlock.
+            fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+
+            runCurrent()
+            values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+            // We got a source but still have no sensor locations, so should be sticking with
+            // the default effect.
+            fakeKeyguardRepository.setBiometricUnlockSource(
+                BiometricUnlockSource.FINGERPRINT_SENSOR
+            )
+
+            runCurrent()
+            values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+            // We got a location for the face sensor, but we unlocked with fingerprint.
+            val faceLocation = Point(250, 0)
+            fakeKeyguardRepository.setFaceSensorLocation(faceLocation)
+
+            runCurrent()
+            values.assertEffectsMatchPredicates({ it == DEFAULT_REVEAL_EFFECT },)
+
+            // Now we have fingerprint sensor locations, and wake and unlock via fingerprint.
+            val fingerprintLocation = Point(500, 500)
+            fakeKeyguardRepository.setFingerprintSensorLocation(fingerprintLocation)
+            fakeKeyguardRepository.setBiometricUnlockSource(
+                BiometricUnlockSource.FINGERPRINT_SENSOR
+            )
+            fakeKeyguardRepository.setBiometricUnlockState(
+                BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
+            )
+
+            // We should now have switched to the circle reveal, at the fingerprint location.
+            runCurrent()
+            values.assertEffectsMatchPredicates(
+                { it == DEFAULT_REVEAL_EFFECT },
+                {
+                    it is CircleReveal &&
+                        it.centerX == fingerprintLocation.x &&
+                        it.centerY == fingerprintLocation.y
+                },
+            )
+
+            // Subsequent wake and unlocks should not emit duplicate, identical CircleReveals.
+            val valuesPrevSize = values.size
+            fakeKeyguardRepository.setBiometricUnlockState(
+                BiometricUnlockModel.WAKE_AND_UNLOCK_PULSING
+            )
+            fakeKeyguardRepository.setBiometricUnlockState(
+                BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
+            )
+            assertEquals(valuesPrevSize, values.size)
+
+            // Non-biometric unlock, we should return to the default reveal.
+            fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.NONE)
+
+            runCurrent()
+            values.assertEffectsMatchPredicates(
+                { it == DEFAULT_REVEAL_EFFECT },
+                {
+                    it is CircleReveal &&
+                        it.centerX == fingerprintLocation.x &&
+                        it.centerY == fingerprintLocation.y
+                },
+                { it == DEFAULT_REVEAL_EFFECT },
+            )
+
+            // We already have a face location, so switching to face source should update the
+            // CircleReveal.
+            fakeKeyguardRepository.setBiometricUnlockSource(BiometricUnlockSource.FACE_SENSOR)
+            runCurrent()
+            fakeKeyguardRepository.setBiometricUnlockState(BiometricUnlockModel.WAKE_AND_UNLOCK)
+            runCurrent()
+
+            values.assertEffectsMatchPredicates(
+                { it == DEFAULT_REVEAL_EFFECT },
+                {
+                    it is CircleReveal &&
+                        it.centerX == fingerprintLocation.x &&
+                        it.centerY == fingerprintLocation.y
+                },
+                { it == DEFAULT_REVEAL_EFFECT },
+                {
+                    it is CircleReveal &&
+                        it.centerX == faceLocation.x &&
+                        it.centerY == faceLocation.y
+                },
+            )
+
+            job.cancel()
+        }
+
+    /**
+     * Asserts that the list of LightRevealEffects satisfies the list of predicates, in order, with
+     * no leftover elements.
+     */
+    private fun List<LightRevealEffect>.assertEffectsMatchPredicates(
+        vararg predicates: (LightRevealEffect) -> Boolean
+    ) {
+        println(this)
+        assertEquals(predicates.size, this.size)
+
+        assertFalse(
+            zip(predicates) { effect, predicate -> predicate(effect) }.any { matched -> !matched }
+        )
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
index c2650ec..1c1f039 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorParameterizedTest.kt
@@ -18,6 +18,7 @@
 package com.android.systemui.keyguard.domain.interactor
 
 import android.content.Intent
+import android.os.UserHandle
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
@@ -29,9 +30,11 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.domain.quickaffordance.FakeKeyguardQuickAffordanceRegistry
@@ -237,8 +240,8 @@
         val qrCodeScanner =
             FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
         val scope = CoroutineScope(IMMEDIATE)
-        val selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+        val localUserSelectionManager =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock<UserFileManager>().apply {
@@ -252,21 +255,32 @@
                             .thenReturn(FakeSharedPreferences())
                     },
                 userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+        val remoteUserSelectionManager =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = scope,
+                userTracker = userTracker,
+                clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker),
+                userHandle = UserHandle.SYSTEM,
             )
         val quickAffordanceRepository =
             KeyguardQuickAffordanceRepository(
                 appContext = context,
                 scope = scope,
-                selectionManager = selectionManager,
+                localUserSelectionManager = localUserSelectionManager,
+                remoteUserSelectionManager = remoteUserSelectionManager,
+                userTracker = userTracker,
                 legacySettingSyncer =
                     KeyguardQuickAffordanceLegacySettingSyncer(
                         scope = scope,
                         backgroundDispatcher = IMMEDIATE,
                         secureSettings = FakeSettings(),
-                        selectionsManager = selectionManager,
+                        selectionsManager = localUserSelectionManager,
                     ),
                 configs = setOf(homeControls, quickAccessWallet, qrCodeScanner),
                 dumpManager = mock(),
+                userHandle = UserHandle.SYSTEM,
             )
         underTest =
             KeyguardQuickAffordanceInteractor(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
index b790306..11fe905 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractorTest.kt
@@ -17,6 +17,7 @@
 
 package com.android.systemui.keyguard.domain.interactor
 
+import android.os.UserHandle
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
@@ -26,9 +27,11 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.domain.model.KeyguardQuickAffordanceModel
@@ -98,8 +101,8 @@
             FakeKeyguardQuickAffordanceConfig(BuiltInKeyguardQuickAffordanceKeys.QR_CODE_SCANNER)
         val scope = CoroutineScope(IMMEDIATE)
 
-        val selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+        val localUserSelectionManager =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock<UserFileManager>().apply {
@@ -113,21 +116,32 @@
                             .thenReturn(FakeSharedPreferences())
                     },
                 userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+        val remoteUserSelectionManager =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = scope,
+                userTracker = userTracker,
+                clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker),
+                userHandle = UserHandle.SYSTEM,
             )
         val quickAffordanceRepository =
             KeyguardQuickAffordanceRepository(
                 appContext = context,
                 scope = scope,
-                selectionManager = selectionManager,
+                localUserSelectionManager = localUserSelectionManager,
+                remoteUserSelectionManager = remoteUserSelectionManager,
+                userTracker = userTracker,
                 legacySettingSyncer =
                     KeyguardQuickAffordanceLegacySettingSyncer(
                         scope = scope,
                         backgroundDispatcher = IMMEDIATE,
                         secureSettings = FakeSettings(),
-                        selectionsManager = selectionManager,
+                        selectionsManager = localUserSelectionManager,
                     ),
                 configs = setOf(homeControls, quickAccessWallet, qrCodeScanner),
                 dumpManager = mock(),
+                userHandle = UserHandle.SYSTEM,
             )
         featureFlags =
             FakeFeatureFlags().apply {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
new file mode 100644
index 0000000..3166214
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/LightRevealScrimInteractorTest.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.domain.interactor
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyguard.data.repository.FakeKeyguardTransitionRepository
+import com.android.systemui.keyguard.data.repository.FakeLightRevealScrimRepository
+import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.TransitionState
+import com.android.systemui.keyguard.shared.model.TransitionStep
+import com.android.systemui.statusbar.LightRevealEffect
+import com.android.systemui.statusbar.LightRevealScrim
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Assert.assertEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(JUnit4::class)
+class LightRevealScrimInteractorTest : SysuiTestCase() {
+    private val fakeKeyguardTransitionRepository = FakeKeyguardTransitionRepository()
+    private val fakeLightRevealScrimRepository = FakeLightRevealScrimRepository()
+
+    private val keyguardTransitionInteractor =
+        KeyguardTransitionInteractor(fakeKeyguardTransitionRepository)
+
+    private lateinit var underTest: LightRevealScrimInteractor
+
+    private val reveal1 =
+        object : LightRevealEffect {
+            override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {}
+        }
+
+    private val reveal2 =
+        object : LightRevealEffect {
+            override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {}
+        }
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        underTest =
+            LightRevealScrimInteractor(
+                fakeKeyguardTransitionRepository,
+                keyguardTransitionInteractor,
+                fakeLightRevealScrimRepository
+            )
+    }
+
+    @Test
+    fun `lightRevealEffect - does not change during keyguard transition`() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<LightRevealEffect>()
+            val job = underTest.lightRevealEffect.onEach(values::add).launchIn(this)
+
+            fakeLightRevealScrimRepository.setRevealEffect(reveal1)
+
+            // The reveal effect shouldn't emit anything until a keyguard transition starts.
+            assertEquals(values.size, 0)
+
+            // Once it starts, it should emit reveal1.
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(transitionState = TransitionState.STARTED)
+            )
+            assertEquals(values, listOf(reveal1))
+
+            // Until the next transition starts, reveal2 should not be emitted.
+            fakeLightRevealScrimRepository.setRevealEffect(reveal2)
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(transitionState = TransitionState.RUNNING)
+            )
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(transitionState = TransitionState.FINISHED)
+            )
+            assertEquals(values, listOf(reveal1))
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(transitionState = TransitionState.STARTED)
+            )
+            assertEquals(values, listOf(reveal1, reveal2))
+
+            job.cancel()
+        }
+
+    @Test
+    fun `revealAmount - inverted when appropriate`() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Float>()
+            val job = underTest.revealAmount.onEach(values::add).launchIn(this)
+
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.AOD,
+                    to = KeyguardState.LOCKSCREEN,
+                    value = 0.3f
+                )
+            )
+
+            assertEquals(values, listOf(0.3f))
+
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(
+                    from = KeyguardState.LOCKSCREEN,
+                    to = KeyguardState.AOD,
+                    value = 0.3f
+                )
+            )
+
+            assertEquals(values, listOf(0.3f, 0.7f))
+
+            job.cancel()
+        }
+
+    @Test
+    fun `revealAmount - ignores transitions that do not affect reveal amount`() =
+        runTest(UnconfinedTestDispatcher()) {
+            val values = mutableListOf<Float>()
+            val job = underTest.revealAmount.onEach(values::add).launchIn(this)
+
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(from = KeyguardState.DOZING, to = KeyguardState.AOD, value = 0.3f)
+            )
+
+            assertEquals(values, emptyList<Float>())
+
+            fakeKeyguardTransitionRepository.sendTransitionStep(
+                TransitionStep(from = KeyguardState.AOD, to = KeyguardState.DOZING, value = 0.3f)
+            )
+
+            assertEquals(values, emptyList<Float>())
+
+            job.cancel()
+        }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 8b166bd..83a5d0e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.keyguard.ui.viewmodel
 
 import android.content.Intent
+import android.os.UserHandle
 import androidx.test.filters.SmallTest
 import com.android.internal.widget.LockPatternUtils
 import com.android.systemui.SysuiTestCase
@@ -27,9 +28,11 @@
 import com.android.systemui.flags.Flags
 import com.android.systemui.keyguard.data.quickaffordance.BuiltInKeyguardQuickAffordanceKeys
 import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceConfig
+import com.android.systemui.keyguard.data.quickaffordance.FakeKeyguardQuickAffordanceProviderClientFactory
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceConfig
 import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLegacySettingSyncer
-import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceLocalUserSelectionManager
+import com.android.systemui.keyguard.data.quickaffordance.KeyguardQuickAffordanceRemoteUserSelectionManager
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
 import com.android.systemui.keyguard.data.repository.KeyguardQuickAffordanceRepository
 import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
@@ -121,8 +124,8 @@
         whenever(lockPatternUtils.getStrongAuthForUser(anyInt()))
             .thenReturn(LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED)
         val scope = CoroutineScope(IMMEDIATE)
-        val selectionManager =
-            KeyguardQuickAffordanceSelectionManager(
+        val localUserSelectionManager =
+            KeyguardQuickAffordanceLocalUserSelectionManager(
                 context = context,
                 userFileManager =
                     mock<UserFileManager>().apply {
@@ -136,18 +139,28 @@
                             .thenReturn(FakeSharedPreferences())
                     },
                 userTracker = userTracker,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+            )
+        val remoteUserSelectionManager =
+            KeyguardQuickAffordanceRemoteUserSelectionManager(
+                scope = scope,
+                userTracker = userTracker,
+                clientFactory = FakeKeyguardQuickAffordanceProviderClientFactory(userTracker),
+                userHandle = UserHandle.SYSTEM,
             )
         val quickAffordanceRepository =
             KeyguardQuickAffordanceRepository(
                 appContext = context,
                 scope = scope,
-                selectionManager = selectionManager,
+                localUserSelectionManager = localUserSelectionManager,
+                remoteUserSelectionManager = remoteUserSelectionManager,
+                userTracker = userTracker,
                 legacySettingSyncer =
                     KeyguardQuickAffordanceLegacySettingSyncer(
                         scope = scope,
                         backgroundDispatcher = IMMEDIATE,
                         secureSettings = FakeSettings(),
-                        selectionsManager = selectionManager,
+                        selectionsManager = localUserSelectionManager,
                     ),
                 configs =
                     setOf(
@@ -156,6 +169,7 @@
                         qrCodeScannerAffordanceConfig,
                     ),
                 dumpManager = mock(),
+                userHandle = UserHandle.SYSTEM,
             )
         underTest =
             KeyguardBottomAreaViewModel(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
new file mode 100644
index 0000000..432764a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableChangeTest.kt
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+
+@SmallTest
+class TableChangeTest : SysuiTestCase() {
+
+    @Test
+    fun setString_isString() {
+        val underTest = TableChange()
+
+        underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
+        underTest.set("fakeValue")
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getVal()).isEqualTo("fakeValue")
+    }
+
+    @Test
+    fun setBoolean_isBoolean() {
+        val underTest = TableChange()
+
+        underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
+        underTest.set(true)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getVal()).isEqualTo("true")
+    }
+
+    @Test
+    fun setInt_isInt() {
+        val underTest = TableChange()
+
+        underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
+        underTest.set(8900)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getVal()).isEqualTo("8900")
+    }
+
+    @Test
+    fun setThenReset_isEmpty() {
+        val underTest = TableChange()
+
+        underTest.reset(timestamp = 100, columnPrefix = "", columnName = "fakeName")
+        underTest.set(8900)
+        underTest.reset(timestamp = 0, columnPrefix = "prefix", columnName = "name")
+
+        assertThat(underTest.hasData()).isFalse()
+        assertThat(underTest.getVal()).isEqualTo("null")
+    }
+
+    @Test
+    fun getName_hasPrefix() {
+        val underTest = TableChange(columnPrefix = "fakePrefix", columnName = "fakeName")
+
+        assertThat(underTest.getName()).contains("fakePrefix")
+        assertThat(underTest.getName()).contains("fakeName")
+    }
+
+    @Test
+    fun getName_noPrefix() {
+        val underTest = TableChange(columnPrefix = "", columnName = "fakeName")
+
+        assertThat(underTest.getName()).contains("fakeName")
+    }
+
+    @Test
+    fun resetThenSet_hasNewValue() {
+        val underTest = TableChange()
+
+        underTest.reset(timestamp = 100, columnPrefix = "prefix", columnName = "original")
+        underTest.set("fakeValue")
+        underTest.reset(timestamp = 0, columnPrefix = "", columnName = "updated")
+        underTest.set(8900)
+
+        assertThat(underTest.hasData()).isTrue()
+        assertThat(underTest.getName()).contains("updated")
+        assertThat(underTest.getName()).doesNotContain("prefix")
+        assertThat(underTest.getName()).doesNotContain("original")
+        assertThat(underTest.getVal()).isEqualTo("8900")
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
new file mode 100644
index 0000000..2c8d7ab
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/log/table/TableLogBufferTest.kt
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.log.table
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.util.time.FakeSystemClock
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Before
+import org.junit.Test
+
+@SmallTest
+class TableLogBufferTest : SysuiTestCase() {
+    private lateinit var underTest: TableLogBuffer
+
+    private lateinit var systemClock: FakeSystemClock
+    private lateinit var outputWriter: StringWriter
+
+    @Before
+    fun setup() {
+        systemClock = FakeSystemClock()
+        outputWriter = StringWriter()
+
+        underTest = TableLogBuffer(MAX_SIZE, NAME, systemClock)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun maxSizeZero_throwsException() {
+        TableLogBuffer(maxSize = 0, "name", systemClock)
+    }
+
+    @Test
+    fun dumpChanges_hasHeader() {
+        val dumpedString = dumpChanges()
+
+        assertThat(logLines(dumpedString)[0]).isEqualTo(HEADER_PREFIX + NAME)
+    }
+
+    @Test
+    fun dumpChanges_hasVersion() {
+        val dumpedString = dumpChanges()
+
+        assertThat(logLines(dumpedString)[1]).isEqualTo("version $VERSION")
+    }
+
+    @Test
+    fun dumpChanges_hasFooter() {
+        val dumpedString = dumpChanges()
+
+        assertThat(logLines(dumpedString).last()).isEqualTo(FOOTER_PREFIX + NAME)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_str_separatorNotAllowedInPrefix() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("columnName", "stringValue")
+                }
+            }
+        underTest.logDiffs("some${SEPARATOR}thing", TestDiffable(), next)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_bool_separatorNotAllowedInPrefix() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("columnName", true)
+                }
+            }
+        underTest.logDiffs("some${SEPARATOR}thing", TestDiffable(), next)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_int_separatorNotAllowedInPrefix() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("columnName", 567)
+                }
+            }
+        underTest.logDiffs("some${SEPARATOR}thing", TestDiffable(), next)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_str_separatorNotAllowedInColumnName() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("column${SEPARATOR}Name", "stringValue")
+                }
+            }
+        underTest.logDiffs("prefix", TestDiffable(), next)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_bool_separatorNotAllowedInColumnName() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("column${SEPARATOR}Name", true)
+                }
+            }
+        underTest.logDiffs("prefix", TestDiffable(), next)
+    }
+
+    @Test(expected = IllegalArgumentException::class)
+    fun dumpChanges_int_separatorNotAllowedInColumnName() {
+        val next =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("column${SEPARATOR}Name", 456)
+                }
+            }
+        underTest.logDiffs("prefix", TestDiffable(), next)
+    }
+
+    @Test
+    fun logChange_bool_dumpsCorrectly() {
+        systemClock.setCurrentTimeMillis(4000L)
+
+        underTest.logChange("prefix", "columnName", true)
+
+        val dumpedString = dumpChanges()
+        val expected =
+            TABLE_LOG_DATE_FORMAT.format(4000L) +
+                SEPARATOR +
+                "prefix.columnName" +
+                SEPARATOR +
+                "true"
+        assertThat(dumpedString).contains(expected)
+    }
+
+    @Test
+    fun dumpChanges_strChange_logsFromNext() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        val prevDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("stringValChange", "prevStringVal")
+                }
+            }
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("stringValChange", "newStringVal")
+                }
+            }
+
+        underTest.logDiffs("prefix", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        val expected =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "prefix.stringValChange" +
+                SEPARATOR +
+                "newStringVal"
+        assertThat(dumpedString).contains(expected)
+        assertThat(dumpedString).doesNotContain("prevStringVal")
+    }
+
+    @Test
+    fun dumpChanges_boolChange_logsFromNext() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        val prevDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("booleanValChange", false)
+                }
+            }
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("booleanValChange", true)
+                }
+            }
+
+        underTest.logDiffs("prefix", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        val expected =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "prefix.booleanValChange" +
+                SEPARATOR +
+                "true"
+        assertThat(dumpedString).contains(expected)
+        assertThat(dumpedString).doesNotContain("false")
+    }
+
+    @Test
+    fun dumpChanges_intChange_logsFromNext() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        val prevDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("intValChange", 12345)
+                }
+            }
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("intValChange", 67890)
+                }
+            }
+
+        underTest.logDiffs("prefix", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        val expected =
+            TABLE_LOG_DATE_FORMAT.format(100L) +
+                SEPARATOR +
+                "prefix.intValChange" +
+                SEPARATOR +
+                "67890"
+        assertThat(dumpedString).contains(expected)
+        assertThat(dumpedString).doesNotContain("12345")
+    }
+
+    @Test
+    fun dumpChanges_noPrefix() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        val prevDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("booleanValChange", false)
+                }
+            }
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("booleanValChange", true)
+                }
+            }
+
+        // WHEN there's a blank prefix
+        underTest.logDiffs("", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        // THEN the dump still works
+        val expected =
+            TABLE_LOG_DATE_FORMAT.format(100L) + SEPARATOR + "booleanValChange" + SEPARATOR + "true"
+        assertThat(dumpedString).contains(expected)
+    }
+
+    @Test
+    fun dumpChanges_multipleChangesForSameColumn_logs() {
+        lateinit var valToDump: String
+
+        val diffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("valChange", valToDump)
+                }
+            }
+
+        systemClock.setCurrentTimeMillis(12000L)
+        valToDump = "stateValue12"
+        underTest.logDiffs(columnPrefix = "", diffable, diffable)
+
+        systemClock.setCurrentTimeMillis(20000L)
+        valToDump = "stateValue20"
+        underTest.logDiffs(columnPrefix = "", diffable, diffable)
+
+        systemClock.setCurrentTimeMillis(40000L)
+        valToDump = "stateValue40"
+        underTest.logDiffs(columnPrefix = "", diffable, diffable)
+
+        systemClock.setCurrentTimeMillis(45000L)
+        valToDump = "stateValue45"
+        underTest.logDiffs(columnPrefix = "", diffable, diffable)
+
+        val dumpedString = dumpChanges()
+
+        val expected1 =
+            TABLE_LOG_DATE_FORMAT.format(12000L) +
+                SEPARATOR +
+                "valChange" +
+                SEPARATOR +
+                "stateValue12"
+        val expected2 =
+            TABLE_LOG_DATE_FORMAT.format(20000L) +
+                SEPARATOR +
+                "valChange" +
+                SEPARATOR +
+                "stateValue20"
+        val expected3 =
+            TABLE_LOG_DATE_FORMAT.format(40000L) +
+                SEPARATOR +
+                "valChange" +
+                SEPARATOR +
+                "stateValue40"
+        val expected4 =
+            TABLE_LOG_DATE_FORMAT.format(45000L) +
+                SEPARATOR +
+                "valChange" +
+                SEPARATOR +
+                "stateValue45"
+        assertThat(dumpedString).contains(expected1)
+        assertThat(dumpedString).contains(expected2)
+        assertThat(dumpedString).contains(expected3)
+        assertThat(dumpedString).contains(expected4)
+    }
+
+    @Test
+    fun dumpChanges_multipleChangesAtOnce_logs() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        val prevDiffable = object : TestDiffable() {}
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("status", "in progress")
+                    row.logChange("connected", false)
+                }
+            }
+
+        underTest.logDiffs(columnPrefix = "", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        val timestamp = TABLE_LOG_DATE_FORMAT.format(100L)
+        val expected1 = timestamp + SEPARATOR + "status" + SEPARATOR + "in progress"
+        val expected2 = timestamp + SEPARATOR + "connected" + SEPARATOR + "false"
+        assertThat(dumpedString).contains(expected1)
+        assertThat(dumpedString).contains(expected2)
+    }
+
+    @Test
+    fun logChange_rowInitializer_dumpsCorrectly() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        underTest.logChange("") { row ->
+            row.logChange("column1", "val1")
+            row.logChange("column2", 2)
+            row.logChange("column3", true)
+        }
+
+        val dumpedString = dumpChanges()
+
+        val timestamp = TABLE_LOG_DATE_FORMAT.format(100L)
+        val expected1 = timestamp + SEPARATOR + "column1" + SEPARATOR + "val1"
+        val expected2 = timestamp + SEPARATOR + "column2" + SEPARATOR + "2"
+        val expected3 = timestamp + SEPARATOR + "column3" + SEPARATOR + "true"
+        assertThat(dumpedString).contains(expected1)
+        assertThat(dumpedString).contains(expected2)
+        assertThat(dumpedString).contains(expected3)
+    }
+
+    @Test
+    fun logChangeAndLogDiffs_bothLogged() {
+        systemClock.setCurrentTimeMillis(100L)
+
+        underTest.logChange("") { row ->
+            row.logChange("column1", "val1")
+            row.logChange("column2", 2)
+            row.logChange("column3", true)
+        }
+
+        systemClock.setCurrentTimeMillis(200L)
+        val prevDiffable = object : TestDiffable() {}
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("column1", "newVal1")
+                    row.logChange("column2", 222)
+                    row.logChange("column3", false)
+                }
+            }
+
+        underTest.logDiffs(columnPrefix = "", prevDiffable, nextDiffable)
+
+        val dumpedString = dumpChanges()
+
+        val timestamp1 = TABLE_LOG_DATE_FORMAT.format(100L)
+        val expected1 = timestamp1 + SEPARATOR + "column1" + SEPARATOR + "val1"
+        val expected2 = timestamp1 + SEPARATOR + "column2" + SEPARATOR + "2"
+        val expected3 = timestamp1 + SEPARATOR + "column3" + SEPARATOR + "true"
+        val timestamp2 = TABLE_LOG_DATE_FORMAT.format(200L)
+        val expected4 = timestamp2 + SEPARATOR + "column1" + SEPARATOR + "newVal1"
+        val expected5 = timestamp2 + SEPARATOR + "column2" + SEPARATOR + "222"
+        val expected6 = timestamp2 + SEPARATOR + "column3" + SEPARATOR + "false"
+        assertThat(dumpedString).contains(expected1)
+        assertThat(dumpedString).contains(expected2)
+        assertThat(dumpedString).contains(expected3)
+        assertThat(dumpedString).contains(expected4)
+        assertThat(dumpedString).contains(expected5)
+        assertThat(dumpedString).contains(expected6)
+    }
+
+    @Test
+    fun dumpChanges_rotatesIfBufferIsFull() {
+        lateinit var valToDump: String
+
+        val prevDiffable = object : TestDiffable() {}
+        val nextDiffable =
+            object : TestDiffable() {
+                override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {
+                    row.logChange("status", valToDump)
+                }
+            }
+
+        for (i in 0 until MAX_SIZE + 3) {
+            valToDump = "testString[$i]"
+            underTest.logDiffs(columnPrefix = "", prevDiffable, nextDiffable)
+        }
+
+        val dumpedString = dumpChanges()
+
+        assertThat(dumpedString).doesNotContain("testString[0]")
+        assertThat(dumpedString).doesNotContain("testString[1]")
+        assertThat(dumpedString).doesNotContain("testString[2]")
+        assertThat(dumpedString).contains("testString[3]")
+        assertThat(dumpedString).contains("testString[${MAX_SIZE + 2}]")
+    }
+
+    private fun dumpChanges(): String {
+        underTest.dump(PrintWriter(outputWriter), arrayOf())
+        return outputWriter.toString()
+    }
+
+    private fun logLines(string: String): List<String> {
+        return string.split("\n").filter { it.isNotBlank() }
+    }
+
+    private open class TestDiffable : Diffable<TestDiffable> {
+        override fun logDiffs(prevVal: TestDiffable, row: TableRowLogger) {}
+    }
+}
+
+private const val NAME = "TestTableBuffer"
+private const val MAX_SIZE = 10
+
+// Copying these here from [TableLogBuffer] so that we catch any accidental versioning change
+private const val HEADER_PREFIX = "SystemUI StateChangeTableSection START: "
+private const val FOOTER_PREFIX = "SystemUI StateChangeTableSection END: "
+private const val SEPARATOR = "|" // TBD
+private const val VERSION = "1"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
index 84fdfd7..136ace1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/resume/MediaResumeListenerTest.kt
@@ -38,6 +38,7 @@
 import com.android.systemui.media.controls.models.player.MediaDeviceData
 import com.android.systemui.media.controls.pipeline.MediaDataManager
 import com.android.systemui.media.controls.pipeline.RESUME_MEDIA_TIMEOUT
+import com.android.systemui.settings.UserTracker
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.time.FakeSystemClock
@@ -79,6 +80,7 @@
 class MediaResumeListenerTest : SysuiTestCase() {
 
     @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock private lateinit var userTracker: UserTracker
     @Mock private lateinit var mediaDataManager: MediaDataManager
     @Mock private lateinit var device: MediaDeviceData
     @Mock private lateinit var token: MediaSession.Token
@@ -131,12 +133,15 @@
         whenever(sharedPrefsEditor.putString(any(), any())).thenReturn(sharedPrefsEditor)
         whenever(mockContext.packageManager).thenReturn(context.packageManager)
         whenever(mockContext.contentResolver).thenReturn(context.contentResolver)
+        whenever(mockContext.userId).thenReturn(context.userId)
 
         executor = FakeExecutor(clock)
         resumeListener =
             MediaResumeListener(
                 mockContext,
                 broadcastDispatcher,
+                userTracker,
+                executor,
                 executor,
                 tunerService,
                 resumeBrowserFactory,
@@ -177,6 +182,8 @@
             MediaResumeListener(
                 context,
                 broadcastDispatcher,
+                userTracker,
+                executor,
                 executor,
                 tunerService,
                 resumeBrowserFactory,
@@ -185,7 +192,7 @@
             )
         listener.setManager(mediaDataManager)
         verify(broadcastDispatcher, never())
-            .registerReceiver(eq(listener.userChangeReceiver), any(), any(), any(), anyInt(), any())
+            .registerReceiver(eq(listener.userUnlockReceiver), any(), any(), any(), anyInt(), any())
 
         // When data is loaded, we do NOT execute or update anything
         listener.onMediaDataLoaded(KEY, OLD_KEY, data)
@@ -289,7 +296,7 @@
         resumeListener.setManager(mediaDataManager)
         verify(broadcastDispatcher)
             .registerReceiver(
-                eq(resumeListener.userChangeReceiver),
+                eq(resumeListener.userUnlockReceiver),
                 any(),
                 any(),
                 any(),
@@ -299,7 +306,8 @@
 
         // When we get an unlock event
         val intent = Intent(Intent.ACTION_USER_UNLOCKED)
-        resumeListener.userChangeReceiver.onReceive(context, intent)
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+        resumeListener.userUnlockReceiver.onReceive(context, intent)
 
         // Then we should attempt to find recent media for each saved component
         verify(resumeBrowser, times(3)).findRecentMedia()
@@ -375,6 +383,8 @@
             MediaResumeListener(
                 mockContext,
                 broadcastDispatcher,
+                userTracker,
+                executor,
                 executor,
                 tunerService,
                 resumeBrowserFactory,
@@ -386,7 +396,8 @@
 
         // When we load a component that was played recently
         val intent = Intent(Intent.ACTION_USER_UNLOCKED)
-        resumeListener.userChangeReceiver.onReceive(mockContext, intent)
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+        resumeListener.userUnlockReceiver.onReceive(mockContext, intent)
 
         // We add its resume controls
         verify(resumeBrowser, times(1)).findRecentMedia()
@@ -404,6 +415,8 @@
             MediaResumeListener(
                 mockContext,
                 broadcastDispatcher,
+                userTracker,
+                executor,
                 executor,
                 tunerService,
                 resumeBrowserFactory,
@@ -415,7 +428,8 @@
 
         // When we load a component that is not recent
         val intent = Intent(Intent.ACTION_USER_UNLOCKED)
-        resumeListener.userChangeReceiver.onReceive(mockContext, intent)
+        intent.putExtra(Intent.EXTRA_USER_HANDLE, context.userId)
+        resumeListener.userUnlockReceiver.onReceive(mockContext, intent)
 
         // We do not try to add resume controls
         verify(resumeBrowser, times(0)).findRecentMedia()
@@ -443,6 +457,8 @@
             MediaResumeListener(
                 mockContext,
                 broadcastDispatcher,
+                userTracker,
+                executor,
                 executor,
                 tunerService,
                 resumeBrowserFactory,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
index 6c03730..1865ef6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavBarHelperTest.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.navigationbar;
 
+import static android.app.StatusBarManager.WINDOW_NAVIGATION_BAR;
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_FLOATING_MENU;
 import static android.provider.Settings.Secure.ACCESSIBILITY_BUTTON_MODE_NAVIGATION_BAR;
 
@@ -47,6 +48,7 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 import com.android.systemui.statusbar.policy.KeyguardStateController;
 
@@ -69,6 +71,10 @@
 @SmallTest
 public class NavBarHelperTest extends SysuiTestCase {
 
+    private static final int DISPLAY_ID = 0;
+    private static final int WINDOW = WINDOW_NAVIGATION_BAR;
+    private static final int STATE_ID = 0;
+
     @Mock
     AccessibilityManager mAccessibilityManager;
     @Mock
@@ -93,6 +99,8 @@
     DumpManager mDumpManager;
     @Mock
     NavBarHelper.NavbarTaskbarStateUpdater mNavbarTaskbarStateUpdater;
+    @Mock
+    CommandQueue mCommandQueue;
     private AccessibilityManager.AccessibilityServicesStateChangeListener
             mAccessibilityServicesStateChangeListener;
 
@@ -114,7 +122,7 @@
                 mAccessibilityButtonModeObserver, mAccessibilityButtonTargetObserver,
                 mSystemActions, mOverviewProxyService, mAssistManagerLazy,
                 () -> Optional.of(mock(CentralSurfaces.class)), mock(KeyguardStateController.class),
-                mNavigationModeController, mUserTracker, mDumpManager);
+                mNavigationModeController, mUserTracker, mDumpManager, mCommandQueue);
 
     }
 
@@ -241,6 +249,45 @@
                 ACCESSIBILITY_BUTTON_CLICKABLE_STATE);
     }
 
+    @Test
+    public void registerCommandQueueCallbacks() {
+        mNavBarHelper.init();
+        verify(mCommandQueue, times(1)).addCallback(any());
+    }
+
+    @Test
+    public void saveMostRecentSysuiState() {
+        mNavBarHelper.init();
+        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
+        NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();
+
+        // Update window state
+        int newState = STATE_ID + 1;
+        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, newState);
+        NavBarHelper.CurrentSysuiState state2 = mNavBarHelper.getCurrentSysuiState();
+
+        // Ensure we get most recent state back
+        assertThat(state1.mWindowState).isNotEqualTo(state2.mWindowState);
+        assertThat(state1.mWindowStateDisplayId).isEqualTo(state2.mWindowStateDisplayId);
+        assertThat(state2.mWindowState).isEqualTo(newState);
+    }
+
+    @Test
+    public void ignoreNonNavbarSysuiState() {
+        mNavBarHelper.init();
+        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW, STATE_ID);
+        NavBarHelper.CurrentSysuiState state1 = mNavBarHelper.getCurrentSysuiState();
+
+        // Update window state for other window type
+        int newState = STATE_ID + 1;
+        mNavBarHelper.setWindowState(DISPLAY_ID, WINDOW + 1, newState);
+        NavBarHelper.CurrentSysuiState state2 = mNavBarHelper.getCurrentSysuiState();
+
+        // Ensure we get first state back
+        assertThat(state2.mWindowState).isEqualTo(state1.mWindowState);
+        assertThat(state2.mWindowState).isNotEqualTo(newState);
+    }
+
     private List<String> createFakeShortcutTargets() {
         return new ArrayList<>(List.of("a", "b", "c", "d"));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index c1fa9b3..80adbf0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -44,14 +44,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Handler;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.provider.DeviceConfig;
 import android.telecom.TelecomManager;
 import android.testing.AndroidTestingRunner;
@@ -79,7 +76,6 @@
 import com.android.systemui.accessibility.AccessibilityButtonTargetsObserver;
 import com.android.systemui.accessibility.SystemActions;
 import com.android.systemui.assist.AssistManager;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.model.SysUiState;
@@ -119,6 +115,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.Optional;
+import java.util.concurrent.Executor;
 
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper(setAsMainLooper = true)
@@ -166,7 +163,7 @@
     @Mock
     private Handler mHandler;
     @Mock
-    private BroadcastDispatcher mBroadcastDispatcher;
+    private UserTracker mUserTracker;
     @Mock
     private UiEventLogger mUiEventLogger;
     @Mock
@@ -247,7 +244,7 @@
                     mSystemActions, mOverviewProxyService,
                     () -> mock(AssistManager.class), () -> Optional.of(mCentralSurfaces),
                     mKeyguardStateController, mock(NavigationModeController.class),
-                    mock(UserTracker.class), mock(DumpManager.class)));
+                    mock(UserTracker.class), mock(DumpManager.class), mock(CommandQueue.class)));
             mNavigationBar = createNavBar(mContext);
             mExternalDisplayNavigationBar = createNavBar(mSysuiTestableContextExternal);
         });
@@ -315,14 +312,10 @@
     }
 
     @Test
-    public void testRegisteredWithDispatcher() {
+    public void testRegisteredWithUserTracker() {
         mNavigationBar.init();
         mNavigationBar.onViewAttached();
-        verify(mBroadcastDispatcher).registerReceiverWithHandler(
-                any(BroadcastReceiver.class),
-                any(IntentFilter.class),
-                any(Handler.class),
-                any(UserHandle.class));
+        verify(mUserTracker).addCallback(any(UserTracker.Callback.class), any(Executor.class));
     }
 
     @Test
@@ -438,6 +431,12 @@
         verify(mNavigationBarView).setVisibility(View.INVISIBLE);
     }
 
+    @Test
+    public void testOnInit_readCurrentSysuiState() {
+        mNavigationBar.init();
+        verify(mNavBarHelper, times(1)).getCurrentSysuiState();
+    }
+
     private NavigationBar createNavBar(Context context) {
         DeviceProvisionedController deviceProvisionedController =
                 mock(DeviceProvisionedController.class);
@@ -457,7 +456,7 @@
                 mStatusBarStateController,
                 mStatusBarKeyguardViewManager,
                 mMockSysUiState,
-                mBroadcastDispatcher,
+                mUserTracker,
                 mCommandQueue,
                 Optional.of(mock(Pip.class)),
                 Optional.of(mock(Recents.class)),
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 c377c37..338182a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -48,6 +48,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.power.PowerUI.WarningsUI;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.CentralSurfaces;
 
@@ -85,6 +86,7 @@
     private PowerUI mPowerUI;
     @Mock private EnhancedEstimates mEnhancedEstimates;
     @Mock private PowerManager mPowerManager;
+    @Mock private UserTracker mUserTracker;
     @Mock private WakefulnessLifecycle mWakefulnessLifecycle;
     @Mock private IThermalService mThermalServiceMock;
     private IThermalEventListener mUsbThermalEventListener;
@@ -682,7 +684,8 @@
     private void createPowerUi() {
         mPowerUI = new PowerUI(
                 mContext, mBroadcastDispatcher, mCommandQueue, mCentralSurfacesOptionalLazy,
-                mMockWarnings, mEnhancedEstimates, mWakefulnessLifecycle, mPowerManager);
+                mMockWarnings, mEnhancedEstimates, mWakefulnessLifecycle, mPowerManager,
+                mUserTracker);
         mPowerUI.mThermalService = mThermalServiceMock;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
index 7bae115..17eb6e2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/FgsManagerControllerTest.java
@@ -18,6 +18,7 @@
 
 import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
 
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
@@ -29,6 +30,9 @@
 
 import android.app.IActivityManager;
 import android.app.IForegroundServiceObserver;
+import android.app.job.IUserVisibleJobObserver;
+import android.app.job.JobScheduler;
+import android.app.job.UserVisibleJobSummary;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -59,6 +63,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.ArgumentMatchers;
+import org.mockito.InOrder;
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
@@ -79,6 +84,8 @@
     @Mock
     IActivityManager mIActivityManager;
     @Mock
+    JobScheduler mJobScheduler;
+    @Mock
     PackageManager mPackageManager;
     @Mock
     UserTracker mUserTracker;
@@ -92,8 +99,10 @@
     private FgsManagerController mFmc;
 
     private IForegroundServiceObserver mIForegroundServiceObserver;
+    private IUserVisibleJobObserver mIUserVisibleJobObserver;
     private UserTracker.Callback mUserTrackerCallback;
     private BroadcastReceiver mShowFgsManagerReceiver;
+    private InOrder mJobSchedulerInOrder;
 
     private List<UserInfo> mUserProfiles;
 
@@ -111,6 +120,8 @@
         mUserProfiles = new ArrayList<>();
         Mockito.doReturn(mUserProfiles).when(mUserTracker).getUserProfiles();
 
+        mJobSchedulerInOrder = Mockito.inOrder(mJobScheduler);
+
         mFmc = createFgsManagerController();
     }
 
@@ -132,6 +143,52 @@
     }
 
     @Test
+    public void testNumPackages_jobs() throws RemoteException {
+        setUserProfiles(0);
+        setShowUserVisibleJobs(true);
+
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", 0);
+        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, 0, "pkg2", 1);
+        Assert.assertEquals(0, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, true);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, true);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, false);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, false);
+        Assert.assertEquals(0, mFmc.getNumRunningPackages());
+    }
+
+    @Test
+    public void testNumPackages_FgsAndJobs() throws RemoteException {
+        setUserProfiles(0);
+        setShowUserVisibleJobs(true);
+
+        Binder b1 = new Binder();
+        Binder b2 = new Binder();
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", 0);
+        UserVisibleJobSummary j3 = new UserVisibleJobSummary(1, 0, "pkg3", 1);
+        Assert.assertEquals(0, mFmc.getNumRunningPackages());
+        mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, true);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, true);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j3, true);
+        Assert.assertEquals(3, mFmc.getNumRunningPackages());
+        mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, false);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j3, false);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIForegroundServiceObserver.onForegroundStateChanged(b1, "pkg1", 0, false);
+        Assert.assertEquals(1, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, false);
+        Assert.assertEquals(0, mFmc.getNumRunningPackages());
+    }
+
+    @Test
     public void testNumPackagesDoesNotChangeWhenSecondFgsIsStarted() throws RemoteException {
         setUserProfiles(0);
 
@@ -243,6 +300,91 @@
         Assert.assertEquals(0, mFmc.visibleButtonsCount());
     }
 
+    @Test
+    public void testShowUserVisibleJobsOnCreation() {
+        // Test when the default is on.
+        mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS,
+                "true", false);
+        FgsManagerController fmc = new FgsManagerControllerImpl(
+                mContext,
+                mMainExecutor,
+                mBackgroundExecutor,
+                mSystemClock,
+                mIActivityManager,
+                mJobScheduler,
+                mPackageManager,
+                mUserTracker,
+                mDeviceConfigProxyFake,
+                mDialogLaunchAnimator,
+                mBroadcastDispatcher,
+                mDumpManager
+        );
+        fmc.init();
+        Assert.assertTrue(fmc.getIncludesUserVisibleJobs());
+        ArgumentCaptor<IUserVisibleJobObserver> iUserVisibleJobObserverArgumentCaptor =
+                ArgumentCaptor.forClass(IUserVisibleJobObserver.class);
+        mJobSchedulerInOrder.verify(mJobScheduler)
+                .registerUserVisibleJobObserver(iUserVisibleJobObserverArgumentCaptor.capture());
+        Assert.assertNotNull(iUserVisibleJobObserverArgumentCaptor.getValue());
+
+        // Test when the default is off.
+        mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS,
+                "false", false);
+        fmc = new FgsManagerControllerImpl(
+                mContext,
+                mMainExecutor,
+                mBackgroundExecutor,
+                mSystemClock,
+                mIActivityManager,
+                mJobScheduler,
+                mPackageManager,
+                mUserTracker,
+                mDeviceConfigProxyFake,
+                mDialogLaunchAnimator,
+                mBroadcastDispatcher,
+                mDumpManager
+        );
+        fmc.init();
+        Assert.assertFalse(fmc.getIncludesUserVisibleJobs());
+        mJobSchedulerInOrder.verify(mJobScheduler, never()).registerUserVisibleJobObserver(any());
+    }
+
+    @Test
+    public void testShowUserVisibleJobsToggling() throws Exception {
+        setUserProfiles(0);
+        setShowUserVisibleJobs(true);
+
+        // pkg1 has only job
+        // pkg2 has both job and fgs
+        // pkg3 has only fgs
+        UserVisibleJobSummary j1 = new UserVisibleJobSummary(0, 0, "pkg1", 0);
+        UserVisibleJobSummary j2 = new UserVisibleJobSummary(1, 0, "pkg2", 1);
+        Binder b2 = new Binder();
+        Binder b3 = new Binder();
+
+        Assert.assertEquals(0, mFmc.getNumRunningPackages());
+        mIForegroundServiceObserver.onForegroundStateChanged(b2, "pkg2", 0, true);
+        mIForegroundServiceObserver.onForegroundStateChanged(b3, "pkg3", 0, true);
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, true);
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, true);
+        Assert.assertEquals(3, mFmc.getNumRunningPackages());
+
+        // Turn off the flag, confirm the number of packages is updated properly.
+        setShowUserVisibleJobs(false);
+        // Only pkg1 should be removed since the other two have fgs
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+
+        setShowUserVisibleJobs(true);
+
+        Assert.assertEquals(2, mFmc.getNumRunningPackages());
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j1, true);
+        mIUserVisibleJobObserver.onUserVisibleJobStateChanged(j2, true);
+        Assert.assertEquals(3, mFmc.getNumRunningPackages());
+    }
+
     private void setShowStopButtonForUserAllowlistedApps(boolean enable) {
         mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
                 SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_STOP_BUTTON_FOR_USER_ALLOWLISTED_APPS,
@@ -251,6 +393,33 @@
         mBackgroundExecutor.runAllReady();
     }
 
+    private void setShowUserVisibleJobs(boolean enable) {
+        if (mFmc.getIncludesUserVisibleJobs() == enable) {
+            // No change.
+            return;
+        }
+
+        mDeviceConfigProxyFake.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
+                SystemUiDeviceConfigFlags.TASK_MANAGER_SHOW_USER_VISIBLE_JOBS,
+                enable ? "true" : "false", false);
+        mBackgroundExecutor.advanceClockToLast();
+        mBackgroundExecutor.runAllReady();
+
+        ArgumentCaptor<IUserVisibleJobObserver> iUserVisibleJobObserverArgumentCaptor =
+                ArgumentCaptor.forClass(IUserVisibleJobObserver.class);
+        if (enable) {
+            mJobSchedulerInOrder.verify(mJobScheduler).registerUserVisibleJobObserver(
+                    iUserVisibleJobObserverArgumentCaptor.capture()
+            );
+            mIUserVisibleJobObserver = iUserVisibleJobObserverArgumentCaptor.getValue();
+        } else {
+            mJobSchedulerInOrder.verify(mJobScheduler).unregisterUserVisibleJobObserver(
+                    eq(mIUserVisibleJobObserver)
+            );
+            mIUserVisibleJobObserver = null;
+        }
+    }
+
     private void setBackgroundRestrictionExemptionReason(String pkgName, int uid, int reason)
             throws Exception {
         Mockito.doReturn(uid)
@@ -275,6 +444,7 @@
                 mBackgroundExecutor,
                 mSystemClock,
                 mIActivityManager,
+                mJobScheduler,
                 mPackageManager,
                 mUserTracker,
                 mDeviceConfigProxyFake,
@@ -304,6 +474,15 @@
         mUserTrackerCallback = userTrackerCallbackArgumentCaptor.getValue();
         mShowFgsManagerReceiver = showFgsManagerReceiverArgumentCaptor.getValue();
 
+        if (result.getIncludesUserVisibleJobs()) {
+            ArgumentCaptor<IUserVisibleJobObserver> iUserVisibleJobObserverArgumentCaptor =
+                    ArgumentCaptor.forClass(IUserVisibleJobObserver.class);
+            mJobSchedulerInOrder.verify(mJobScheduler).registerUserVisibleJobObserver(
+                    iUserVisibleJobObserverArgumentCaptor.capture()
+            );
+            mIUserVisibleJobObserver = iUserVisibleJobObserverArgumentCaptor.getValue();
+        }
+
         return result;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
index 645b1cd..23466cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/domain/interactor/FooterActionsInteractorTest.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.nullable
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.TestCoroutineScheduler
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,7 +56,7 @@
 
     @Before
     fun setUp() {
-        utils = FooterActionsTestUtils(context, TestableLooper.get(this))
+        utils = FooterActionsTestUtils(context, TestableLooper.get(this), TestCoroutineScheduler())
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index 081a218..47afa70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.broadcast.BroadcastDispatcher
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.qs.FakeFgsManagerController
 import com.android.systemui.qs.QSSecurityFooterUtils
 import com.android.systemui.qs.footer.FooterActionsTestUtils
@@ -44,12 +45,9 @@
 import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.launch
-import kotlinx.coroutines.test.TestCoroutineScheduler
 import kotlinx.coroutines.test.TestScope
-import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import kotlinx.coroutines.test.advanceUntilIdle
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -62,16 +60,20 @@
 @RunWith(AndroidTestingRunner::class)
 @RunWithLooper
 class FooterActionsViewModelTest : SysuiTestCase() {
+    private val testScope = TestScope()
     private lateinit var utils: FooterActionsTestUtils
-    private val testDispatcher = UnconfinedTestDispatcher(TestCoroutineScheduler())
 
     @Before
     fun setUp() {
-        utils = FooterActionsTestUtils(context, TestableLooper.get(this))
+        utils = FooterActionsTestUtils(context, TestableLooper.get(this), testScope.testScheduler)
+    }
+
+    private fun runTest(block: suspend TestScope.() -> Unit) {
+        testScope.runTest(testBody = block)
     }
 
     @Test
-    fun settingsButton() = runBlockingTest {
+    fun settingsButton() = runTest {
         val underTest = utils.footerActionsViewModel(showPowerButton = false)
         val settings = underTest.settings
 
@@ -87,7 +89,7 @@
     }
 
     @Test
-    fun powerButton() = runBlockingTest {
+    fun powerButton() = runTest {
         // Without power button.
         val underTestWithoutPower = utils.footerActionsViewModel(showPowerButton = false)
         assertThat(underTestWithoutPower.power).isNull()
@@ -114,7 +116,7 @@
     }
 
     @Test
-    fun userSwitcher() = runBlockingTest {
+    fun userSwitcher() = runTest {
         val picture: Drawable = mock()
         val userInfoController = FakeUserInfoController(FakeInfo(picture = picture))
         val settings = FakeSettings()
@@ -135,7 +137,6 @@
                 showPowerButton = false,
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
-                        bgDispatcher = testDispatcher,
                         userSwitcherRepository =
                             utils.userSwitcherRepository(
                                 userTracker = userTracker,
@@ -143,22 +144,12 @@
                                 userManager = userManager,
                                 userInfoController = userInfoController,
                                 userSwitcherController = userSwitcherControllerWrapper.controller,
-                                bgDispatcher = testDispatcher,
                             ),
                     )
             )
 
         // Collect the user switcher into currentUserSwitcher.
-        var currentUserSwitcher: FooterActionsButtonViewModel? = null
-        val job = launch { underTest.userSwitcher.collect { currentUserSwitcher = it } }
-        fun currentUserSwitcher(): FooterActionsButtonViewModel? {
-            // Make sure we finish collecting the current user switcher. This is necessary because
-            // combined flows launch multiple coroutines in the current scope so we need to make
-            // sure we process all coroutines triggered by our flow collection before we make
-            // assertions on the current buttons.
-            advanceUntilIdle()
-            return currentUserSwitcher
-        }
+        val currentUserSwitcher = collectLastValue(underTest.userSwitcher)
 
         // The user switcher is disabled.
         assertThat(currentUserSwitcher()).isNull()
@@ -203,12 +194,10 @@
         // in guest mode.
         userInfoController.updateInfo { this.picture = mock<UserIconDrawable>() }
         assertThat(iconTint()).isNull()
-
-        job.cancel()
     }
 
     @Test
-    fun security() = runBlockingTest {
+    fun security() = runTest {
         val securityController = FakeSecurityController()
         val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()
 
@@ -224,22 +213,15 @@
                 footerActionsInteractor =
                     utils.footerActionsInteractor(
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
-                        bgDispatcher = testDispatcher,
                         securityRepository =
                             utils.securityRepository(
                                 securityController = securityController,
-                                bgDispatcher = testDispatcher,
                             ),
                     ),
             )
 
         // Collect the security model into currentSecurity.
-        var currentSecurity: FooterActionsSecurityButtonViewModel? = null
-        val job = launch { underTest.security.collect { currentSecurity = it } }
-        fun currentSecurity(): FooterActionsSecurityButtonViewModel? {
-            advanceUntilIdle()
-            return currentSecurity
-        }
+        val currentSecurity = collectLastValue(underTest.security)
 
         // By default, we always return a null SecurityButtonConfig.
         assertThat(currentSecurity()).isNull()
@@ -270,12 +252,10 @@
         security = currentSecurity()
         assertThat(security).isNotNull()
         assertThat(security!!.onClick).isNull()
-
-        job.cancel()
     }
 
     @Test
-    fun foregroundServices() = runBlockingTest {
+    fun foregroundServices() = runTest {
         val securityController = FakeSecurityController()
         val fgsManagerController =
             FakeFgsManagerController(
@@ -300,21 +280,14 @@
                         securityRepository =
                             utils.securityRepository(
                                 securityController,
-                                bgDispatcher = testDispatcher,
                             ),
                         foregroundServicesRepository =
                             utils.foregroundServicesRepository(fgsManagerController),
-                        bgDispatcher = testDispatcher,
                     ),
             )
 
         // Collect the security model into currentSecurity.
-        var currentForegroundServices: FooterActionsForegroundServicesButtonViewModel? = null
-        val job = launch { underTest.foregroundServices.collect { currentForegroundServices = it } }
-        fun currentForegroundServices(): FooterActionsForegroundServicesButtonViewModel? {
-            advanceUntilIdle()
-            return currentForegroundServices
-        }
+        val currentForegroundServices = collectLastValue(underTest.foregroundServices)
 
         // We don't show the foreground services button if the number of running packages is not
         // > 1.
@@ -356,12 +329,10 @@
         }
         securityController.updateState {}
         assertThat(currentForegroundServices()?.displayText).isFalse()
-
-        job.cancel()
     }
 
     @Test
-    fun observeDeviceMonitoringDialogRequests() = runBlockingTest {
+    fun observeDeviceMonitoringDialogRequests() = runTest {
         val qsSecurityFooterUtils = mock<QSSecurityFooterUtils>()
         val broadcastDispatcher = mock<BroadcastDispatcher>()
 
@@ -390,7 +361,6 @@
                     utils.footerActionsInteractor(
                         qsSecurityFooterUtils = qsSecurityFooterUtils,
                         broadcastDispatcher = broadcastDispatcher,
-                        bgDispatcher = testDispatcher,
                     ),
             )
 
@@ -415,7 +385,4 @@
         underTest.onVisibilityChangeRequested(visible = true)
         assertThat(underTest.isVisible.value).isTrue()
     }
-
-    private fun runBlockingTest(block: suspend TestScope.() -> Unit) =
-        runTest(testDispatcher) { block() }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java
new file mode 100644
index 0000000..ea0e454
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/reardisplay/RearDisplayDialogControllerTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.reardisplay;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.hardware.devicestate.DeviceStateManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+
+import java.util.concurrent.Executor;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class RearDisplayDialogControllerTest extends SysuiTestCase {
+
+    @Mock
+    private CommandQueue mCommandQueue;
+
+    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
+
+
+    private static final int CLOSED_BASE_STATE = 0;
+    private static final int OPEN_BASE_STATE = 1;
+
+    @Test
+    public void testClosedDialogIsShown() {
+        RearDisplayDialogController controller = new RearDisplayDialogController(mContext,
+                mCommandQueue, mFakeExecutor);
+        controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback());
+        controller.setFoldedStates(new int[]{0});
+        controller.setAnimationRepeatCount(0);
+
+        controller.showRearDisplayDialog(CLOSED_BASE_STATE);
+        assertTrue(controller.mRearDisplayEducationDialog.isShowing());
+        View deviceOpenedWarningTextView = controller.mRearDisplayEducationDialog.findViewById(
+                R.id.rear_display_warning_text_view);
+        assertNull(deviceOpenedWarningTextView);
+    }
+
+    @Test
+    public void testOpenDialogIsShown() {
+        RearDisplayDialogController controller = new RearDisplayDialogController(mContext,
+                mCommandQueue, mFakeExecutor);
+        controller.setDeviceStateManagerCallback(new TestDeviceStateManagerCallback());
+        controller.setFoldedStates(new int[]{0});
+        controller.setAnimationRepeatCount(0);
+
+        controller.showRearDisplayDialog(OPEN_BASE_STATE);
+
+        assertTrue(controller.mRearDisplayEducationDialog.isShowing());
+        View deviceOpenedWarningTextView = controller.mRearDisplayEducationDialog.findViewById(
+                R.id.rear_display_warning_text_view);
+        assertNotNull(deviceOpenedWarningTextView);
+    }
+
+    /**
+     * Empty device state manager callbacks, so we can verify that the correct
+     * dialogs are being created regardless of device state of the test device.
+     */
+    private static class TestDeviceStateManagerCallback implements
+            DeviceStateManager.DeviceStateCallback {
+
+        @Override
+        public void onStateChanged(int state) { }
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index 013e58e..69f3e987 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -33,6 +33,9 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.settings.UserContextProvider;
+import com.android.systemui.settings.UserTracker;
+import com.android.systemui.util.concurrency.FakeExecutor;
+import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -49,12 +52,16 @@
  */
 public class RecordingControllerTest extends SysuiTestCase {
 
+    private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
+    private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
     @Mock
     private RecordingController.RecordingStateChangeCallback mCallback;
     @Mock
     private BroadcastDispatcher mBroadcastDispatcher;
     @Mock
     private UserContextProvider mUserContextProvider;
+    @Mock
+    private UserTracker mUserTracker;
 
     private RecordingController mController;
 
@@ -63,7 +70,8 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mController = new RecordingController(mBroadcastDispatcher, mUserContextProvider);
+        mController = new RecordingController(mMainExecutor, mBroadcastDispatcher,
+                mUserContextProvider, mUserTracker);
         mController.addCallback(mCallback);
     }
 
@@ -176,9 +184,7 @@
         mController.updateState(true);
 
         // and user is changed
-        Intent intent = new Intent(Intent.ACTION_USER_SWITCHED)
-                .putExtra(Intent.EXTRA_USER_HANDLE, USER_ID);
-        mController.mUserChangeReceiver.onReceive(mContext, intent);
+        mController.mUserChangedCallback.onUserChanged(USER_ID, mContext);
 
         // Ensure that the recording was stopped
         verify(mCallback).onRecordingEnd();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
index 6d9b01e..020a866 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/UserFileManagerImplTest.kt
@@ -50,24 +50,20 @@
 
     lateinit var userFileManager: UserFileManagerImpl
     lateinit var backgroundExecutor: FakeExecutor
-    @Mock
-    lateinit var userManager: UserManager
-    @Mock
-    lateinit var broadcastDispatcher: BroadcastDispatcher
+    @Mock lateinit var userManager: UserManager
+    @Mock lateinit var broadcastDispatcher: BroadcastDispatcher
 
     @Before
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         backgroundExecutor = FakeExecutor(FakeSystemClock())
-        userFileManager = UserFileManagerImpl(context, userManager,
-            broadcastDispatcher, backgroundExecutor)
+        userFileManager =
+            UserFileManagerImpl(context, userManager, broadcastDispatcher, backgroundExecutor)
     }
 
     @After
     fun end() {
-        val dir = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID)
+        val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID)
         dir.deleteRecursively()
     }
 
@@ -82,13 +78,14 @@
     @Test
     fun testGetSharedPreferences() {
         val secondarySharedPref = userFileManager.getSharedPreferences(TEST_FILE_NAME, 0, 11)
-        val secondaryUserDir = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID,
-            "11",
-            UserFileManagerImpl.SHARED_PREFS,
-            TEST_FILE_NAME
-        )
+        val secondaryUserDir =
+            Environment.buildPath(
+                context.filesDir,
+                UserFileManagerImpl.ID,
+                "11",
+                UserFileManagerImpl.SHARED_PREFS,
+                TEST_FILE_NAME
+            )
 
         assertThat(secondarySharedPref).isNotNull()
         assertThat(secondaryUserDir.exists())
@@ -101,32 +98,35 @@
         val userFileManager = spy(userFileManager)
         userFileManager.start()
         verify(userFileManager).clearDeletedUserData()
-        verify(broadcastDispatcher).registerReceiver(any(BroadcastReceiver::class.java),
-            any(IntentFilter::class.java),
-            any(Executor::class.java), isNull(), eq(Context.RECEIVER_EXPORTED), isNull())
+        verify(broadcastDispatcher)
+            .registerReceiver(
+                any(BroadcastReceiver::class.java),
+                any(IntentFilter::class.java),
+                any(Executor::class.java),
+                isNull(),
+                eq(Context.RECEIVER_EXPORTED),
+                isNull()
+            )
     }
 
     @Test
     fun testClearDeletedUserData() {
-        val dir = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID,
-            "11",
-            "files"
-        )
+        val dir = Environment.buildPath(context.filesDir, UserFileManagerImpl.ID, "11", "files")
         dir.mkdirs()
-        val file = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID,
-            "11",
-            "files",
-            TEST_FILE_NAME
-        )
-        val secondaryUserDir = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID,
-            "11",
-        )
+        val file =
+            Environment.buildPath(
+                context.filesDir,
+                UserFileManagerImpl.ID,
+                "11",
+                "files",
+                TEST_FILE_NAME
+            )
+        val secondaryUserDir =
+            Environment.buildPath(
+                context.filesDir,
+                UserFileManagerImpl.ID,
+                "11",
+            )
         file.createNewFile()
         assertThat(secondaryUserDir.exists()).isTrue()
         assertThat(file.exists()).isTrue()
@@ -139,15 +139,16 @@
 
     @Test
     fun testEnsureParentDirExists() {
-        val file = Environment.buildPath(
-            context.filesDir,
-            UserFileManagerImpl.ID,
-            "11",
-            "files",
-            TEST_FILE_NAME
-        )
+        val file =
+            Environment.buildPath(
+                context.filesDir,
+                UserFileManagerImpl.ID,
+                "11",
+                "files",
+                TEST_FILE_NAME
+            )
         assertThat(file.parentFile.exists()).isFalse()
-        userFileManager.ensureParentDirExists(file)
+        UserFileManagerImpl.ensureParentDirExists(file)
         assertThat(file.parentFile.exists()).isTrue()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
index 9c36be6..88651c1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/CombinedShadeHeaderConstraintsTest.kt
@@ -23,9 +23,11 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
 import org.junit.Before
+import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -37,6 +39,9 @@
     private lateinit var qsConstraint: ConstraintSet
     private lateinit var largeScreenConstraint: ConstraintSet
 
+    @get:Rule
+    val expect: Expect = Expect.create()
+
     @Before
     fun setUp() {
         qqsConstraint = ConstraintSet().apply {
@@ -344,6 +349,32 @@
     }
 
     @Test
+    fun testCheckViewsDontChangeSizeBetweenAnimationConstraints() {
+        val views = mapOf(
+                R.id.clock to "clock",
+                R.id.date to "date",
+                R.id.statusIcons to "icons",
+                R.id.privacy_container to "privacy",
+                R.id.carrier_group to "carriers",
+                R.id.batteryRemainingIcon to "battery",
+        )
+        views.forEach { (id, name) ->
+            expect.withMessage("$name changes height")
+                    .that(qqsConstraint.getConstraint(id).layout.mHeight.fromConstraint())
+                    .isEqualTo(qsConstraint.getConstraint(id).layout.mHeight.fromConstraint())
+            expect.withMessage("$name changes width")
+                    .that(qqsConstraint.getConstraint(id).layout.mWidth.fromConstraint())
+                    .isEqualTo(qsConstraint.getConstraint(id).layout.mWidth.fromConstraint())
+        }
+    }
+
+    private fun Int.fromConstraint() = when (this) {
+        -1 -> "MATCH_PARENT"
+        -2 -> "WRAP_CONTENT"
+        else -> toString()
+    }
+
+    @Test
     fun testEmptyCutoutDateIconsAreConstrainedWidth() {
         CombinedShadeHeadersConstraintManagerImpl.emptyCutoutConstraints()()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
index e1007fa..1d30ad9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerCombinedTest.kt
@@ -35,6 +35,8 @@
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -44,16 +46,17 @@
 import com.android.systemui.qs.carrier.QSCarrierGroupController
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.HEADER_TRANSITION_ID
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_CONSTRAINT
-import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.LARGE_SCREEN_HEADER_TRANSITION_ID
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QQS_HEADER_CONSTRAINT
 import com.android.systemui.shade.LargeScreenShadeHeaderController.Companion.QS_HEADER_CONSTRAINT
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusIconContainer
+import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.VariableDateView
 import com.android.systemui.statusbar.policy.VariableDateViewController
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
@@ -73,6 +76,7 @@
 import org.mockito.Mockito.clearInvocations
 import org.mockito.Mockito.inOrder
 import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.junit.MockitoJUnit
@@ -104,7 +108,7 @@
     @Mock
     private lateinit var featureFlags: FeatureFlags
     @Mock
-    private lateinit var clock: TextView
+    private lateinit var clock: Clock
     @Mock
     private lateinit var date: VariableDateView
     @Mock
@@ -138,6 +142,7 @@
     private lateinit var qsConstraints: ConstraintSet
     @Mock
     private lateinit var largeScreenConstraints: ConstraintSet
+    @Mock private lateinit var demoModeController: DemoModeController
 
     @JvmField @Rule
     val mockitoRule = MockitoJUnit.rule()
@@ -146,10 +151,12 @@
     private lateinit var controller: LargeScreenShadeHeaderController
     private lateinit var carrierIconSlots: List<String>
     private val configurationController = FakeConfigurationController()
+    private lateinit var demoModeControllerCapture: ArgumentCaptor<DemoMode>
 
     @Before
     fun setUp() {
-        whenever<TextView>(view.findViewById(R.id.clock)).thenReturn(clock)
+        demoModeControllerCapture = argumentCaptor<DemoMode>()
+        whenever<Clock>(view.findViewById(R.id.clock)).thenReturn(clock)
         whenever(clock.context).thenReturn(mockedContext)
 
         whenever<TextView>(view.findViewById(R.id.date)).thenReturn(date)
@@ -195,7 +202,8 @@
             dumpManager,
             featureFlags,
             qsCarrierGroupControllerBuilder,
-            combinedShadeHeadersConstraintManager
+            combinedShadeHeadersConstraintManager,
+            demoModeController
         )
         whenever(view.isAttachedToWindow).thenReturn(true)
         controller.init()
@@ -204,20 +212,6 @@
     }
 
     @Test
-    fun testCorrectConstraints() {
-        val captor = ArgumentCaptor.forClass(XmlResourceParser::class.java)
-
-        verify(qqsConstraints).load(eq(context), capture(captor))
-        assertThat(captor.value.getResId()).isEqualTo(R.xml.qqs_header)
-
-        verify(qsConstraints).load(eq(context), capture(captor))
-        assertThat(captor.value.getResId()).isEqualTo(R.xml.qs_header)
-
-        verify(largeScreenConstraints).load(eq(context), capture(captor))
-        assertThat(captor.value.getResId()).isEqualTo(R.xml.large_screen_shade_header)
-    }
-
-    @Test
     fun testControllersCreatedAndInitialized() {
         verify(variableDateViewController).init()
 
@@ -279,16 +273,6 @@
     }
 
     @Test
-    fun testLargeScreenActive_true() {
-        controller.largeScreenActive = false // Make sure there's a change
-        clearInvocations(view)
-
-        controller.largeScreenActive = true
-
-        verify(view).setTransition(LARGE_SCREEN_HEADER_TRANSITION_ID)
-    }
-
-    @Test
     fun testLargeScreenActive_false() {
         controller.largeScreenActive = true // Make sure there's a change
         clearInvocations(view)
@@ -617,6 +601,21 @@
     }
 
     @Test
+    fun demoMode_attachDemoMode() {
+        verify(demoModeController).addCallback(capture(demoModeControllerCapture))
+        demoModeControllerCapture.value.onDemoModeStarted()
+        verify(clock).onDemoModeStarted()
+    }
+
+    @Test
+    fun demoMode_detachDemoMode() {
+        controller.simulateViewDetached()
+        verify(demoModeController).removeCallback(capture(demoModeControllerCapture))
+        demoModeControllerCapture.value.onDemoModeFinished()
+        verify(clock).onDemoModeFinished()
+    }
+
+    @Test
     fun animateOutOnStartCustomizing() {
         val animator = Mockito.mock(ViewPropertyAnimator::class.java, Answers.RETURNS_SELF)
         val duration = 1000L
@@ -673,6 +672,25 @@
         verify(clock).pivotY = height.toFloat() / 2
     }
 
+    @Test
+    fun onDensityOrFontScaleChanged_reloadConstraints() {
+        // After density or font scale change, constraints need to be reloaded to reflect new
+        // dimensions.
+        reset(qqsConstraints)
+        reset(qsConstraints)
+        reset(largeScreenConstraints)
+
+        configurationController.notifyDensityOrFontScaleChanged()
+
+        val captor = ArgumentCaptor.forClass(XmlResourceParser::class.java)
+        verify(qqsConstraints).load(eq(context), capture(captor))
+        assertThat(captor.value.getResId()).isEqualTo(R.xml.qqs_header)
+        verify(qsConstraints).load(eq(context), capture(captor))
+        assertThat(captor.value.getResId()).isEqualTo(R.xml.qs_header)
+        verify(largeScreenConstraints).load(eq(context), capture(captor))
+        assertThat(captor.value.getResId()).isEqualTo(R.xml.large_screen_shade_header)
+    }
+
     private fun View.executeLayoutChange(
             left: Int,
             top: Int,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
index 90ae693..b4c8f98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/LargeScreenShadeHeaderControllerTest.kt
@@ -13,6 +13,8 @@
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.battery.BatteryMeterView
 import com.android.systemui.battery.BatteryMeterViewController
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.flags.FeatureFlags
 import com.android.systemui.flags.Flags
@@ -22,9 +24,12 @@
 import com.android.systemui.statusbar.phone.StatusBarContentInsetsProvider
 import com.android.systemui.statusbar.phone.StatusBarIconController
 import com.android.systemui.statusbar.phone.StatusIconContainer
+import com.android.systemui.statusbar.policy.Clock
 import com.android.systemui.statusbar.policy.FakeConfigurationController
 import com.android.systemui.statusbar.policy.VariableDateViewController
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.capture
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
@@ -52,7 +57,7 @@
     @Mock private lateinit var qsCarrierGroupController: QSCarrierGroupController
     @Mock private lateinit var qsCarrierGroupControllerBuilder: QSCarrierGroupController.Builder
     @Mock private lateinit var featureFlags: FeatureFlags
-    @Mock private lateinit var clock: TextView
+    @Mock private lateinit var clock: Clock
     @Mock private lateinit var date: TextView
     @Mock private lateinit var carrierGroup: QSCarrierGroup
     @Mock private lateinit var batteryMeterView: BatteryMeterView
@@ -66,6 +71,7 @@
         CombinedShadeHeadersConstraintManager
 
     @Mock private lateinit var mockedContext: Context
+    @Mock private lateinit var demoModeController: DemoModeController
 
     @JvmField @Rule val mockitoRule = MockitoJUnit.rule()
     var viewVisibility = View.GONE
@@ -76,7 +82,7 @@
 
     @Before
     fun setup() {
-        whenever<TextView>(view.findViewById(R.id.clock)).thenReturn(clock)
+        whenever<Clock>(view.findViewById(R.id.clock)).thenReturn(clock)
         whenever(clock.context).thenReturn(mockedContext)
         whenever<TextView>(view.findViewById(R.id.date)).thenReturn(date)
         whenever(date.context).thenReturn(mockedContext)
@@ -111,8 +117,9 @@
                 dumpManager,
                 featureFlags,
                 qsCarrierGroupControllerBuilder,
-                combinedShadeHeadersConstraintManager
-        )
+                combinedShadeHeadersConstraintManager,
+                demoModeController
+                )
         whenever(view.isAttachedToWindow).thenReturn(true)
         mLargeScreenShadeHeaderController.init()
         carrierIconSlots = listOf(
@@ -230,4 +237,21 @@
         verify(animator).setInterpolator(Interpolators.ALPHA_IN)
         verify(animator).start()
     }
+
+    @Test
+    fun demoMode_attachDemoMode() {
+        val cb = argumentCaptor<DemoMode>()
+        verify(demoModeController).addCallback(capture(cb))
+        cb.value.onDemoModeStarted()
+        verify(clock).onDemoModeStarted()
+    }
+
+    @Test
+    fun demoMode_detachDemoMode() {
+        mLargeScreenShadeHeaderController.simulateViewDetached()
+        val cb = argumentCaptor<DemoMode>()
+        verify(demoModeController).removeCallback(capture(cb))
+        cb.value.onDemoModeFinished()
+        verify(clock).onDemoModeFinished()
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 69a4559..56a840c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -43,6 +43,7 @@
 import static org.mockito.Mockito.inOrder;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -131,6 +132,7 @@
 import com.android.systemui.statusbar.notification.ConversationNotificationManager;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
+import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinatorLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.row.ExpandableView.OnHeightChangedListener;
 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -383,7 +385,8 @@
                                 mInteractionJankMonitor, mShadeExpansionStateManager),
                         mKeyguardBypassController,
                         mDozeParameters,
-                        mScreenOffAnimationController);
+                        mScreenOffAnimationController,
+                        mock(NotificationWakeUpCoordinatorLogger.class));
         mConfigurationController = new ConfigurationControllerImpl(mContext);
         PulseExpansionHandler expansionHandler = new PulseExpansionHandler(
                 mContext,
@@ -499,8 +502,18 @@
                 mDumpManager);
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
+                null,
                 () -> {},
                 mNotificationShelfController);
+        mNotificationPanelViewController.setTrackingStartedListener(() -> {});
+        mNotificationPanelViewController.setOpenCloseListener(
+                new NotificationPanelViewController.OpenCloseListener() {
+                    @Override
+                    public void onClosingFinished() {}
+
+                    @Override
+                    public void onOpenStarted() {}
+                });
         mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
         ArgumentCaptor<View.OnAttachStateChangeListener> onAttachStateChangeListenerArgumentCaptor =
                 ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
@@ -518,6 +531,8 @@
                 .setHeadsUpAppearanceController(mock(HeadsUpAppearanceController.class));
         verify(mNotificationStackScrollLayoutController)
                 .setOnEmptySpaceClickListener(mEmptySpaceClickListenerCaptor.capture());
+        verify(mKeyguardStatusViewController).displayClock(LARGE, /* animate */ true);
+        reset(mKeyguardStatusViewController);
     }
 
     @After
@@ -597,7 +612,7 @@
 
     @Test
     public void getVerticalSpaceForLockscreenNotifications_useLockIconBottomPadding_returnsSpaceAvailable() {
-        setBottomPadding(/* stackScrollLayoutBottom= */ 100,
+        setBottomPadding(/* stackScrollLayoutBottom= */ 180,
                 /* lockIconPadding= */ 20,
                 /* indicationPadding= */ 0,
                 /* ambientPadding= */ 0);
@@ -608,7 +623,7 @@
 
     @Test
     public void getVerticalSpaceForLockscreenNotifications_useIndicationBottomPadding_returnsSpaceAvailable() {
-        setBottomPadding(/* stackScrollLayoutBottom= */ 100,
+        setBottomPadding(/* stackScrollLayoutBottom= */ 180,
                 /* lockIconPadding= */ 0,
                 /* indicationPadding= */ 30,
                 /* ambientPadding= */ 0);
@@ -619,7 +634,7 @@
 
     @Test
     public void getVerticalSpaceForLockscreenNotifications_useAmbientBottomPadding_returnsSpaceAvailable() {
-        setBottomPadding(/* stackScrollLayoutBottom= */ 100,
+        setBottomPadding(/* stackScrollLayoutBottom= */ 180,
                 /* lockIconPadding= */ 0,
                 /* indicationPadding= */ 0,
                 /* ambientPadding= */ 40);
@@ -790,55 +805,6 @@
     }
 
     @Test
-    public void handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(false);
-
-        boolean returnVal = mNotificationPanelViewController
-                .getStatusBarTouchEventHandler()
-                .handleTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-
-        assertThat(returnVal).isFalse();
-        verify(mView, never()).dispatchTouchEvent(any());
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(false);
-
-        boolean returnVal = mNotificationPanelViewController
-                .getStatusBarTouchEventHandler()
-                .handleTouchEvent(
-                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0));
-
-        assertThat(returnVal).isTrue();
-        verify(mView, never()).dispatchTouchEvent(any());
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(false);
-        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0);
-
-        mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
-
-        verify(mView).dispatchTouchEvent(event);
-    }
-
-    @Test
-    public void handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
-        when(mCommandQueue.panelsEnabled()).thenReturn(true);
-        when(mView.isEnabled()).thenReturn(true);
-        MotionEvent event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0);
-
-        mNotificationPanelViewController.getStatusBarTouchEventHandler().handleTouchEvent(event);
-
-        verify(mView).dispatchTouchEvent(event);
-    }
-
-    @Test
     public void testA11y_initializeNode() {
         AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
         mAccessibilityDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
@@ -991,7 +957,7 @@
     }
 
     @Test
-    public void testFinishInflate_userSwitcherDisabled_doNotInflateUserSwitchView() {
+    public void testFinishInflate_userSwitcherDisabled_doNotInflateUserSwitchView_initClock() {
         givenViewAttached();
         when(mResources.getBoolean(
                 com.android.internal.R.bool.config_keyguardUserSwitcher)).thenReturn(true);
@@ -1002,6 +968,7 @@
         mNotificationPanelViewController.onFinishInflate();
 
         verify(mUserSwitcherStubView, never()).inflate();
+        verify(mKeyguardStatusViewController, times(3)).displayClock(LARGE, /* animate */ true);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index e1346ea..0000c32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -118,13 +118,6 @@
     }
 
     @Test
-    public void testCollapsePanels() {
-        mCommandQueue.animateCollapsePanels();
-        waitForIdleSync();
-        verify(mCallbacks).animateCollapsePanels(eq(0), eq(false));
-    }
-
-    @Test
     public void testExpandSettings() {
         String panel = "some_panel";
         mCommandQueue.animateExpandSettingsPanel(panel);
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 15a687d..452606d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar;
 
-import static android.content.Intent.ACTION_USER_SWITCHED;
-
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
@@ -34,7 +32,6 @@
 import android.app.admin.DevicePolicyManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.os.Handler;
@@ -293,11 +290,9 @@
     }
 
     @Test
-    public void testActionUserSwitchedCallsOnUserSwitched() {
-        Intent intent = new Intent()
-                .setAction(ACTION_USER_SWITCHED)
-                .putExtra(Intent.EXTRA_USER_HANDLE, mSecondaryUser.id);
-        mLockscreenUserManager.getBaseBroadcastReceiverForTest().onReceive(mContext, intent);
+    public void testUserSwitchedCallsOnUserSwitched() {
+        mLockscreenUserManager.getUserTrackerCallbackForTest().onUserChanged(mSecondaryUser.id,
+                mContext);
         verify(mPresenter, times(1)).onUserSwitched(mSecondaryUser.id);
     }
 
@@ -366,6 +361,10 @@
             return mBaseBroadcastReceiver;
         }
 
+        public UserTracker.Callback getUserTrackerCallbackForTest() {
+            return mUserChangedCallback;
+        }
+
         public ContentObserver getLockscreenSettingsObserverForTest() {
             return mLockscreenSettingsObserver;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
index bdedd24..7f73856 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coordinator/KeyguardCoordinatorTest.kt
@@ -30,6 +30,8 @@
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.SectionHeaderVisibilityProvider
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProvider
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl
 import com.android.systemui.statusbar.notification.interruption.KeyguardNotificationVisibilityProvider
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.mockito.mock
@@ -103,6 +105,31 @@
     }
 
     @Test
+    fun unseenFilterUpdatesSeenProviderWhenSuppressing() {
+        whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
+
+        // GIVEN: Keyguard is not showing, and a notification is present
+        keyguardRepository.setKeyguardShowing(false)
+        runKeyguardCoordinatorTest {
+            val fakeEntry = NotificationEntryBuilder().build()
+            collectionListener.onEntryAdded(fakeEntry)
+
+            // WHEN: The keyguard is now showing
+            keyguardRepository.setKeyguardShowing(true)
+            testScheduler.runCurrent()
+
+            // THEN: The notification is recognized as "seen" and is filtered out.
+            assertThat(unseenFilter.shouldFilterOut(fakeEntry, 0L)).isTrue()
+
+            // WHEN: The filter is cleaned up
+            unseenFilter.onCleanup()
+
+            // THEN: The SeenNotificationProvider has been updated to reflect the suppression
+            assertThat(seenNotificationsProvider.hasFilteredOutSeenNotifications).isTrue()
+        }
+    }
+
+    @Test
     fun unseenFilterAllowsNewNotif() {
         whenever(notifPipelineFlags.shouldFilterUnseenNotifsOnKeyguard).thenReturn(true)
 
@@ -204,6 +231,7 @@
         testBlock: suspend KeyguardCoordinatorTestScope.() -> Unit
     ) {
         val testScope = TestScope(UnconfinedTestDispatcher())
+        val seenNotificationsProvider = SeenNotificationsProviderImpl()
         val keyguardCoordinator =
             KeyguardCoordinator(
                 keyguardNotifVisibilityProvider,
@@ -211,18 +239,20 @@
                 notifPipelineFlags,
                 testScope.backgroundScope,
                 sectionHeaderVisibilityProvider,
+                seenNotificationsProvider,
                 statusBarStateController,
             )
         keyguardCoordinator.attach(notifPipeline)
-        KeyguardCoordinatorTestScope(keyguardCoordinator, testScope).run {
-            testScheduler.advanceUntilIdle()
-            testScope.runTest(dispatchTimeoutMs = 1.seconds.inWholeMilliseconds) { testBlock() }
+        testScope.runTest(dispatchTimeoutMs = 1.seconds.inWholeMilliseconds) {
+            KeyguardCoordinatorTestScope(keyguardCoordinator, testScope, seenNotificationsProvider)
+                .testBlock()
         }
     }
 
     private inner class KeyguardCoordinatorTestScope(
         private val keyguardCoordinator: KeyguardCoordinator,
         private val scope: TestScope,
+        val seenNotificationsProvider: SeenNotificationsProvider,
     ) : CoroutineScope by scope {
         val testScheduler: TestCoroutineScheduler
             get() = scope.testScheduler
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
index 8b7b4de..6bd3f7a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/KeyguardNotificationVisibilityProviderTest.java
@@ -26,22 +26,17 @@
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 import static com.android.systemui.statusbar.StatusBarState.SHADE;
 import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
-import static com.android.systemui.util.mockito.KotlinMockitoHelpersKt.argThat;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -54,10 +49,10 @@
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.CoreStartable;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Main;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.settings.UserTracker;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.RankingBuilder;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
@@ -97,7 +92,7 @@
     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock private HighPriorityProvider mHighPriorityProvider;
     @Mock private SysuiStatusBarStateController mStatusBarStateController;
-    @Mock private BroadcastDispatcher mBroadcastDispatcher;
+    @Mock private UserTracker mUserTracker;
     private final FakeSettings mFakeSettings = new FakeSettings();
 
     private KeyguardNotificationVisibilityProvider mKeyguardNotificationVisibilityProvider;
@@ -117,7 +112,7 @@
                                 mKeyguardUpdateMonitor,
                                 mHighPriorityProvider,
                                 mStatusBarStateController,
-                                mBroadcastDispatcher,
+                                mUserTracker,
                                 mFakeSettings,
                                 mFakeSettings);
         mKeyguardNotificationVisibilityProvider = component.getProvider();
@@ -205,23 +200,19 @@
     }
 
     @Test
-    public void notifyListeners_onReceiveUserSwitchBroadcast() {
-        ArgumentCaptor<BroadcastReceiver> callbackCaptor =
-                ArgumentCaptor.forClass(BroadcastReceiver.class);
-        verify(mBroadcastDispatcher).registerReceiver(
+    public void notifyListeners_onReceiveUserSwitchCallback() {
+        ArgumentCaptor<UserTracker.Callback> callbackCaptor =
+                ArgumentCaptor.forClass(UserTracker.Callback.class);
+        verify(mUserTracker).addCallback(
                 callbackCaptor.capture(),
-                argThat(intentFilter -> intentFilter.hasAction(Intent.ACTION_USER_SWITCHED)),
-                isNull(),
-                isNull(),
-                eq(Context.RECEIVER_EXPORTED),
-                isNull());
-        BroadcastReceiver callback = callbackCaptor.getValue();
+                any());
+        UserTracker.Callback callback = callbackCaptor.getValue();
 
         Consumer<String> listener = mock(Consumer.class);
         mKeyguardNotificationVisibilityProvider.addOnStateChangedListener(listener);
 
         when(mStatusBarStateController.getCurrentOrUpcomingState()).thenReturn(KEYGUARD);
-        callback.onReceive(mContext, new Intent(Intent.ACTION_USER_SWITCHED));
+        callback.onUserChanged(CURR_USER_ID, mContext);
 
         verify(listener).accept(anyString());
     }
@@ -619,7 +610,7 @@
                     @BindsInstance KeyguardUpdateMonitor keyguardUpdateMonitor,
                     @BindsInstance HighPriorityProvider highPriorityProvider,
                     @BindsInstance SysuiStatusBarStateController statusBarStateController,
-                    @BindsInstance BroadcastDispatcher broadcastDispatcher,
+                    @BindsInstance UserTracker userTracker,
                     @BindsInstance SecureSettings secureSettings,
                     @BindsInstance GlobalSettings globalSettings
             );
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
index ea311da..21aae00 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImplTest.java
@@ -17,6 +17,7 @@
 
 
 import static android.app.Notification.FLAG_BUBBLE;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
 import static android.app.Notification.GROUP_ALERT_SUMMARY;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
@@ -33,6 +34,8 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -390,6 +393,127 @@
         assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
     }
 
+    private long makeWhenHoursAgo(long hoursAgo) {
+        return System.currentTimeMillis() - (1000 * 60 * 60 * hoursAgo);
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_flagDisabled() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(false);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = makeWhenHoursAgo(25);
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_whenNow() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_whenRecent() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = makeWhenHoursAgo(13);
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_whenZero() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = 0L;
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(0L), anyLong(),
+                eq("when <= 0"));
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_whenNegative() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = -1L;
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(-1L), anyLong(),
+                eq("when <= 0"));
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_hasFullScreenIntent() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+        long when = makeWhenHoursAgo(25);
+
+        NotificationEntry entry = createFsiNotification(IMPORTANCE_HIGH, /* silent= */ false);
+        entry.getSbn().getNotification().when = when;
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(when), anyLong(),
+                eq("full-screen intent"));
+    }
+
+    @Test
+    public void testShouldHeadsUp_oldWhen_isForegroundService() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+        long when = makeWhenHoursAgo(25);
+
+        NotificationEntry entry = createFgsNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = when;
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isTrue();
+
+        verify(mLogger, never()).logNoHeadsUpOldWhen(any(), anyLong(), anyLong());
+        verify(mLogger).logMaybeHeadsUpDespiteOldWhen(eq(entry), eq(when), anyLong(),
+                eq("foreground service"));
+    }
+
+    @Test
+    public void testShouldNotHeadsUp_oldWhen() throws Exception {
+        ensureStateForHeadsUpWhenAwake();
+        when(mFlags.isNoHunForOldWhenEnabled()).thenReturn(true);
+        long when = makeWhenHoursAgo(25);
+
+        NotificationEntry entry = createNotification(IMPORTANCE_HIGH);
+        entry.getSbn().getNotification().when = when;
+
+        assertThat(mNotifInterruptionStateProvider.shouldHeadsUp(entry)).isFalse();
+
+        verify(mLogger).logNoHeadsUpOldWhen(eq(entry), eq(when), anyLong());
+        verify(mLogger, never()).logMaybeHeadsUpDespiteOldWhen(any(), anyLong(), anyLong(), any());
+    }
+
     @Test
     public void testShouldNotFullScreen_notPendingIntent_withStrictFlag() throws Exception {
         when(mFlags.fullScreenIntentRequiresKeyguard()).thenReturn(true);
@@ -763,6 +887,16 @@
         return createNotification(importance, n);
     }
 
+    private NotificationEntry createFgsNotification(int importance) {
+        Notification n = new Notification.Builder(getContext(), "a")
+                .setContentTitle("title")
+                .setContentText("content text")
+                .setFlag(FLAG_FOREGROUND_SERVICE, true)
+                .build();
+
+        return createNotification(importance, n);
+    }
+
     private final NotificationInterruptSuppressor
             mSuppressAwakeHeadsUp =
             new NotificationInterruptSuppressor() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
new file mode 100644
index 0000000..2d23f3c
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.row
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper
+import androidx.test.filters.SmallTest
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.flags.FeatureFlags
+import com.android.systemui.flags.Flags
+import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.PluginManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.SmartReplyController
+import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
+import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager
+import com.android.systemui.statusbar.notification.logging.NotificationLogger
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.SmartReplyConstants
+import com.android.systemui.statusbar.policy.dagger.RemoteInputViewSubcomponent
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.time.SystemClock
+import com.android.systemui.wmshell.BubblesManager
+import java.util.Optional
+import junit.framework.Assert
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.anyBoolean
+import org.mockito.Mockito.never
+import org.mockito.Mockito.`when` as whenever
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+@TestableLooper.RunWithLooper
+class ExpandableNotificationRowControllerTest : SysuiTestCase() {
+
+    private val appName = "MyApp"
+    private val notifKey = "MyNotifKey"
+
+    private val view: ExpandableNotificationRow = mock()
+    private val activableNotificationViewController: ActivatableNotificationViewController = mock()
+    private val rivSubComponentFactory: RemoteInputViewSubcomponent.Factory = mock()
+    private val metricsLogger: MetricsLogger = mock()
+    private val logBufferLogger: NotificationRowLogger = mock()
+    private val listContainer: NotificationListContainer = mock()
+    private val mediaManager: NotificationMediaManager = mock()
+    private val smartReplyConstants: SmartReplyConstants = mock()
+    private val smartReplyController: SmartReplyController = mock()
+    private val pluginManager: PluginManager = mock()
+    private val systemClock: SystemClock = mock()
+    private val keyguardBypassController: KeyguardBypassController = mock()
+    private val groupMembershipManager: GroupMembershipManager = mock()
+    private val groupExpansionManager: GroupExpansionManager = mock()
+    private val rowContentBindStage: RowContentBindStage = mock()
+    private val notifLogger: NotificationLogger = mock()
+    private val headsUpManager: HeadsUpManager = mock()
+    private val onExpandClickListener: ExpandableNotificationRow.OnExpandClickListener = mock()
+    private val statusBarStateController: StatusBarStateController = mock()
+    private val gutsManager: NotificationGutsManager = mock()
+    private val onUserInteractionCallback: OnUserInteractionCallback = mock()
+    private val falsingManager: FalsingManager = mock()
+    private val falsingCollector: FalsingCollector = mock()
+    private val featureFlags: FeatureFlags = mock()
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier = mock()
+    private val bubblesManager: BubblesManager = mock()
+    private val dragController: ExpandableNotificationRowDragController = mock()
+    private lateinit var controller: ExpandableNotificationRowController
+
+    @Before
+    fun setUp() {
+        allowTestableLooperAsMainThread()
+        controller =
+            ExpandableNotificationRowController(
+                view,
+                activableNotificationViewController,
+                rivSubComponentFactory,
+                metricsLogger,
+                logBufferLogger,
+                listContainer,
+                mediaManager,
+                smartReplyConstants,
+                smartReplyController,
+                pluginManager,
+                systemClock,
+                appName,
+                notifKey,
+                keyguardBypassController,
+                groupMembershipManager,
+                groupExpansionManager,
+                rowContentBindStage,
+                notifLogger,
+                headsUpManager,
+                onExpandClickListener,
+                statusBarStateController,
+                gutsManager,
+                /*allowLongPress=*/ false,
+                onUserInteractionCallback,
+                falsingManager,
+                falsingCollector,
+                featureFlags,
+                peopleNotificationIdentifier,
+                Optional.of(bubblesManager),
+                dragController
+            )
+    }
+
+    @After
+    fun tearDown() {
+        disallowTestableLooperAsMainThread()
+    }
+
+    @Test
+    fun offerKeepInParent_parentDismissed() {
+        whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
+            .thenReturn(true)
+        whenever(view.isParentDismissed).thenReturn(true)
+
+        Assert.assertTrue(controller.offerToKeepInParentForAnimation())
+        Mockito.verify(view).setKeepInParentForDismissAnimation(true)
+    }
+
+    @Test
+    fun offerKeepInParent_parentNotDismissed() {
+        whenever(featureFlags.isEnabled(Flags.NOTIFICATION_GROUP_DISMISSAL_ANIMATION))
+            .thenReturn(true)
+
+        Assert.assertFalse(controller.offerToKeepInParentForAnimation())
+        Mockito.verify(view, never()).setKeepInParentForDismissAnimation(anyBoolean())
+    }
+
+    @Test
+    fun removeFromParent_keptForAnimation() {
+        val parentView: ExpandableNotificationRow = mock()
+        whenever(view.notificationParent).thenReturn(parentView)
+        whenever(view.keepInParentForDismissAnimation()).thenReturn(true)
+
+        Assert.assertTrue(controller.removeFromParentIfKeptForAnimation())
+        Mockito.verify(parentView).removeChildNotification(view)
+    }
+
+    @Test
+    fun removeFromParent_notKeptForAnimation() {
+        val parentView: ExpandableNotificationRow = mock()
+        whenever(view.notificationParent).thenReturn(parentView)
+
+        Assert.assertFalse(controller.removeFromParentIfKeptForAnimation())
+        Mockito.verifyNoMoreInteractions(parentView)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
index ed2afe7..915924f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowDragControllerTest.java
@@ -41,7 +41,6 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.notification.logging.NotificationPanelLogger;
-import com.android.systemui.statusbar.notification.logging.NotificationPanelLoggerFake;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index 496bf37..088d165 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -299,7 +299,8 @@
     public ExpandableNotificationRow createBubble()
             throws Exception {
         Notification n = createNotification(false /* isGroupSummary */,
-                null /* groupKey */, makeBubbleMetadata(null));
+                null /* groupKey */,
+                makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */));
         n.flags |= FLAG_BUBBLE;
         ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
                 mDefaultInflationFlags, IMPORTANCE_HIGH);
@@ -332,7 +333,8 @@
     public ExpandableNotificationRow createBubbleInGroup()
             throws Exception {
         Notification n = createNotification(false /* isGroupSummary */,
-                GROUP_KEY /* groupKey */, makeBubbleMetadata(null));
+                GROUP_KEY /* groupKey */,
+                makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */));
         n.flags |= FLAG_BUBBLE;
         ExpandableNotificationRow row = generateRow(n, PKG, UID, USER_HANDLE,
                 mDefaultInflationFlags, IMPORTANCE_HIGH);
@@ -348,7 +350,7 @@
      * @param deleteIntent the intent to assign to {@link BubbleMetadata#deleteIntent}
      */
     public NotificationEntry createBubble(@Nullable PendingIntent deleteIntent) {
-        return createBubble(makeBubbleMetadata(deleteIntent), USER_HANDLE);
+        return createBubble(makeBubbleMetadata(deleteIntent, false /* autoExpand */), USER_HANDLE);
     }
 
     /**
@@ -357,7 +359,16 @@
      * @param handle the user to associate with this bubble.
      */
     public NotificationEntry createBubble(UserHandle handle) {
-        return createBubble(makeBubbleMetadata(null), handle);
+        return createBubble(makeBubbleMetadata(null /* deleteIntent */, false /* autoExpand */),
+                handle);
+    }
+
+    /**
+     * Returns an {@link NotificationEntry} that should be shown as a auto-expanded bubble.
+     */
+    public NotificationEntry createAutoExpandedBubble() {
+        return createBubble(makeBubbleMetadata(null /* deleteIntent */, true /* autoExpand */),
+                USER_HANDLE);
     }
 
     /**
@@ -565,7 +576,7 @@
         assertTrue(countDownLatch.await(500, TimeUnit.MILLISECONDS));
     }
 
-    private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent) {
+    private BubbleMetadata makeBubbleMetadata(PendingIntent deleteIntent, boolean autoExpand) {
         Intent target = new Intent(mContext, BubblesTestActivity.class);
         PendingIntent bubbleIntent = PendingIntent.getActivity(mContext, 0, target,
                 PendingIntent.FLAG_MUTABLE);
@@ -574,6 +585,7 @@
                         Icon.createWithResource(mContext, R.drawable.android))
                 .setDeleteIntent(deleteIntent)
                 .setDesiredHeight(314)
+                .setAutoExpandBubble(autoExpand)
                 .build();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
index 026c82e..645052f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutControllerTest.java
@@ -59,8 +59,10 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
+import com.android.systemui.statusbar.notification.NotifPipelineFlags;
 import com.android.systemui.statusbar.notification.collection.NotifCollection;
 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
+import com.android.systemui.statusbar.notification.collection.provider.SeenNotificationsProviderImpl;
 import com.android.systemui.statusbar.notification.collection.provider.VisibilityLocationProviderDelegator;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -119,6 +121,7 @@
     @Mock private GroupExpansionManager mGroupExpansionManager;
     @Mock private SectionHeaderController mSilentHeaderController;
     @Mock private NotifPipeline mNotifPipeline;
+    @Mock private NotifPipelineFlags mNotifPipelineFlags;
     @Mock private NotifCollection mNotifCollection;
     @Mock private UiEventLogger mUiEventLogger;
     @Mock private LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -170,12 +173,14 @@
                 mGroupExpansionManager,
                 mSilentHeaderController,
                 mNotifPipeline,
+                mNotifPipelineFlags,
                 mNotifCollection,
                 mLockscreenShadeTransitionController,
                 mShadeTransitionController,
                 mUiEventLogger,
                 mRemoteInputManager,
                 mVisibilityLocationProviderDelegator,
+                new SeenNotificationsProviderImpl(),
                 mShadeController,
                 mJankMonitor,
                 mStackLogger,
@@ -228,14 +233,16 @@
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ true,
-                /* notifVisibleInShade= */ true);
+                /* notifVisibleInShade= */ true,
+                /* areSeenNotifsFiltered= */false);
 
         setupShowEmptyShadeViewState(false);
         reset(mNotificationStackScrollLayout);
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ false,
-                /* notifVisibleInShade= */ true);
+                /* notifVisibleInShade= */ true,
+                /* areSeenNotifsFiltered= */false);
     }
 
     @Test
@@ -248,14 +255,16 @@
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ true,
-                /* notifVisibleInShade= */ false);
+                /* notifVisibleInShade= */ false,
+                /* areSeenNotifsFiltered= */false);
 
         setupShowEmptyShadeViewState(false);
         reset(mNotificationStackScrollLayout);
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ false,
-                /* notifVisibleInShade= */ false);
+                /* notifVisibleInShade= */ false,
+                /* areSeenNotifsFiltered= */false);
     }
 
     @Test
@@ -274,14 +283,16 @@
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ true,
-                /* notifVisibleInShade= */ false);
+                /* notifVisibleInShade= */ false,
+                /* areSeenNotifsFiltered= */false);
 
         mController.setQsFullScreen(true);
         reset(mNotificationStackScrollLayout);
         mController.updateShowEmptyShadeView();
         verify(mNotificationStackScrollLayout).updateEmptyShadeView(
                 /* visible= */ true,
-                /* notifVisibleInShade= */ false);
+                /* notifVisibleInShade= */ false,
+                /* areSeenNotifsFiltered= */false);
     }
 
     @Test
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 dceb4ff..07ea630 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
@@ -324,7 +324,7 @@
     public void updateEmptyView_dndSuppressing() {
         when(mEmptyShadeView.willBeGone()).thenReturn(true);
 
-        mStackScroller.updateEmptyShadeView(true, true);
+        mStackScroller.updateEmptyShadeView(true, true, false);
 
         verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
     }
@@ -334,7 +334,7 @@
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
         when(mEmptyShadeView.willBeGone()).thenReturn(true);
 
-        mStackScroller.updateEmptyShadeView(true, false);
+        mStackScroller.updateEmptyShadeView(true, false, false);
 
         verify(mEmptyShadeView).setText(R.string.empty_shade_text);
     }
@@ -343,10 +343,10 @@
     public void updateEmptyView_noNotificationsToDndSuppressing() {
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
         when(mEmptyShadeView.willBeGone()).thenReturn(true);
-        mStackScroller.updateEmptyShadeView(true, false);
+        mStackScroller.updateEmptyShadeView(true, false, false);
         verify(mEmptyShadeView).setText(R.string.empty_shade_text);
 
-        mStackScroller.updateEmptyShadeView(true, true);
+        mStackScroller.updateEmptyShadeView(true, true, false);
         verify(mEmptyShadeView).setText(R.string.dnd_suppressing_shade_text);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
index d5bfe1f..c17c5b0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesCommandQueueCallbacksTest.java
@@ -136,7 +136,7 @@
                 StatusBarManager.DISABLE2_NOTIFICATION_SHADE, false);
 
         verify(mCentralSurfaces).updateQsExpansionEnabled();
-        verify(mShadeController).animateCollapsePanels();
+        verify(mShadeController).animateCollapseShade();
 
         // Trying to open it does nothing.
         mSbcqCallbacks.animateExpandNotificationsPanel();
@@ -154,7 +154,7 @@
         mSbcqCallbacks.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_NONE,
                 StatusBarManager.DISABLE2_NONE, false);
         verify(mCentralSurfaces).updateQsExpansionEnabled();
-        verify(mShadeController, never()).animateCollapsePanels();
+        verify(mShadeController, never()).animateCollapseShade();
 
         // Can now be opened.
         mSbcqCallbacks.animateExpandNotificationsPanel();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
index 013e727..521e518 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CentralSurfacesImplTest.java
@@ -106,6 +106,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.ScreenLifecycle;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
+import com.android.systemui.keyguard.ui.viewmodel.LightRevealScrimViewModel;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
 import com.android.systemui.plugins.PluginDependencyProvider;
@@ -212,6 +213,7 @@
     @Mock private NotificationPanelView mNotificationPanelView;
     @Mock private IStatusBarService mBarService;
     @Mock private IDreamManager mDreamManager;
+    @Mock private LightRevealScrimViewModel mLightRevealScrimViewModel;
     @Mock private ScrimController mScrimController;
     @Mock private DozeScrimController mDozeScrimController;
     @Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@@ -392,10 +394,21 @@
             return null;
         }).when(mNotificationShadeWindowController).batchApplyWindowLayoutParams(any());
 
-        mShadeController = spy(new ShadeControllerImpl(mCommandQueue,
-                mStatusBarStateController, mNotificationShadeWindowController,
-                mStatusBarKeyguardViewManager, mContext.getSystemService(WindowManager.class),
-                () -> Optional.of(mCentralSurfaces), () -> mAssistManager));
+        mShadeController = spy(new ShadeControllerImpl(
+                mCommandQueue,
+                mKeyguardStateController,
+                mStatusBarStateController,
+                mStatusBarKeyguardViewManager,
+                mStatusBarWindowController,
+                mNotificationShadeWindowController,
+                mContext.getSystemService(WindowManager.class),
+                () -> mAssistManager,
+                () -> mNotificationGutsManager
+        ));
+        mShadeController.setNotificationPanelViewController(mNotificationPanelViewController);
+        mShadeController.setNotificationShadeWindowViewController(
+                mNotificationShadeWindowViewController);
+        mShadeController.setNotificationPresenter(mNotificationPresenter);
 
         when(mOperatorNameViewControllerFactory.create(any()))
                 .thenReturn(mOperatorNameViewController);
@@ -486,12 +499,14 @@
                 mDeviceStateManager,
                 mWiredChargingRippleController,
                 mDreamManager,
-                mCameraLauncherLazy) {
+                mCameraLauncherLazy,
+                () -> mLightRevealScrimViewModel) {
             @Override
             protected ViewRootImpl getViewRootImpl() {
                 return mViewRootImpl;
             }
         };
+        mCentralSurfaces.initShadeVisibilityListener();
         when(mViewRootImpl.getOnBackInvokedDispatcher())
                 .thenReturn(mOnBackInvokedDispatcher);
         when(mKeyguardViewMediator.registerCentralSurfaces(
@@ -807,7 +822,7 @@
 
         when(mNotificationPanelViewController.canPanelBeCollapsed()).thenReturn(true);
         mOnBackInvokedCallback.getValue().onBackInvoked();
-        verify(mShadeController).animateCollapsePanels();
+        verify(mShadeController).animateCollapseShade();
     }
 
     @Test
@@ -1030,7 +1045,7 @@
     }
 
     @Test
-    public void collapseShade_callsAnimateCollapsePanels_whenExpanded() {
+    public void collapseShade_callsanimateCollapseShade_whenExpanded() {
         // GIVEN the shade is expanded
         mCentralSurfaces.onShadeExpansionFullyChanged(true);
         mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE);
@@ -1038,12 +1053,12 @@
         // WHEN collapseShade is called
         mCentralSurfaces.collapseShade();
 
-        // VERIFY that animateCollapsePanels is called
-        verify(mShadeController).animateCollapsePanels();
+        // VERIFY that animateCollapseShade is called
+        verify(mShadeController).animateCollapseShade();
     }
 
     @Test
-    public void collapseShade_doesNotCallAnimateCollapsePanels_whenCollapsed() {
+    public void collapseShade_doesNotCallanimateCollapseShade_whenCollapsed() {
         // GIVEN the shade is collapsed
         mCentralSurfaces.onShadeExpansionFullyChanged(false);
         mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE);
@@ -1051,12 +1066,12 @@
         // WHEN collapseShade is called
         mCentralSurfaces.collapseShade();
 
-        // VERIFY that animateCollapsePanels is NOT called
-        verify(mShadeController, never()).animateCollapsePanels();
+        // VERIFY that animateCollapseShade is NOT called
+        verify(mShadeController, never()).animateCollapseShade();
     }
 
     @Test
-    public void collapseShadeForBugReport_callsAnimateCollapsePanels_whenFlagDisabled() {
+    public void collapseShadeForBugReport_callsanimateCollapseShade_whenFlagDisabled() {
         // GIVEN the shade is expanded & flag enabled
         mCentralSurfaces.onShadeExpansionFullyChanged(true);
         mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE);
@@ -1065,12 +1080,12 @@
         // WHEN collapseShadeForBugreport is called
         mCentralSurfaces.collapseShadeForBugreport();
 
-        // VERIFY that animateCollapsePanels is called
-        verify(mShadeController).animateCollapsePanels();
+        // VERIFY that animateCollapseShade is called
+        verify(mShadeController).animateCollapseShade();
     }
 
     @Test
-    public void collapseShadeForBugReport_doesNotCallAnimateCollapsePanels_whenFlagEnabled() {
+    public void collapseShadeForBugReport_doesNotCallanimateCollapseShade_whenFlagEnabled() {
         // GIVEN the shade is expanded & flag enabled
         mCentralSurfaces.onShadeExpansionFullyChanged(true);
         mCentralSurfaces.setBarStateForTest(StatusBarState.SHADE);
@@ -1079,8 +1094,8 @@
         // WHEN collapseShadeForBugreport is called
         mCentralSurfaces.collapseShadeForBugreport();
 
-        // VERIFY that animateCollapsePanels is called
-        verify(mShadeController, never()).animateCollapsePanels();
+        // VERIFY that animateCollapseShade is called
+        verify(mShadeController, never()).animateCollapseShade();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index d3b5418..df7ee43 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -39,6 +39,7 @@
 
 import android.content.res.ColorStateList;
 import android.graphics.Color;
+import android.hardware.biometrics.BiometricSourceType;
 import android.os.Handler;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -398,6 +399,8 @@
 
     @Test
     public void testShow_delaysIfFaceAuthIsRunning() {
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
+                .thenReturn(true);
         when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
         mBouncer.show(true /* reset */);
 
@@ -410,9 +413,10 @@
     }
 
     @Test
-    public void testShow_doesNotDelaysIfFaceAuthIsLockedOut() {
+    public void testShow_doesNotDelaysIfFaceAuthIsNotAllowed() {
         when(mKeyguardStateController.isFaceAuthEnabled()).thenReturn(true);
-        when(mKeyguardUpdateMonitor.isFaceLockedOut()).thenReturn(true);
+        when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(BiometricSourceType.FACE))
+                .thenReturn(false);
         mBouncer.show(true /* reset */);
 
         verify(mHandler, never()).postDelayed(any(), anyLong());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
index e2843a1..14d239a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarViewControllerTest.kt
@@ -27,6 +27,8 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.shade.NotificationPanelViewController
+import com.android.systemui.shade.ShadeControllerImpl
+import com.android.systemui.shade.ShadeLogger
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.config.UnfoldTransitionConfig
@@ -41,6 +43,7 @@
 import org.mockito.Mock
 import org.mockito.Mockito.`when`
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
@@ -49,8 +52,6 @@
 @SmallTest
 class PhoneStatusBarViewControllerTest : SysuiTestCase() {
 
-    private val touchEventHandler = TestTouchEventHandler()
-
     @Mock
     private lateinit var notificationPanelViewController: NotificationPanelViewController
     @Mock
@@ -66,6 +67,12 @@
     @Mock
     private lateinit var userChipViewModel: StatusBarUserChipViewModel
     @Mock
+    private lateinit var centralSurfacesImpl: CentralSurfacesImpl
+    @Mock
+    private lateinit var shadeControllerImpl: ShadeControllerImpl
+    @Mock
+    private lateinit var shadeLogger: ShadeLogger
+    @Mock
     private lateinit var viewUtil: ViewUtil
 
     private lateinit var view: PhoneStatusBarView
@@ -88,18 +95,6 @@
     }
 
     @Test
-    fun constructor_setsTouchHandlerOnView() {
-        val interceptEvent = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 10f, 10f, 0)
-        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
-
-        view.onInterceptTouchEvent(interceptEvent)
-        view.onTouchEvent(event)
-
-        assertThat(touchEventHandler.lastInterceptEvent).isEqualTo(interceptEvent)
-        assertThat(touchEventHandler.lastEvent).isEqualTo(event)
-    }
-
-    @Test
     fun onViewAttachedAndDrawn_moveFromCenterAnimationEnabled_moveFromCenterAnimationInitialized() {
         val view = createViewMock()
         val argumentCaptor = ArgumentCaptor.forClass(OnPreDrawListener::class.java)
@@ -115,6 +110,66 @@
         verify(moveFromCenterAnimation).onViewsReady(any())
     }
 
+    @Test
+    fun handleTouchEventFromStatusBar_panelsNotEnabled_returnsFalseAndNoViewEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(false)
+        val returnVal = view.onTouchEvent(
+                        MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        assertThat(returnVal).isFalse()
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_viewNotEnabled_returnsTrueAndNoViewEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+        val returnVal = view.onTouchEvent(
+                MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0))
+        assertThat(returnVal).isTrue()
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_viewNotEnabledButIsMoveEvent_viewReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(false)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_MOVE, 0f, 0f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController).sendTouchEventToView(event)
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_panelAndViewEnabled_viewReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isViewEnabled).thenReturn(true)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 2f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController).sendTouchEventToView(event)
+    }
+
+    @Test
+    fun handleTouchEventFromStatusBar_topEdgeTouch_viewNeverReceivesEvent() {
+        `when`(centralSurfacesImpl.commandQueuePanelsEnabled).thenReturn(true)
+        `when`(centralSurfacesImpl.notificationPanelViewController)
+                .thenReturn(notificationPanelViewController)
+        `when`(notificationPanelViewController.isFullyCollapsed).thenReturn(true)
+        val event = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
+
+        view.onTouchEvent(event)
+
+        verify(notificationPanelViewController, never()).sendTouchEventToView(any())
+    }
+
     private fun createViewMock(): PhoneStatusBarView {
         val view = spy(view)
         val viewTreeObserver = mock(ViewTreeObserver::class.java)
@@ -128,9 +183,12 @@
             Optional.of(sysuiUnfoldComponent),
             Optional.of(progressProvider),
             userChipViewModel,
+            centralSurfacesImpl,
+            shadeControllerImpl,
+            shadeLogger,
             viewUtil,
             configurationController
-        ).create(view, touchEventHandler).also {
+        ).create(view).also {
             it.init()
         }
     }
@@ -140,17 +198,4 @@
         override var isHingeAngleEnabled: Boolean = false
         override val halfFoldedTimeoutMillis: Int = 0
     }
-
-    private class TestTouchEventHandler : PhoneStatusBarView.TouchEventHandler {
-        var lastEvent: MotionEvent? = null
-        var lastInterceptEvent: MotionEvent? = null
-
-        override fun onInterceptTouchEvent(event: MotionEvent?) {
-            lastInterceptEvent = event
-        }
-        override fun handleTouchEvent(event: MotionEvent?): Boolean {
-            lastEvent = event
-            return false
-        }
-    }
 }
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 de71e2c..e475905 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
@@ -1442,16 +1442,30 @@
 
     @Test
     public void testNotificationTransparency_followsTransitionToFullShade() {
+        mScrimController.setClipsQsScrim(true);
+
         mScrimController.transitionTo(SHADE_LOCKED);
         mScrimController.setRawPanelExpansionFraction(1.0f);
         finishAnimationsImmediately();
+
+        assertScrimTinted(Map.of(
+                mScrimInFront, false,
+                mScrimBehind, true,
+                mNotificationsScrim, false
+        ));
+
         float shadeLockedAlpha = mNotificationsScrim.getViewAlpha();
         mScrimController.transitionTo(ScrimState.KEYGUARD);
         mScrimController.setRawPanelExpansionFraction(1.0f);
         finishAnimationsImmediately();
         float keyguardAlpha = mNotificationsScrim.getViewAlpha();
 
-        mScrimController.setClipsQsScrim(true);
+        assertScrimTinted(Map.of(
+                mScrimInFront, true,
+                mScrimBehind, true,
+                mNotificationsScrim, true
+        ));
+
         float progress = 0.5f;
         float lsNotifProgress = 0.3f;
         mScrimController.setTransitionToFullShadeProgress(progress, lsNotifProgress);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index bf5186b..471f8d3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -222,31 +222,32 @@
     }
 
     @Test
-    public void onPanelExpansionChanged_neverHidesFullscreenBouncer() {
-        when(mPrimaryBouncer.isShowing()).thenReturn(true);
-        when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
-                KeyguardSecurityModel.SecurityMode.SimPuk);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
-
-        reset(mPrimaryBouncer);
-        when(mKeyguardSecurityModel.getSecurityMode(anyInt())).thenReturn(
-                KeyguardSecurityModel.SecurityMode.SimPin);
-        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
-    }
-
-    @Test
     public void onPanelExpansionChanged_neverShowsDuringHintAnimation() {
         when(mNotificationPanelView.isUnlockHintRunning()).thenReturn(true);
         mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
-        verify(mPrimaryBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_HIDDEN));
+        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
     }
 
     @Test
-    public void onPanelExpansionChanged_propagatesToBouncer() {
+    public void onPanelExpansionChanged_propagatesToBouncerOnlyIfShowing() {
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
+        verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
+
+        when(mPrimaryBouncer.isShowing()).thenReturn(true);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+                expansionEvent(/* fraction= */ 0.6f, /* expanded= */ false, /* tracking= */ true));
+        verify(mPrimaryBouncer).setExpansion(eq(0.6f));
+    }
+
+    @Test
+    public void onPanelExpansionChanged_duplicateEventsAreIgnored() {
+        when(mPrimaryBouncer.isShowing()).thenReturn(true);
         mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
         verify(mPrimaryBouncer).setExpansion(eq(0.5f));
+
+        reset(mPrimaryBouncer);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(EXPANSION_EVENT);
+        verify(mPrimaryBouncer, never()).setExpansion(eq(0.5f));
     }
 
     @Test
@@ -307,6 +308,17 @@
     }
 
     @Test
+    public void onPanelExpansionChanged_neverTranslatesBouncerWhenOccluded() {
+        when(mKeyguardStateController.isOccluded()).thenReturn(true);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+                expansionEvent(
+                        /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+                        /* expanded= */ true,
+                        /* tracking= */ false));
+        verify(mPrimaryBouncer, never()).setExpansion(anyFloat());
+    }
+
+    @Test
     public void onPanelExpansionChanged_neverTranslatesBouncerWhenShowBouncer() {
         // Since KeyguardBouncer.EXPANSION_VISIBLE = 0 panel expansion, if the unlock is dismissing
         // the bouncer, there may be an onPanelExpansionChanged(0) call to collapse the panel
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 ce54d78..cae414a 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
@@ -263,7 +263,7 @@
         while (!runnables.isEmpty()) runnables.remove(0).run();
 
         // Then
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mShadeController, atLeastOnce()).collapseShade();
 
         verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
                 eq(false) /* animate */, any(), any());
@@ -296,7 +296,7 @@
         verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
 
         // This is called regardless, and simply short circuits when there is nothing to do.
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mShadeController, atLeastOnce()).collapseShade();
 
         verify(mAssistManager).hideAssist();
 
@@ -329,7 +329,7 @@
         // Then
         verify(mBubblesManager).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry()));
 
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mShadeController, atLeastOnce()).collapseShade();
 
         verify(mAssistManager).hideAssist();
 
@@ -357,7 +357,7 @@
         // Then
         verify(mBubblesManager).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry());
 
-        verify(mShadeController, atLeastOnce()).collapsePanel();
+        verify(mShadeController, atLeastOnce()).collapseShade();
 
         verify(mAssistManager).hideAssist();
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
index b7a6c01..d35ce76 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/data/repository/AirplaneModeRepositoryImplTest.kt
@@ -22,7 +22,7 @@
 import android.provider.Settings.Global
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.util.settings.FakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
@@ -45,7 +45,7 @@
 
     private lateinit var underTest: AirplaneModeRepositoryImpl
 
-    @Mock private lateinit var logger: ConnectivityPipelineLogger
+    @Mock private lateinit var logger: TableLogBuffer
     private lateinit var bgHandler: Handler
     private lateinit var scope: CoroutineScope
     private lateinit var settings: FakeSettings
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
new file mode 100644
index 0000000..5a6bb30
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelImplTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pipeline.airplane.ui.viewmodel
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
+import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+class AirplaneModeViewModelImplTest : SysuiTestCase() {
+
+    private lateinit var underTest: AirplaneModeViewModelImpl
+
+    @Mock private lateinit var logger: ConnectivityPipelineLogger
+    private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var interactor: AirplaneModeInteractor
+    private lateinit var scope: CoroutineScope
+
+    @Before
+    fun setUp() {
+        MockitoAnnotations.initMocks(this)
+        airplaneModeRepository = FakeAirplaneModeRepository()
+        connectivityRepository = FakeConnectivityRepository()
+        interactor = AirplaneModeInteractor(airplaneModeRepository, connectivityRepository)
+        scope = CoroutineScope(IMMEDIATE)
+
+        underTest =
+            AirplaneModeViewModelImpl(
+                interactor,
+                logger,
+                scope,
+            )
+    }
+
+    @Test
+    fun isAirplaneModeIconVisible_notAirplaneMode_outputsFalse() =
+        runBlocking(IMMEDIATE) {
+            connectivityRepository.setForceHiddenIcons(setOf())
+            airplaneModeRepository.setIsAirplaneMode(false)
+
+            var latest: Boolean? = null
+            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isAirplaneModeIconVisible_forceHidden_outputsFalse() =
+        runBlocking(IMMEDIATE) {
+            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.AIRPLANE))
+            airplaneModeRepository.setIsAirplaneMode(true)
+
+            var latest: Boolean? = null
+            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isAirplaneModeIconVisible_isAirplaneModeAndNotForceHidden_outputsTrue() =
+        runBlocking(IMMEDIATE) {
+            connectivityRepository.setForceHiddenIcons(setOf())
+            airplaneModeRepository.setIsAirplaneMode(true)
+
+            var latest: Boolean? = null
+            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelTest.kt
deleted file mode 100644
index 76016a1..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/airplane/ui/viewmodel/AirplaneModeViewModelTest.kt
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.pipeline.airplane.ui.viewmodel
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
-import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
-import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
-import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
-import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import org.junit.Before
-import org.junit.Test
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@OptIn(ExperimentalCoroutinesApi::class)
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
-class AirplaneModeViewModelTest : SysuiTestCase() {
-
-    private lateinit var underTest: AirplaneModeViewModel
-
-    @Mock private lateinit var logger: ConnectivityPipelineLogger
-    private lateinit var airplaneModeRepository: FakeAirplaneModeRepository
-    private lateinit var connectivityRepository: FakeConnectivityRepository
-    private lateinit var interactor: AirplaneModeInteractor
-    private lateinit var scope: CoroutineScope
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        airplaneModeRepository = FakeAirplaneModeRepository()
-        connectivityRepository = FakeConnectivityRepository()
-        interactor = AirplaneModeInteractor(airplaneModeRepository, connectivityRepository)
-        scope = CoroutineScope(IMMEDIATE)
-
-        underTest =
-            AirplaneModeViewModel(
-                interactor,
-                logger,
-                scope,
-            )
-    }
-
-    @Test
-    fun isAirplaneModeIconVisible_notAirplaneMode_outputsFalse() =
-        runBlocking(IMMEDIATE) {
-            connectivityRepository.setForceHiddenIcons(setOf())
-            airplaneModeRepository.setIsAirplaneMode(false)
-
-            var latest: Boolean? = null
-            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun isAirplaneModeIconVisible_forceHidden_outputsFalse() =
-        runBlocking(IMMEDIATE) {
-            connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.AIRPLANE))
-            airplaneModeRepository.setIsAirplaneMode(true)
-
-            var latest: Boolean? = null
-            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isFalse()
-
-            job.cancel()
-        }
-
-    @Test
-    fun isAirplaneModeIconVisible_isAirplaneModeAndNotForceHidden_outputsTrue() =
-        runBlocking(IMMEDIATE) {
-            connectivityRepository.setForceHiddenIcons(setOf())
-            airplaneModeRepository.setIsAirplaneMode(true)
-
-            var latest: Boolean? = null
-            val job = underTest.isAirplaneModeIconVisible.onEach { latest = it }.launchIn(this)
-
-            assertThat(latest).isTrue()
-
-            job.cancel()
-        }
-}
-
-private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
index 3d29d2b..30fd308 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/model/WifiNetworkModelTest.kt
@@ -18,8 +18,10 @@
 
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.log.table.TableRowLogger
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MAX_VALID_LEVEL
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel.Active.Companion.MIN_VALID_LEVEL
+import com.google.common.truth.Truth.assertThat
 import org.junit.Test
 
 @SmallTest
@@ -48,6 +50,125 @@
         WifiNetworkModel.Active(NETWORK_ID, level = MAX_VALID_LEVEL + 1)
     }
 
+    // Non-exhaustive logDiffs test -- just want to make sure the logging logic isn't totally broken
+
+    @Test
+    fun logDiffs_inactiveToActive_logsAllActiveFields() {
+        val logger = TestLogger()
+        val activeNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 3,
+                ssid = "Test SSID"
+            )
+
+        activeNetwork.logDiffs(prevVal = WifiNetworkModel.Inactive, logger)
+
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
+        assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
+        assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
+        assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
+    }
+    @Test
+    fun logDiffs_activeToInactive_resetsAllActiveFields() {
+        val logger = TestLogger()
+        val activeNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 3,
+                ssid = "Test SSID"
+            )
+
+        WifiNetworkModel.Inactive.logDiffs(prevVal = activeNetwork, logger)
+
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_INACTIVE))
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
+        assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
+        assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
+        assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
+    }
+
+    @Test
+    fun logDiffs_carrierMergedToActive_logsAllActiveFields() {
+        val logger = TestLogger()
+        val activeNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 3,
+                ssid = "Test SSID"
+            )
+
+        activeNetwork.logDiffs(prevVal = WifiNetworkModel.CarrierMerged, logger)
+
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_ACTIVE))
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, "5"))
+        assertThat(logger.changes).contains(Pair(COL_VALIDATED, "true"))
+        assertThat(logger.changes).contains(Pair(COL_LEVEL, "3"))
+        assertThat(logger.changes).contains(Pair(COL_SSID, "Test SSID"))
+    }
+    @Test
+    fun logDiffs_activeToCarrierMerged_resetsAllActiveFields() {
+        val logger = TestLogger()
+        val activeNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 3,
+                ssid = "Test SSID"
+            )
+
+        WifiNetworkModel.CarrierMerged.logDiffs(prevVal = activeNetwork, logger)
+
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_TYPE, TYPE_CARRIER_MERGED))
+        assertThat(logger.changes).contains(Pair(COL_NETWORK_ID, NETWORK_ID_DEFAULT.toString()))
+        assertThat(logger.changes).contains(Pair(COL_VALIDATED, "false"))
+        assertThat(logger.changes).contains(Pair(COL_LEVEL, LEVEL_DEFAULT.toString()))
+        assertThat(logger.changes).contains(Pair(COL_SSID, "null"))
+    }
+
+    @Test
+    fun logDiffs_activeChangesLevel_onlyLevelLogged() {
+        val logger = TestLogger()
+        val prevActiveNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 3,
+                ssid = "Test SSID"
+            )
+        val newActiveNetwork =
+            WifiNetworkModel.Active(
+                networkId = 5,
+                isValidated = true,
+                level = 2,
+                ssid = "Test SSID"
+            )
+
+        newActiveNetwork.logDiffs(prevActiveNetwork, logger)
+
+        assertThat(logger.changes).isEqualTo(listOf(Pair(COL_LEVEL, "2")))
+    }
+
+    private class TestLogger : TableRowLogger {
+        val changes = mutableListOf<Pair<String, String>>()
+
+        override fun logChange(columnName: String, value: String?) {
+            changes.add(Pair(columnName, value.toString()))
+        }
+
+        override fun logChange(columnName: String, value: Int) {
+            changes.add(Pair(columnName, value.toString()))
+        }
+
+        override fun logChange(columnName: String, value: Boolean) {
+            changes.add(Pair(columnName, value.toString()))
+        }
+    }
+
     companion object {
         private const val NETWORK_ID = 2
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
index a64a4bd..800f3c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryImplTest.kt
@@ -29,6 +29,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.log.table.TableLogBuffer
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepositoryImpl.Companion.ACTIVITY_DEFAULT
@@ -69,6 +70,7 @@
 
     @Mock private lateinit var broadcastDispatcher: BroadcastDispatcher
     @Mock private lateinit var logger: ConnectivityPipelineLogger
+    @Mock private lateinit var tableLogger: TableLogBuffer
     @Mock private lateinit var connectivityManager: ConnectivityManager
     @Mock private lateinit var wifiManager: WifiManager
     private lateinit var executor: Executor
@@ -804,6 +806,7 @@
             broadcastDispatcher,
             connectivityManager,
             logger,
+            tableLogger,
             executor,
             scope,
             wifiManagerToUse,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
new file mode 100644
index 0000000..b38497a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorImplTest.kt
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pipeline.wifi.domain.interactor
+
+import android.net.wifi.WifiManager
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
+import org.junit.Before
+import org.junit.Test
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SmallTest
+class WifiInteractorImplTest : SysuiTestCase() {
+
+    private lateinit var underTest: WifiInteractor
+
+    private lateinit var connectivityRepository: FakeConnectivityRepository
+    private lateinit var wifiRepository: FakeWifiRepository
+
+    @Before
+    fun setUp() {
+        connectivityRepository = FakeConnectivityRepository()
+        wifiRepository = FakeWifiRepository()
+        underTest = WifiInteractorImpl(connectivityRepository, wifiRepository)
+    }
+
+    @Test
+    fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
+
+        var latest: String? = "default"
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
+
+        var latest: String? = "default"
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            isOnlineSignUpForPasspointAccessPoint = true,
+            passpointProviderFriendlyName = "friendly",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("friendly")
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = WifiManager.UNKNOWN_SSID,
+        ))
+
+        var latest: String? = "default"
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isNull()
+
+        job.cancel()
+    }
+
+    @Test
+    fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
+        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
+            networkId = 1,
+            ssid = "MyAwesomeWifiNetwork",
+        ))
+
+        var latest: String? = null
+        val job = underTest
+            .ssid
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo("MyAwesomeWifiNetwork")
+
+        job.cancel()
+    }
+
+    @Test
+    fun isEnabled_matchesRepoIsEnabled() = runBlocking(IMMEDIATE) {
+        var latest: Boolean? = null
+        val job = underTest
+            .isEnabled
+            .onEach { latest = it }
+            .launchIn(this)
+
+        wifiRepository.setIsWifiEnabled(true)
+        yield()
+        assertThat(latest).isTrue()
+
+        wifiRepository.setIsWifiEnabled(false)
+        yield()
+        assertThat(latest).isFalse()
+
+        wifiRepository.setIsWifiEnabled(true)
+        yield()
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun isDefault_matchesRepoIsDefault() = runBlocking(IMMEDIATE) {
+        var latest: Boolean? = null
+        val job = underTest
+            .isDefault
+            .onEach { latest = it }
+            .launchIn(this)
+
+        wifiRepository.setIsWifiDefault(true)
+        yield()
+        assertThat(latest).isTrue()
+
+        wifiRepository.setIsWifiDefault(false)
+        yield()
+        assertThat(latest).isFalse()
+
+        wifiRepository.setIsWifiDefault(true)
+        yield()
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun wifiNetwork_matchesRepoWifiNetwork() = runBlocking(IMMEDIATE) {
+        val wifiNetwork = WifiNetworkModel.Active(
+            networkId = 45,
+            isValidated = true,
+            level = 3,
+            ssid = "AB",
+            passpointProviderFriendlyName = "friendly"
+        )
+        wifiRepository.setWifiNetwork(wifiNetwork)
+
+        var latest: WifiNetworkModel? = null
+        val job = underTest
+            .wifiNetwork
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isEqualTo(wifiNetwork)
+
+        job.cancel()
+    }
+
+    @Test
+    fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) {
+        var latest: WifiActivityModel? = null
+        val job = underTest
+            .activity
+            .onEach { latest = it }
+            .launchIn(this)
+
+        val activity1 = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
+        wifiRepository.setWifiActivity(activity1)
+        yield()
+        assertThat(latest).isEqualTo(activity1)
+
+        val activity2 = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity2)
+        yield()
+        assertThat(latest).isEqualTo(activity2)
+
+        val activity3 = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
+        wifiRepository.setWifiActivity(activity3)
+        yield()
+        assertThat(latest).isEqualTo(activity3)
+
+        job.cancel()
+    }
+
+    @Test
+    fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+
+        var latest: Boolean? = null
+        val job = underTest
+            .isForceHidden
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isTrue()
+
+        job.cancel()
+    }
+
+    @Test
+    fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) {
+        connectivityRepository.setForceHiddenIcons(setOf())
+
+        var latest: Boolean? = null
+        val job = underTest
+            .isForceHidden
+            .onEach { latest = it }
+            .launchIn(this)
+
+        assertThat(latest).isFalse()
+
+        job.cancel()
+    }
+}
+
+private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
deleted file mode 100644
index 71b8bab..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/domain/interactor/WifiInteractorTest.kt
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.pipeline.wifi.domain.interactor
-
-import android.net.wifi.WifiManager
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
-import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
-import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
-import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
-import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.yield
-import org.junit.Before
-import org.junit.Test
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-class WifiInteractorTest : SysuiTestCase() {
-
-    private lateinit var underTest: WifiInteractor
-
-    private lateinit var connectivityRepository: FakeConnectivityRepository
-    private lateinit var wifiRepository: FakeWifiRepository
-
-    @Before
-    fun setUp() {
-        connectivityRepository = FakeConnectivityRepository()
-        wifiRepository = FakeWifiRepository()
-        underTest = WifiInteractor(connectivityRepository, wifiRepository)
-    }
-
-    @Test
-    fun ssid_inactiveNetwork_outputsNull() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Inactive)
-
-        var latest: String? = "default"
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun ssid_carrierMergedNetwork_outputsNull() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged)
-
-        var latest: String? = "default"
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun ssid_isPasspointAccessPoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
-            networkId = 1,
-            isPasspointAccessPoint = true,
-            passpointProviderFriendlyName = "friendly",
-        ))
-
-        var latest: String? = null
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isEqualTo("friendly")
-
-        job.cancel()
-    }
-
-    @Test
-    fun ssid_isOnlineSignUpForPasspoint_outputsPasspointName() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
-            networkId = 1,
-            isOnlineSignUpForPasspointAccessPoint = true,
-            passpointProviderFriendlyName = "friendly",
-        ))
-
-        var latest: String? = null
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isEqualTo("friendly")
-
-        job.cancel()
-    }
-
-    @Test
-    fun ssid_unknownSsid_outputsNull() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
-            networkId = 1,
-            ssid = WifiManager.UNKNOWN_SSID,
-        ))
-
-        var latest: String? = "default"
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isNull()
-
-        job.cancel()
-    }
-
-    @Test
-    fun ssid_validSsid_outputsSsid() = runBlocking(IMMEDIATE) {
-        wifiRepository.setWifiNetwork(WifiNetworkModel.Active(
-            networkId = 1,
-            ssid = "MyAwesomeWifiNetwork",
-        ))
-
-        var latest: String? = null
-        val job = underTest
-            .ssid
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isEqualTo("MyAwesomeWifiNetwork")
-
-        job.cancel()
-    }
-
-    @Test
-    fun isEnabled_matchesRepoIsEnabled() = runBlocking(IMMEDIATE) {
-        var latest: Boolean? = null
-        val job = underTest
-            .isEnabled
-            .onEach { latest = it }
-            .launchIn(this)
-
-        wifiRepository.setIsWifiEnabled(true)
-        yield()
-        assertThat(latest).isTrue()
-
-        wifiRepository.setIsWifiEnabled(false)
-        yield()
-        assertThat(latest).isFalse()
-
-        wifiRepository.setIsWifiEnabled(true)
-        yield()
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun isDefault_matchesRepoIsDefault() = runBlocking(IMMEDIATE) {
-        var latest: Boolean? = null
-        val job = underTest
-            .isDefault
-            .onEach { latest = it }
-            .launchIn(this)
-
-        wifiRepository.setIsWifiDefault(true)
-        yield()
-        assertThat(latest).isTrue()
-
-        wifiRepository.setIsWifiDefault(false)
-        yield()
-        assertThat(latest).isFalse()
-
-        wifiRepository.setIsWifiDefault(true)
-        yield()
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun wifiNetwork_matchesRepoWifiNetwork() = runBlocking(IMMEDIATE) {
-        val wifiNetwork = WifiNetworkModel.Active(
-            networkId = 45,
-            isValidated = true,
-            level = 3,
-            ssid = "AB",
-            passpointProviderFriendlyName = "friendly"
-        )
-        wifiRepository.setWifiNetwork(wifiNetwork)
-
-        var latest: WifiNetworkModel? = null
-        val job = underTest
-            .wifiNetwork
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isEqualTo(wifiNetwork)
-
-        job.cancel()
-    }
-
-    @Test
-    fun activity_matchesRepoWifiActivity() = runBlocking(IMMEDIATE) {
-        var latest: WifiActivityModel? = null
-        val job = underTest
-            .activity
-            .onEach { latest = it }
-            .launchIn(this)
-
-        val activity1 = WifiActivityModel(hasActivityIn = true, hasActivityOut = true)
-        wifiRepository.setWifiActivity(activity1)
-        yield()
-        assertThat(latest).isEqualTo(activity1)
-
-        val activity2 = WifiActivityModel(hasActivityIn = false, hasActivityOut = false)
-        wifiRepository.setWifiActivity(activity2)
-        yield()
-        assertThat(latest).isEqualTo(activity2)
-
-        val activity3 = WifiActivityModel(hasActivityIn = true, hasActivityOut = false)
-        wifiRepository.setWifiActivity(activity3)
-        yield()
-        assertThat(latest).isEqualTo(activity3)
-
-        job.cancel()
-    }
-
-    @Test
-    fun isForceHidden_repoHasWifiHidden_outputsTrue() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
-
-        var latest: Boolean? = null
-        val job = underTest
-            .isForceHidden
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isTrue()
-
-        job.cancel()
-    }
-
-    @Test
-    fun isForceHidden_repoDoesNotHaveWifiHidden_outputsFalse() = runBlocking(IMMEDIATE) {
-        connectivityRepository.setForceHiddenIcons(setOf())
-
-        var latest: Boolean? = null
-        val job = underTest
-            .isForceHidden
-            .onEach { latest = it }
-            .launchIn(this)
-
-        assertThat(latest).isFalse()
-
-        job.cancel()
-    }
-}
-
-private val IMMEDIATE = Dispatchers.Main.immediate
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
index 37457b3..5c16e129 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/view/ModernStatusBarWifiViewTest.kt
@@ -32,12 +32,14 @@
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
+import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel
@@ -86,9 +88,9 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
         scope = CoroutineScope(Dispatchers.Unconfined)
-        airplaneModeViewModel = AirplaneModeViewModel(
+        airplaneModeViewModel = AirplaneModeViewModelImpl(
             AirplaneModeInteractor(
                 airplaneModeRepository,
                 connectivityRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
index a1afcd7..3001b81 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelIconParameterizedTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
+import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
@@ -37,6 +38,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
 import com.google.common.truth.Truth.assertThat
@@ -81,10 +83,10 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
         scope = CoroutineScope(IMMEDIATE)
         airplaneModeViewModel =
-            AirplaneModeViewModel(
+            AirplaneModeViewModelImpl(
                 AirplaneModeInteractor(
                     airplaneModeRepository,
                     connectivityRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 7d2c560..6a6b2a8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository
 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor
 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel
+import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
 import com.android.systemui.statusbar.pipeline.shared.ConnectivityPipelineLogger
 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
@@ -30,6 +31,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.model.WifiNetworkModel
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
+import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiActivityModel
 import com.google.common.truth.Truth.assertThat
@@ -73,9 +75,9 @@
         connectivityRepository = FakeConnectivityRepository()
         wifiRepository = FakeWifiRepository()
         wifiRepository.setIsWifiEnabled(true)
-        interactor = WifiInteractor(connectivityRepository, wifiRepository)
+        interactor = WifiInteractorImpl(connectivityRepository, wifiRepository)
         scope = CoroutineScope(IMMEDIATE)
-        airplaneModeViewModel = AirplaneModeViewModel(
+        airplaneModeViewModel = AirplaneModeViewModelImpl(
             AirplaneModeInteractor(
                 airplaneModeRepository,
                 connectivityRepository,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
index 5509a6ca..03fd624 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProviderTest.kt
@@ -124,8 +124,11 @@
             { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE) },
             { foldStateProvider.sendHingeAngleUpdate(10f) },
             { foldStateProvider.sendHingeAngleUpdate(90f) },
-            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) },
-            { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING) },
+            {
+                foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN)
+                // Start closing immediately after we opened, before the animation ended
+                foldStateProvider.sendFoldUpdate(FOLD_UPDATE_START_CLOSING)
+            },
             { foldStateProvider.sendHingeAngleUpdate(60f) },
             { foldStateProvider.sendHingeAngleUpdate(10f) },
             { foldStateProvider.sendFoldUpdate(FOLD_UPDATE_FINISH_CLOSED) },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
index 2e527be1..034c618 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/UserRepositoryImplTest.kt
@@ -95,6 +95,24 @@
     }
 
     @Test
+    fun userSwitcherSettings_isUserSwitcherEnabled_notInitialized() = runSelfCancelingTest {
+        underTest = create(this)
+
+        var value: UserSwitcherSettingsModel? = null
+        underTest.userSwitcherSettings.onEach { value = it }.launchIn(this)
+
+        assertUserSwitcherSettings(
+            model = value,
+            expectedSimpleUserSwitcher = false,
+            expectedAddUsersFromLockscreen = false,
+            expectedUserSwitcherEnabled =
+                context.resources.getBoolean(
+                    com.android.internal.R.bool.config_showUserSwitcherByDefault
+                ),
+        )
+    }
+
+    @Test
     fun refreshUsers() = runSelfCancelingTest {
         underTest = create(this)
         val initialExpectedValue =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
index 50d239d..5beb2b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/domain/interactor/UserInteractorTest.kt
@@ -761,7 +761,7 @@
         }
 
     @Test
-    fun `users - secondary user - no guest user`() =
+    fun `users - secondary user - guest user can be switched to`() =
         runBlocking(IMMEDIATE) {
             val userInfos = createUserInfos(count = 3, includeGuest = true)
             userRepository.setUserInfos(userInfos)
@@ -770,8 +770,8 @@
 
             var res: List<UserModel>? = null
             val job = underTest.users.onEach { res = it }.launchIn(this)
-            assertThat(res?.size == 2).isTrue()
-            assertThat(res?.find { it.isGuest }).isNull()
+            assertThat(res?.size == 3).isTrue()
+            assertThat(res?.find { it.isGuest }).isNotNull()
             job.cancel()
         }
 
@@ -813,7 +813,8 @@
             val job = underTest.dialogShowRequests.onEach { dialogRequest = it }.launchIn(this)
 
             // Dialog is shown.
-            assertThat(dialogRequest).isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog)
+            assertThat(dialogRequest)
+                .isEqualTo(ShowDialogRequestModel.ShowUserSwitcherDialog(expandable))
 
             underTest.onDialogShown()
             assertThat(dialogRequest).isNull()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
index 4b6bdac..784a26b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/user/ui/viewmodel/UserSwitcherViewModelTest.kt
@@ -47,18 +47,14 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.SupervisorJob
-import kotlinx.coroutines.cancelAndJoin
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.TestDispatcher
-import kotlinx.coroutines.test.TestResult
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -89,7 +85,6 @@
 
     private lateinit var testDispatcher: TestDispatcher
     private lateinit var testScope: TestScope
-    private lateinit var injectedScope: CoroutineScope
 
     @Before
     fun setUp() {
@@ -104,7 +99,6 @@
 
         testDispatcher = UnconfinedTestDispatcher()
         testScope = TestScope(testDispatcher)
-        injectedScope = CoroutineScope(testScope.coroutineContext + SupervisorJob())
         userRepository = FakeUserRepository()
         runBlocking {
             userRepository.setSettings(
@@ -118,14 +112,14 @@
         powerRepository = FakePowerRepository()
         val refreshUsersScheduler =
             RefreshUsersScheduler(
-                applicationScope = injectedScope,
+                applicationScope = testScope.backgroundScope,
                 mainDispatcher = testDispatcher,
                 repository = userRepository,
             )
         val guestUserInteractor =
             GuestUserInteractor(
                 applicationContext = context,
-                applicationScope = injectedScope,
+                applicationScope = testScope.backgroundScope,
                 mainDispatcher = testDispatcher,
                 backgroundDispatcher = testDispatcher,
                 manager = manager,
@@ -154,7 +148,7 @@
                                     set(Flags.FULL_SCREEN_USER_SWITCHER, false)
                                 },
                             manager = manager,
-                            applicationScope = injectedScope,
+                            applicationScope = testScope.backgroundScope,
                             telephonyInteractor =
                                 TelephonyInteractor(
                                     repository = FakeTelephonyRepository(),
@@ -175,7 +169,7 @@
     }
 
     @Test
-    fun users() = selfCancelingTest {
+    fun users() = testScope.runTest {
         val userInfos =
             listOf(
                 UserInfo(
@@ -210,26 +204,26 @@
         assertUserViewModel(
             viewModel = userViewModels.last()[0],
             viewKey = 0,
-            name = "zero",
+            name = Text.Loaded("zero"),
             isSelectionMarkerVisible = true,
         )
         assertUserViewModel(
             viewModel = userViewModels.last()[1],
             viewKey = 1,
-            name = "one",
+            name = Text.Loaded("one"),
             isSelectionMarkerVisible = false,
         )
         assertUserViewModel(
             viewModel = userViewModels.last()[2],
             viewKey = 2,
-            name = "two",
+            name = Text.Loaded("two"),
             isSelectionMarkerVisible = false,
         )
         job.cancel()
     }
 
     @Test
-    fun `maximumUserColumns - few users`() = selfCancelingTest {
+    fun `maximumUserColumns - few users`() = testScope.runTest {
         setUsers(count = 2)
         val values = mutableListOf<Int>()
         val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -240,7 +234,7 @@
     }
 
     @Test
-    fun `maximumUserColumns - many users`() = selfCancelingTest {
+    fun `maximumUserColumns - many users`() = testScope.runTest {
         setUsers(count = 5)
         val values = mutableListOf<Int>()
         val job = launch(testDispatcher) { underTest.maximumUserColumns.toList(values) }
@@ -250,7 +244,7 @@
     }
 
     @Test
-    fun `isOpenMenuButtonVisible - has actions - true`() = selfCancelingTest {
+    fun `isOpenMenuButtonVisible - has actions - true`() = testScope.runTest {
         setUsers(2)
 
         val isVisible = mutableListOf<Boolean>()
@@ -261,7 +255,7 @@
     }
 
     @Test
-    fun `isOpenMenuButtonVisible - no actions - false`() = selfCancelingTest {
+    fun `isOpenMenuButtonVisible - no actions - false`() = testScope.runTest {
         val userInfos = setUsers(2)
         userRepository.setSelectedUserInfo(userInfos[1])
         keyguardRepository.setKeyguardShowing(true)
@@ -275,7 +269,7 @@
     }
 
     @Test
-    fun menu() = selfCancelingTest {
+    fun menu() = testScope.runTest {
         val isMenuVisible = mutableListOf<Boolean>()
         val job = launch(testDispatcher) { underTest.isMenuVisible.toList(isMenuVisible) }
         assertThat(isMenuVisible.last()).isFalse()
@@ -290,7 +284,7 @@
     }
 
     @Test
-    fun `menu actions`() = selfCancelingTest {
+    fun `menu actions`() = testScope.runTest {
         setUsers(2)
         val actions = mutableListOf<List<UserActionViewModel>>()
         val job = launch(testDispatcher) { underTest.menu.toList(actions) }
@@ -309,7 +303,7 @@
     }
 
     @Test
-    fun `isFinishRequested - finishes when user is switched`() = selfCancelingTest {
+    fun `isFinishRequested - finishes when user is switched`() = testScope.runTest {
         val userInfos = setUsers(count = 2)
         val isFinishRequested = mutableListOf<Boolean>()
         val job = launch(testDispatcher) { underTest.isFinishRequested.toList(isFinishRequested) }
@@ -323,7 +317,7 @@
     }
 
     @Test
-    fun `isFinishRequested - finishes when the screen turns off`() = selfCancelingTest {
+    fun `isFinishRequested - finishes when the screen turns off`() = testScope.runTest {
         setUsers(count = 2)
         powerRepository.setInteractive(true)
         val isFinishRequested = mutableListOf<Boolean>()
@@ -338,7 +332,7 @@
     }
 
     @Test
-    fun `isFinishRequested - finishes when cancel button is clicked`() = selfCancelingTest {
+    fun `isFinishRequested - finishes when cancel button is clicked`() = testScope.runTest {
         setUsers(count = 2)
         powerRepository.setInteractive(true)
         val isFinishRequested = mutableListOf<Boolean>()
@@ -356,6 +350,93 @@
         job.cancel()
     }
 
+    @Test
+    fun `guest selected -- name is exit guest`() = testScope.runTest {
+        val userInfos =
+                listOf(
+                        UserInfo(
+                                /* id= */ 0,
+                                /* name= */ "zero",
+                                /* iconPath= */ "",
+                                /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+                                UserManager.USER_TYPE_FULL_SYSTEM,
+                        ),
+                        UserInfo(
+                                /* id= */ 1,
+                                /* name= */ "one",
+                                /* iconPath= */ "",
+                                /* flags= */ UserInfo.FLAG_FULL,
+                                UserManager.USER_TYPE_FULL_GUEST,
+                        ),
+                )
+
+        userRepository.setUserInfos(userInfos)
+        userRepository.setSelectedUserInfo(userInfos[1])
+
+        val userViewModels = mutableListOf<List<UserViewModel>>()
+        val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+        assertThat(userViewModels.last()).hasSize(2)
+        assertUserViewModel(
+                viewModel = userViewModels.last()[0],
+                viewKey = 0,
+                name = Text.Loaded("zero"),
+                isSelectionMarkerVisible = false,
+        )
+        assertUserViewModel(
+                viewModel = userViewModels.last()[1],
+                viewKey = 1,
+                name = Text.Resource(
+                    com.android.settingslib.R.string.guest_exit_quick_settings_button
+                ),
+                isSelectionMarkerVisible = true,
+        )
+        job.cancel()
+    }
+
+    @Test
+    fun `guest not selected -- name is guest`() = testScope.runTest {
+        val userInfos =
+                listOf(
+                        UserInfo(
+                                /* id= */ 0,
+                                /* name= */ "zero",
+                                /* iconPath= */ "",
+                                /* flags= */ UserInfo.FLAG_PRIMARY or UserInfo.FLAG_ADMIN or UserInfo.FLAG_FULL,
+                                UserManager.USER_TYPE_FULL_SYSTEM,
+                        ),
+                        UserInfo(
+                                /* id= */ 1,
+                                /* name= */ "one",
+                                /* iconPath= */ "",
+                                /* flags= */ UserInfo.FLAG_FULL,
+                                UserManager.USER_TYPE_FULL_GUEST,
+                        ),
+                )
+
+        userRepository.setUserInfos(userInfos)
+        userRepository.setSelectedUserInfo(userInfos[0])
+        runCurrent()
+
+        val userViewModels = mutableListOf<List<UserViewModel>>()
+        val job = launch(testDispatcher) { underTest.users.toList(userViewModels) }
+
+        assertThat(userViewModels.last()).hasSize(2)
+        assertUserViewModel(
+                viewModel = userViewModels.last()[0],
+                viewKey = 0,
+                name = Text.Loaded("zero"),
+                isSelectionMarkerVisible = true,
+        )
+        assertUserViewModel(
+                viewModel = userViewModels.last()[1],
+                viewKey = 1,
+                name = Text.Loaded("one"),
+                isSelectionMarkerVisible = false,
+        )
+        job.cancel()
+    }
+
     private suspend fun setUsers(count: Int): List<UserInfo> {
         val userInfos =
             (0 until count).map { index ->
@@ -384,26 +465,18 @@
     private fun assertUserViewModel(
         viewModel: UserViewModel?,
         viewKey: Int,
-        name: String,
+        name: Text,
         isSelectionMarkerVisible: Boolean,
     ) {
         checkNotNull(viewModel)
         assertThat(viewModel.viewKey).isEqualTo(viewKey)
-        assertThat(viewModel.name).isEqualTo(Text.Loaded(name))
+        assertThat(viewModel.name).isEqualTo(name)
         assertThat(viewModel.isSelectionMarkerVisible).isEqualTo(isSelectionMarkerVisible)
         assertThat(viewModel.alpha)
             .isEqualTo(LegacyUserUiHelper.USER_SWITCHER_USER_VIEW_SELECTABLE_ALPHA)
         assertThat(viewModel.onClicked).isNotNull()
     }
 
-    private fun selfCancelingTest(
-        block: suspend TestScope.() -> Unit,
-    ): TestResult =
-        testScope.runTest {
-            block()
-            injectedScope.coroutineContext[Job.Key]?.cancelAndJoin()
-        }
-
     companion object {
         private const val SUPERVISED_USER_CREATION_PACKAGE = "com.some.package"
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 7df7077..6bfc2f1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -51,15 +51,11 @@
             )
     }
 
-    @Test
-    fun notEnough() = runBlocking {
-        assertThatFlow(flowOf(1).pairwise()).emitsNothing()
-    }
+    @Test fun notEnough() = runBlocking { assertThatFlow(flowOf(1).pairwise()).emitsNothing() }
 
     @Test
     fun withInit() = runBlocking {
-        assertThatFlow(flowOf(2).pairwise(initialValue = 1))
-            .emitsExactly(WithPrev(1, 2))
+        assertThatFlow(flowOf(2).pairwise(initialValue = 1)).emitsExactly(WithPrev(1, 2))
     }
 
     @Test
@@ -68,25 +64,78 @@
     }
 
     @Test
-    fun withStateFlow() = runBlocking(Dispatchers.Main.immediate) {
-        val state = MutableStateFlow(1)
-        val stop = MutableSharedFlow<Unit>()
-
-        val stoppable = merge(state, stop)
-            .takeWhile { it is Int }
-            .filterIsInstance<Int>()
-
-        val job1 = launch {
-            assertThatFlow(stoppable.pairwise()).emitsExactly(WithPrev(1, 2))
-        }
-        state.value = 2
-        val job2 = launch { assertThatFlow(stoppable.pairwise()).emitsNothing() }
-
-        stop.emit(Unit)
-
-        assertThatJob(job1).isCompleted()
-        assertThatJob(job2).isCompleted()
+    fun withTransform() = runBlocking {
+        assertThatFlow(
+                flowOf("val1", "val2", "val3").pairwiseBy { prev: String, next: String ->
+                    "$prev|$next"
+                }
+            )
+            .emitsExactly("val1|val2", "val2|val3")
     }
+
+    @Test
+    fun withGetInit() = runBlocking {
+        var initRun = false
+        assertThatFlow(
+                flowOf("val1", "val2").pairwiseBy(
+                    getInitialValue = {
+                        initRun = true
+                        "initial"
+                    }
+                ) { prev: String, next: String -> "$prev|$next" }
+            )
+            .emitsExactly("initial|val1", "val1|val2")
+        assertThat(initRun).isTrue()
+    }
+
+    @Test
+    fun notEnoughWithGetInit() = runBlocking {
+        var initRun = false
+        assertThatFlow(
+                emptyFlow<String>().pairwiseBy(
+                    getInitialValue = {
+                        initRun = true
+                        "initial"
+                    }
+                ) { prev: String, next: String -> "$prev|$next" }
+            )
+            .emitsNothing()
+        // Even though the flow will not emit anything, the initial value function should still get
+        // run.
+        assertThat(initRun).isTrue()
+    }
+
+    @Test
+    fun getInitNotRunWhenFlowNotCollected() = runBlocking {
+        var initRun = false
+        flowOf("val1", "val2").pairwiseBy(
+            getInitialValue = {
+                initRun = true
+                "initial"
+            }
+        ) { prev: String, next: String -> "$prev|$next" }
+
+        // Since the flow isn't collected, ensure [initialValueFun] isn't run.
+        assertThat(initRun).isFalse()
+    }
+
+    @Test
+    fun withStateFlow() =
+        runBlocking(Dispatchers.Main.immediate) {
+            val state = MutableStateFlow(1)
+            val stop = MutableSharedFlow<Unit>()
+
+            val stoppable = merge(state, stop).takeWhile { it is Int }.filterIsInstance<Int>()
+
+            val job1 = launch { assertThatFlow(stoppable.pairwise()).emitsExactly(WithPrev(1, 2)) }
+            state.value = 2
+            val job2 = launch { assertThatFlow(stoppable.pairwise()).emitsNothing() }
+
+            stop.emit(Unit)
+
+            assertThatJob(job1).isCompleted()
+            assertThatJob(job2).isCompleted()
+        }
 }
 
 @SmallTest
@@ -94,18 +143,17 @@
 class SetChangesFlowTest : SysuiTestCase() {
     @Test
     fun simple() = runBlocking {
-        assertThatFlow(
-            flowOf(setOf(1, 2, 3), setOf(2, 3, 4)).setChanges()
-        ).emitsExactly(
-            SetChanges(
-                added = setOf(1, 2, 3),
-                removed = emptySet(),
-            ),
-            SetChanges(
-                added = setOf(4),
-                removed = setOf(1),
-            ),
-        )
+        assertThatFlow(flowOf(setOf(1, 2, 3), setOf(2, 3, 4)).setChanges())
+            .emitsExactly(
+                SetChanges(
+                    added = setOf(1, 2, 3),
+                    removed = emptySet(),
+                ),
+                SetChanges(
+                    added = setOf(4),
+                    removed = setOf(1),
+                ),
+            )
     }
 
     @Test
@@ -147,14 +195,19 @@
 class SampleFlowTest : SysuiTestCase() {
     @Test
     fun simple() = runBlocking {
-        assertThatFlow(flow { yield(); emit(1) }.sample(flowOf(2)) { a, b -> a to b })
+        assertThatFlow(
+                flow {
+                        yield()
+                        emit(1)
+                    }
+                    .sample(flowOf(2)) { a, b -> a to b }
+            )
             .emitsExactly(1 to 2)
     }
 
     @Test
     fun otherFlowNoValueYet() = runBlocking {
-        assertThatFlow(flowOf(1).sample(emptyFlow<Unit>()))
-            .emitsNothing()
+        assertThatFlow(flowOf(1).sample(emptyFlow<Unit>())).emitsNothing()
     }
 
     @Test
@@ -178,13 +231,14 @@
     }
 }
 
-private fun <T> assertThatFlow(flow: Flow<T>) = object {
-    suspend fun emitsExactly(vararg emissions: T) =
-        assertThat(flow.toList()).containsExactly(*emissions).inOrder()
-    suspend fun emitsNothing() =
-        assertThat(flow.toList()).isEmpty()
-}
+private fun <T> assertThatFlow(flow: Flow<T>) =
+    object {
+        suspend fun emitsExactly(vararg emissions: T) =
+            assertThat(flow.toList()).containsExactly(*emissions).inOrder()
+        suspend fun emitsNothing() = assertThat(flow.toList()).isEmpty()
+    }
 
-private fun assertThatJob(job: Job) = object {
-    fun isCompleted() = assertThat(job.isCompleted).isTrue()
-}
+private fun assertThatJob(job: Job) =
+    object {
+        fun isCompleted() = assertThat(job.isCompleted).isTrue()
+    }
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 3769f52..915ea1a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/volume/VolumeDialogControllerImplTest.java
@@ -170,6 +170,34 @@
     }
 
     @Test
+    public void testVolumeChangeW_deviceOutFromBLEHeadset_doStateChanged() {
+        mVolumeController.setDeviceInteractive(false);
+        when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+                WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+        when(mAudioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)).thenReturn(
+                AudioManager.DEVICE_OUT_BLE_HEADSET);
+
+        mVolumeController.onVolumeChangedW(
+                AudioManager.STREAM_VOICE_CALL, AudioManager.FLAG_SHOW_UI);
+
+        verify(mCallback, times(1)).onStateChanged(any());
+    }
+
+    @Test
+    public void testVolumeChangeW_deviceOutFromA2DP_doStateChanged() {
+        mVolumeController.setDeviceInteractive(false);
+        when(mWakefullnessLifcycle.getWakefulness()).thenReturn(
+                WakefulnessLifecycle.WAKEFULNESS_AWAKE);
+        when(mAudioManager.getDevicesForStream(AudioManager.STREAM_VOICE_CALL)).thenReturn(
+                AudioManager.DEVICE_OUT_BLUETOOTH_A2DP);
+
+        mVolumeController.onVolumeChangedW(
+                AudioManager.STREAM_VOICE_CALL, AudioManager.FLAG_SHOW_UI);
+
+        verify(mCallback, never()).onStateChanged(any());
+    }
+
+    @Test
     public void testOnRemoteVolumeChanged_newStream_noNullPointer() {
         MediaSession.Token token = new MediaSession.Token(Process.myUid(), null);
         mVolumeController.mMediaSessionsCallbacksW.onRemoteVolumeChanged(token, 0);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index db3b9b5..d31f0bb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -1423,13 +1423,43 @@
         assertStackCollapsed();
         // Post status bar state change update with the same value
         mBubbleController.onStatusBarStateChanged(false);
-        // Stack should remain collapsedb
+        // Stack should remain collapsed
         assertStackCollapsed();
         // Post status bar state change which should trigger bubble to expand
         mBubbleController.onStatusBarStateChanged(true);
         assertStackExpanded();
     }
 
+    /**
+     * Test to verify behavior for the following scenario:
+     * <ol>
+     *     <li>device is locked with keyguard on, status bar shade state updates to
+     *     <code>false</code></li>
+     *     <li>notification entry is marked to be a bubble and it is set to auto-expand</li>
+     *     <li>device unlock starts, status bar shade state receives another update to
+     *     <code>false</code></li>
+     *     <li>device is unlocked and status bar shade state is set to <code>true</code></li>
+     *     <li>bubble should be expanded</li>
+     * </ol>
+     */
+    @Test
+    public void testOnStatusBarStateChanged_newAutoExpandedBubbleRemainsExpanded() {
+        // Set device as locked
+        mBubbleController.onStatusBarStateChanged(false);
+
+        // Create a auto-expanded bubble
+        NotificationEntry entry = mNotificationTestHelper.createAutoExpandedBubble();
+        mEntryListener.onEntryAdded(entry);
+
+        // When unlocking, we may receive duplicate updates with shade=false, ensure they don't
+        // clear the expanded state
+        mBubbleController.onStatusBarStateChanged(false);
+        mBubbleController.onStatusBarStateChanged(true);
+
+        // After unlocking, stack should be expanded
+        assertStackExpanded();
+    }
+
     @Test
     public void testSetShouldAutoExpand_notifiesFlagChanged() {
         mBubbleController.updateBubble(mBubbleEntry);
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
index fa3cc99..bf2235a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/SysuiTestCase.java
@@ -136,6 +136,8 @@
                 InstrumentationRegistry.getArguments());
         if (TestableLooper.get(this) != null) {
             TestableLooper.get(this).processAllMessages();
+            // Must remove static reference to this test object to prevent leak (b/261039202)
+            TestableLooper.remove(this);
         }
         disallowTestableLooperAsMainThread();
         mContext.cleanUpReceivers(this.getClass().getSimpleName());
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt
new file mode 100644
index 0000000..8176dd0
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/biometrics/udfps/FakeOverlapDetector.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.biometrics.udfps
+
+import android.graphics.Rect
+
+class FakeOverlapDetector : OverlapDetector {
+    var shouldReturn: Boolean = false
+
+    override fun isGoodOverlap(touchData: NormalizedTouchData, nativeSensorBounds: Rect): Boolean {
+        return shouldReturn
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
index 52e0c982..ad086ff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/broadcast/FakeBroadcastDispatcher.kt
@@ -22,12 +22,12 @@
 import android.os.Handler
 import android.os.Looper
 import android.os.UserHandle
-import android.util.ArraySet
 import android.util.Log
 import com.android.systemui.SysuiTestableContext
 import com.android.systemui.broadcast.logging.BroadcastDispatcherLogger
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.settings.UserTracker
+import java.util.concurrent.ConcurrentHashMap
 import java.util.concurrent.Executor
 
 class FakeBroadcastDispatcher(
@@ -50,7 +50,7 @@
         PendingRemovalStore(logger)
     ) {
 
-    val registeredReceivers = ArraySet<BroadcastReceiver>()
+    val registeredReceivers: MutableSet<BroadcastReceiver> = ConcurrentHashMap.newKeySet()
 
     override fun registerReceiverWithHandler(
         receiver: BroadcastReceiver,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt
new file mode 100644
index 0000000..b7a8d2e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/coroutines/Flow.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.coroutines
+
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+import kotlinx.coroutines.CoroutineStart
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+
+/** Collect [flow] in a new [Job] and return a getter for the last collected value. */
+fun <T> TestScope.collectLastValue(
+    flow: Flow<T>,
+    context: CoroutineContext = EmptyCoroutineContext,
+    start: CoroutineStart = CoroutineStart.DEFAULT,
+): () -> T? {
+    var lastValue: T? = null
+    backgroundScope.launch(context, start) { flow.collect { lastValue = it } }
+    return {
+        runCurrent()
+        lastValue
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceProviderClientFactory.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceProviderClientFactory.kt
new file mode 100644
index 0000000..d85dd2e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/quickaffordance/FakeKeyguardQuickAffordanceProviderClientFactory.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.quickaffordance
+
+import com.android.systemui.settings.UserTracker
+import com.android.systemui.shared.quickaffordance.data.content.FakeKeyguardQuickAffordanceProviderClient
+import com.android.systemui.shared.quickaffordance.data.content.KeyguardQuickAffordanceProviderClient
+
+class FakeKeyguardQuickAffordanceProviderClientFactory(
+    private val userTracker: UserTracker,
+    private val callback: (Int) -> KeyguardQuickAffordanceProviderClient = {
+        FakeKeyguardQuickAffordanceProviderClient()
+    },
+) : KeyguardQuickAffordanceProviderClientFactory {
+
+    override fun create(): KeyguardQuickAffordanceProviderClient {
+        return callback(userTracker.userId)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 3601667..5c2a915 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -17,11 +17,15 @@
 
 package com.android.systemui.keyguard.data.repository
 
+import android.graphics.Point
 import com.android.systemui.common.shared.model.Position
 import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
+import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
 import com.android.systemui.keyguard.shared.model.DozeTransitionModel
 import com.android.systemui.keyguard.shared.model.StatusBarState
+import com.android.systemui.keyguard.shared.model.WakeSleepReason
 import com.android.systemui.keyguard.shared.model.WakefulnessModel
+import com.android.systemui.keyguard.shared.model.WakefulnessState
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
@@ -49,7 +53,7 @@
     override val isDreaming: Flow<Boolean> = _isDreaming
 
     private val _dozeAmount = MutableStateFlow(0f)
-    override val dozeAmount: Flow<Float> = _dozeAmount
+    override val linearDozeAmount: Flow<Float> = _dozeAmount
 
     private val _statusBarState = MutableStateFlow(StatusBarState.SHADE)
     override val statusBarState: Flow<StatusBarState> = _statusBarState
@@ -57,8 +61,16 @@
     private val _dozeTransitionModel = MutableStateFlow(DozeTransitionModel())
     override val dozeTransitionModel: Flow<DozeTransitionModel> = _dozeTransitionModel
 
-    private val _wakefulnessState = MutableStateFlow(WakefulnessModel.ASLEEP)
-    override val wakefulnessState: Flow<WakefulnessModel> = _wakefulnessState
+    private val _wakefulnessModel =
+        MutableStateFlow(
+            WakefulnessModel(
+                WakefulnessState.ASLEEP,
+                false,
+                WakeSleepReason.OTHER,
+                WakeSleepReason.OTHER
+            )
+        )
+    override val wakefulness: Flow<WakefulnessModel> = _wakefulnessModel
 
     private val _isUdfpsSupported = MutableStateFlow(false)
 
@@ -71,6 +83,15 @@
     private val _biometricUnlockState = MutableStateFlow(BiometricUnlockModel.NONE)
     override val biometricUnlockState: Flow<BiometricUnlockModel> = _biometricUnlockState
 
+    private val _fingerprintSensorLocation = MutableStateFlow<Point?>(null)
+    override val fingerprintSensorLocation: Flow<Point?> = _fingerprintSensorLocation
+
+    private val _faceSensorLocation = MutableStateFlow<Point?>(null)
+    override val faceSensorLocation: Flow<Point?> = _faceSensorLocation
+
+    private val _biometricUnlockSource = MutableStateFlow<BiometricUnlockSource?>(null)
+    override val biometricUnlockSource: Flow<BiometricUnlockSource?> = _biometricUnlockSource
+
     override fun isKeyguardShowing(): Boolean {
         return _isKeyguardShowing.value
     }
@@ -99,6 +120,22 @@
         _dozeAmount.value = dozeAmount
     }
 
+    fun setBiometricUnlockState(state: BiometricUnlockModel) {
+        _biometricUnlockState.tryEmit(state)
+    }
+
+    fun setBiometricUnlockSource(source: BiometricUnlockSource?) {
+        _biometricUnlockSource.tryEmit(source)
+    }
+
+    fun setFaceSensorLocation(location: Point?) {
+        _faceSensorLocation.tryEmit(location)
+    }
+
+    fun setFingerprintSensorLocation(location: Point?) {
+        _fingerprintSensorLocation.tryEmit(location)
+    }
+
     override fun isUdfpsSupported(): Boolean {
         return _isUdfpsSupported.value
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
new file mode 100644
index 0000000..7c22604
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeLightRevealScrimRepository.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.keyguard.data.repository
+
+import com.android.systemui.statusbar.LightRevealEffect
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Fake implementation of [LightRevealScrimRepository] */
+class FakeLightRevealScrimRepository : LightRevealScrimRepository {
+
+    private val _revealEffect: MutableStateFlow<LightRevealEffect> =
+        MutableStateFlow(DEFAULT_REVEAL_EFFECT)
+    override val revealEffect = _revealEffect
+
+    fun setRevealEffect(effect: LightRevealEffect) {
+        _revealEffect.tryEmit(effect)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt
index c33ce5d..b31f119 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/FakeFgsManagerController.kt
@@ -43,6 +43,9 @@
 
     override val showFooterDot: MutableStateFlow<Boolean> = MutableStateFlow(showFooterDot)
 
+    override var includesUserVisibleJobs = false
+        private set
+
     private val numRunningPackagesListeners = LinkedHashSet<OnNumberOfPackagesChangedListener>()
     private val dialogDismissedListeners = LinkedHashSet<OnDialogDismissedListener>()
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
index 63448e2..1a893f8 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
@@ -56,7 +56,8 @@
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.util.settings.GlobalSettings
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.test.TestCoroutineDispatcher
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestCoroutineScheduler
 
 /**
  * Util class to create real implementations of the FooterActions repositories, viewModel and
@@ -65,6 +66,7 @@
 class FooterActionsTestUtils(
     private val context: Context,
     private val testableLooper: TestableLooper,
+    private val scheduler: TestCoroutineScheduler,
 ) {
     /** Enable or disable the user switcher in the settings. */
     fun setUserSwitcherEnabled(settings: GlobalSettings, enabled: Boolean, userId: Int) {
@@ -105,7 +107,7 @@
         foregroundServicesRepository: ForegroundServicesRepository = foregroundServicesRepository(),
         userSwitcherRepository: UserSwitcherRepository = userSwitcherRepository(),
         broadcastDispatcher: BroadcastDispatcher = mock(),
-        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
+        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
     ): FooterActionsInteractor {
         return FooterActionsInteractorImpl(
             activityStarter,
@@ -126,7 +128,7 @@
     /** Create a [SecurityRepository] to be used in tests. */
     fun securityRepository(
         securityController: SecurityController = FakeSecurityController(),
-        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
+        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
     ): SecurityRepository {
         return SecurityRepositoryImpl(
             securityController,
@@ -145,7 +147,7 @@
     fun userSwitcherRepository(
         @Application context: Context = this.context.applicationContext,
         bgHandler: Handler = Handler(testableLooper.looper),
-        bgDispatcher: CoroutineDispatcher = TestCoroutineDispatcher(),
+        bgDispatcher: CoroutineDispatcher = StandardTestDispatcher(scheduler),
         userManager: UserManager = mock(),
         userTracker: UserTracker = FakeUserTracker(),
         userSwitcherController: UserSwitcherController = mock(),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
index a7eadba..0dd1fc7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/settings/FakeUserTracker.kt
@@ -66,7 +66,8 @@
         _userId = _userInfo.id
         _userHandle = UserHandle.of(_userId)
 
-        callbacks.forEach { it.onUserChanged(_userId, userContext) }
+        val copy = callbacks.toList()
+        copy.forEach { it.onUserChanged(_userId, userContext) }
     }
 
     fun onProfileChanged() {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeFlashlightController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeFlashlightController.java
index f6fd2cb..f68baf5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeFlashlightController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/FakeFlashlightController.java
@@ -16,32 +16,71 @@
 
 import android.testing.LeakCheck;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.FlashlightController.FlashlightListener;
 
+import java.util.ArrayList;
+import java.util.List;
+
 public class FakeFlashlightController extends BaseLeakChecker<FlashlightListener>
         implements FlashlightController {
+
+    private final List<FlashlightListener> callbacks = new ArrayList<>();
+
+    @VisibleForTesting
+    public boolean isAvailable;
+    @VisibleForTesting
+    public boolean isEnabled;
+    @VisibleForTesting
+    public boolean hasFlashlight;
+
     public FakeFlashlightController(LeakCheck test) {
         super(test, "flashlight");
     }
 
+    @VisibleForTesting
+    public void onFlashlightAvailabilityChanged(boolean newValue) {
+        callbacks.forEach(
+                flashlightListener -> flashlightListener.onFlashlightAvailabilityChanged(newValue)
+        );
+    }
+
+    @VisibleForTesting
+    public void onFlashlightError() {
+        callbacks.forEach(FlashlightListener::onFlashlightError);
+    }
+
     @Override
     public boolean hasFlashlight() {
-        return false;
+        return hasFlashlight;
     }
 
     @Override
     public void setFlashlight(boolean newState) {
-
+        callbacks.forEach(flashlightListener -> flashlightListener.onFlashlightChanged(newState));
     }
 
     @Override
     public boolean isAvailable() {
-        return false;
+        return isAvailable;
     }
 
     @Override
     public boolean isEnabled() {
-        return false;
+        return isEnabled;
+    }
+
+    @Override
+    public void addCallback(FlashlightListener listener) {
+        super.addCallback(listener);
+        callbacks.add(listener);
+    }
+
+    @Override
+    public void removeCallback(FlashlightListener listener) {
+        super.removeCallback(listener);
+        callbacks.remove(listener);
     }
 }
diff --git a/packages/VpnDialogs/res/values-af/strings.xml b/packages/VpnDialogs/res/values-af/strings.xml
index b1aedf3..db3c355 100644
--- a/packages/VpnDialogs/res/values-af/strings.xml
+++ b/packages/VpnDialogs/res/values-af/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ontkoppel"</string>
     <string name="open_app" msgid="3717639178595958667">"Maak program oop"</string>
     <string name="dismiss" msgid="6192859333764711227">"Maak toe"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-am/strings.xml b/packages/VpnDialogs/res/values-am/strings.xml
index d1fcaa5..d86e043 100644
--- a/packages/VpnDialogs/res/values-am/strings.xml
+++ b/packages/VpnDialogs/res/values-am/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ግንኙነት አቋርጥ"</string>
     <string name="open_app" msgid="3717639178595958667">"መተግበሪያን ክፈት"</string>
     <string name="dismiss" msgid="6192859333764711227">"አሰናብት"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ar/strings.xml b/packages/VpnDialogs/res/values-ar/strings.xml
index 0e0581e..9307a74 100644
--- a/packages/VpnDialogs/res/values-ar/strings.xml
+++ b/packages/VpnDialogs/res/values-ar/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"قطع الاتصال"</string>
     <string name="open_app" msgid="3717639178595958667">"فتح التطبيق"</string>
     <string name="dismiss" msgid="6192859333764711227">"تجاهل"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-as/strings.xml b/packages/VpnDialogs/res/values-as/strings.xml
index dc99278..736bb83 100644
--- a/packages/VpnDialogs/res/values-as/strings.xml
+++ b/packages/VpnDialogs/res/values-as/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন কৰক"</string>
     <string name="open_app" msgid="3717639178595958667">"এপ্ খোলক"</string>
     <string name="dismiss" msgid="6192859333764711227">"অগ্ৰাহ্য কৰক"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-az/strings.xml b/packages/VpnDialogs/res/values-az/strings.xml
index ca0066f..9b69e3e5 100644
--- a/packages/VpnDialogs/res/values-az/strings.xml
+++ b/packages/VpnDialogs/res/values-az/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Əlaqəni kəs"</string>
     <string name="open_app" msgid="3717639178595958667">"Tətbiqi açın"</string>
     <string name="dismiss" msgid="6192859333764711227">"İmtina edin"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
index 9f0b486..3270744 100644
--- a/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
+++ b/packages/VpnDialogs/res/values-b+sr+Latn/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-be/strings.xml b/packages/VpnDialogs/res/values-be/strings.xml
index 3621798..54908f6 100644
--- a/packages/VpnDialogs/res/values-be/strings.xml
+++ b/packages/VpnDialogs/res/values-be/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Адключыцца"</string>
     <string name="open_app" msgid="3717639178595958667">"Адкрыць праграму"</string>
     <string name="dismiss" msgid="6192859333764711227">"Адхіліць"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bg/strings.xml b/packages/VpnDialogs/res/values-bg/strings.xml
index df487ee..734888f 100644
--- a/packages/VpnDialogs/res/values-bg/strings.xml
+++ b/packages/VpnDialogs/res/values-bg/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Изключване"</string>
     <string name="open_app" msgid="3717639178595958667">"Към приложението"</string>
     <string name="dismiss" msgid="6192859333764711227">"Отхвърляне"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bn/strings.xml b/packages/VpnDialogs/res/values-bn/strings.xml
index 52145d8..f176b244 100644
--- a/packages/VpnDialogs/res/values-bn/strings.xml
+++ b/packages/VpnDialogs/res/values-bn/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"সংযোগ বিচ্ছিন্ন করুন"</string>
     <string name="open_app" msgid="3717639178595958667">"অ্যাপটি খুলুন"</string>
     <string name="dismiss" msgid="6192859333764711227">"খারিজ করুন"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-bs/strings.xml b/packages/VpnDialogs/res/values-bs/strings.xml
index 0626b64..b2f40e2 100644
--- a/packages/VpnDialogs/res/values-bs/strings.xml
+++ b/packages/VpnDialogs/res/values-bs/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ca/strings.xml b/packages/VpnDialogs/res/values-ca/strings.xml
index b8410ef..aa64abd 100644
--- a/packages/VpnDialogs/res/values-ca/strings.xml
+++ b/packages/VpnDialogs/res/values-ca/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconnecta"</string>
     <string name="open_app" msgid="3717639178595958667">"Obre l\'aplicació"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignora"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-cs/strings.xml b/packages/VpnDialogs/res/values-cs/strings.xml
index b1608f9..0658930 100644
--- a/packages/VpnDialogs/res/values-cs/strings.xml
+++ b/packages/VpnDialogs/res/values-cs/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Odpojit"</string>
     <string name="open_app" msgid="3717639178595958667">"Do aplikace"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zavřít"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-da/strings.xml b/packages/VpnDialogs/res/values-da/strings.xml
index 2931cb2..63a32f9 100644
--- a/packages/VpnDialogs/res/values-da/strings.xml
+++ b/packages/VpnDialogs/res/values-da/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Fjern tilknytning"</string>
     <string name="open_app" msgid="3717639178595958667">"Åbn app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Luk"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-de/strings.xml b/packages/VpnDialogs/res/values-de/strings.xml
index 033e550..7397ddb 100644
--- a/packages/VpnDialogs/res/values-de/strings.xml
+++ b/packages/VpnDialogs/res/values-de/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Verbindung trennen"</string>
     <string name="open_app" msgid="3717639178595958667">"App öffnen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Schließen"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-el/strings.xml b/packages/VpnDialogs/res/values-el/strings.xml
index 2c527e8..3d14099 100644
--- a/packages/VpnDialogs/res/values-el/strings.xml
+++ b/packages/VpnDialogs/res/values-el/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Αποσύνδεση"</string>
     <string name="open_app" msgid="3717639178595958667">"Άνοιγμα εφαρμογής"</string>
     <string name="dismiss" msgid="6192859333764711227">"Παράβλεψη"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-es-rUS/strings.xml b/packages/VpnDialogs/res/values-es-rUS/strings.xml
index b75e4bf..3a82cb5 100644
--- a/packages/VpnDialogs/res/values-es-rUS/strings.xml
+++ b/packages/VpnDialogs/res/values-es-rUS/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Descartar"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-es/strings.xml b/packages/VpnDialogs/res/values-es/strings.xml
index d73e2fd..336ac05 100644
--- a/packages/VpnDialogs/res/values-es/strings.xml
+++ b/packages/VpnDialogs/res/values-es/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
     <string name="dismiss" msgid="6192859333764711227">"Cerrar"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-et/strings.xml b/packages/VpnDialogs/res/values-et/strings.xml
index 0e335f2..864b9a4 100644
--- a/packages/VpnDialogs/res/values-et/strings.xml
+++ b/packages/VpnDialogs/res/values-et/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Katkesta ühendus"</string>
     <string name="open_app" msgid="3717639178595958667">"Ava rakendus"</string>
     <string name="dismiss" msgid="6192859333764711227">"Loobu"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-eu/strings.xml b/packages/VpnDialogs/res/values-eu/strings.xml
index e7d3e2b..01d80eb 100644
--- a/packages/VpnDialogs/res/values-eu/strings.xml
+++ b/packages/VpnDialogs/res/values-eu/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Deskonektatu"</string>
     <string name="open_app" msgid="3717639178595958667">"Ireki aplikazioa"</string>
     <string name="dismiss" msgid="6192859333764711227">"Baztertu"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fa/strings.xml b/packages/VpnDialogs/res/values-fa/strings.xml
index 07f8d18..47b8735 100644
--- a/packages/VpnDialogs/res/values-fa/strings.xml
+++ b/packages/VpnDialogs/res/values-fa/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"قطع اتصال"</string>
     <string name="open_app" msgid="3717639178595958667">"باز کردن برنامه"</string>
     <string name="dismiss" msgid="6192859333764711227">"رد کردن"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fi/strings.xml b/packages/VpnDialogs/res/values-fi/strings.xml
index 7e5af3a..a08d66c 100644
--- a/packages/VpnDialogs/res/values-fi/strings.xml
+++ b/packages/VpnDialogs/res/values-fi/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Katkaise yhteys"</string>
     <string name="open_app" msgid="3717639178595958667">"Avaa sovellus"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hylkää"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fr-rCA/strings.xml b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
index 2a1718b..ad450b4 100644
--- a/packages/VpnDialogs/res/values-fr-rCA/strings.xml
+++ b/packages/VpnDialogs/res/values-fr-rCA/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
     <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-fr/strings.xml b/packages/VpnDialogs/res/values-fr/strings.xml
index ba5f092..cdec614 100644
--- a/packages/VpnDialogs/res/values-fr/strings.xml
+++ b/packages/VpnDialogs/res/values-fr/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Déconnecter"</string>
     <string name="open_app" msgid="3717639178595958667">"Ouvrir l\'application"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorer"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-gl/strings.xml b/packages/VpnDialogs/res/values-gl/strings.xml
index b2e3034..5595e15 100644
--- a/packages/VpnDialogs/res/values-gl/strings.xml
+++ b/packages/VpnDialogs/res/values-gl/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir aplicación"</string>
     <string name="dismiss" msgid="6192859333764711227">"Pechar"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-gu/strings.xml b/packages/VpnDialogs/res/values-gu/strings.xml
index 6e9bd32..516d51c 100644
--- a/packages/VpnDialogs/res/values-gu/strings.xml
+++ b/packages/VpnDialogs/res/values-gu/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ડિસ્કનેક્ટ કરો"</string>
     <string name="open_app" msgid="3717639178595958667">"ઍપ ખોલો"</string>
     <string name="dismiss" msgid="6192859333764711227">"છોડી દો"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hi/strings.xml b/packages/VpnDialogs/res/values-hi/strings.xml
index 3e65649..ad0cc0b 100644
--- a/packages/VpnDialogs/res/values-hi/strings.xml
+++ b/packages/VpnDialogs/res/values-hi/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"डिसकनेक्ट करें"</string>
     <string name="open_app" msgid="3717639178595958667">"ऐप खोलें"</string>
     <string name="dismiss" msgid="6192859333764711227">"खारिज करें"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hr/strings.xml b/packages/VpnDialogs/res/values-hr/strings.xml
index dddaa58..ec18688 100644
--- a/packages/VpnDialogs/res/values-hr/strings.xml
+++ b/packages/VpnDialogs/res/values-hr/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini vezu"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvori aplikaciju"</string>
     <string name="dismiss" msgid="6192859333764711227">"Odbaci"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hu/strings.xml b/packages/VpnDialogs/res/values-hu/strings.xml
index a719ef9..0ce41ce 100644
--- a/packages/VpnDialogs/res/values-hu/strings.xml
+++ b/packages/VpnDialogs/res/values-hu/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Kapcsolat bontása"</string>
     <string name="open_app" msgid="3717639178595958667">"Alkalmazás indítása"</string>
     <string name="dismiss" msgid="6192859333764711227">"Bezárás"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-hy/strings.xml b/packages/VpnDialogs/res/values-hy/strings.xml
index b67f79e8..b699902 100644
--- a/packages/VpnDialogs/res/values-hy/strings.xml
+++ b/packages/VpnDialogs/res/values-hy/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Անջատել"</string>
     <string name="open_app" msgid="3717639178595958667">"Բացել հավելվածը"</string>
     <string name="dismiss" msgid="6192859333764711227">"Փակել"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-in/strings.xml b/packages/VpnDialogs/res/values-in/strings.xml
index 20da563..342f403 100644
--- a/packages/VpnDialogs/res/values-in/strings.xml
+++ b/packages/VpnDialogs/res/values-in/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Putuskan koneksi"</string>
     <string name="open_app" msgid="3717639178595958667">"Buka aplikasi"</string>
     <string name="dismiss" msgid="6192859333764711227">"Tutup"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-is/strings.xml b/packages/VpnDialogs/res/values-is/strings.xml
index ab476b2..a52292c 100644
--- a/packages/VpnDialogs/res/values-is/strings.xml
+++ b/packages/VpnDialogs/res/values-is/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Aftengja"</string>
     <string name="open_app" msgid="3717639178595958667">"Opna forrit"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hunsa"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-it/strings.xml b/packages/VpnDialogs/res/values-it/strings.xml
index 19347bf..7773c9e 100644
--- a/packages/VpnDialogs/res/values-it/strings.xml
+++ b/packages/VpnDialogs/res/values-it/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Disconnetti"</string>
     <string name="open_app" msgid="3717639178595958667">"Apri app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignora"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ka/strings.xml b/packages/VpnDialogs/res/values-ka/strings.xml
index d63b416..5c4c815 100644
--- a/packages/VpnDialogs/res/values-ka/strings.xml
+++ b/packages/VpnDialogs/res/values-ka/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"კავშირის გაწყვეტა"</string>
     <string name="open_app" msgid="3717639178595958667">"გახსენით აპი"</string>
     <string name="dismiss" msgid="6192859333764711227">"დახურვა"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-kk/strings.xml b/packages/VpnDialogs/res/values-kk/strings.xml
index b109d91..a519e4c 100644
--- a/packages/VpnDialogs/res/values-kk/strings.xml
+++ b/packages/VpnDialogs/res/values-kk/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ажырату"</string>
     <string name="open_app" msgid="3717639178595958667">"Қолданбаны ашу"</string>
     <string name="dismiss" msgid="6192859333764711227">"Жабу"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-km/strings.xml b/packages/VpnDialogs/res/values-km/strings.xml
index 7e4e9b6..d93c694 100644
--- a/packages/VpnDialogs/res/values-km/strings.xml
+++ b/packages/VpnDialogs/res/values-km/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ផ្ដាច់"</string>
     <string name="open_app" msgid="3717639178595958667">"បើកកម្មវិធី"</string>
     <string name="dismiss" msgid="6192859333764711227">"ច្រានចោល"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-kn/strings.xml b/packages/VpnDialogs/res/values-kn/strings.xml
index 864efd5..4f8d90b 100644
--- a/packages/VpnDialogs/res/values-kn/strings.xml
+++ b/packages/VpnDialogs/res/values-kn/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ಸಂಪರ್ಕ ಕಡಿತಗೊಳಿಸು"</string>
     <string name="open_app" msgid="3717639178595958667">"ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ವಜಾಗೊಳಿಸಿ"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ko/strings.xml b/packages/VpnDialogs/res/values-ko/strings.xml
index 15aa323..ebadad7 100644
--- a/packages/VpnDialogs/res/values-ko/strings.xml
+++ b/packages/VpnDialogs/res/values-ko/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"연결 끊기"</string>
     <string name="open_app" msgid="3717639178595958667">"앱 열기"</string>
     <string name="dismiss" msgid="6192859333764711227">"닫기"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g>(<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ky/strings.xml b/packages/VpnDialogs/res/values-ky/strings.xml
index 0773984..2087b62 100644
--- a/packages/VpnDialogs/res/values-ky/strings.xml
+++ b/packages/VpnDialogs/res/values-ky/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ажыратуу"</string>
     <string name="open_app" msgid="3717639178595958667">"Колдонмону ачуу"</string>
     <string name="dismiss" msgid="6192859333764711227">"Четке кагуу"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lo/strings.xml b/packages/VpnDialogs/res/values-lo/strings.xml
index 747e1f4..4c36b71 100644
--- a/packages/VpnDialogs/res/values-lo/strings.xml
+++ b/packages/VpnDialogs/res/values-lo/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ຕັດການເຊື່ອມຕໍ່"</string>
     <string name="open_app" msgid="3717639178595958667">"ເປີດແອັບ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ປິດໄວ້"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lt/strings.xml b/packages/VpnDialogs/res/values-lt/strings.xml
index 1d9d570..d8783d2 100644
--- a/packages/VpnDialogs/res/values-lt/strings.xml
+++ b/packages/VpnDialogs/res/values-lt/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Atsijungti"</string>
     <string name="open_app" msgid="3717639178595958667">"Atidaryti programą"</string>
     <string name="dismiss" msgid="6192859333764711227">"Atsisakyti"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-lv/strings.xml b/packages/VpnDialogs/res/values-lv/strings.xml
index e3a2db8..7e8ecc1 100644
--- a/packages/VpnDialogs/res/values-lv/strings.xml
+++ b/packages/VpnDialogs/res/values-lv/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Pārtraukt savienojumu"</string>
     <string name="open_app" msgid="3717639178595958667">"Atvērt lietotni"</string>
     <string name="dismiss" msgid="6192859333764711227">"Nerādīt"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mk/strings.xml b/packages/VpnDialogs/res/values-mk/strings.xml
index 867e6d1..ec692ab 100644
--- a/packages/VpnDialogs/res/values-mk/strings.xml
+++ b/packages/VpnDialogs/res/values-mk/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Прекини врска"</string>
     <string name="open_app" msgid="3717639178595958667">"Отвори ја апликацијата"</string>
     <string name="dismiss" msgid="6192859333764711227">"Отфрли"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ml/strings.xml b/packages/VpnDialogs/res/values-ml/strings.xml
index 2c5b048..a98bcdc 100644
--- a/packages/VpnDialogs/res/values-ml/strings.xml
+++ b/packages/VpnDialogs/res/values-ml/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"വിച്ഛേദിക്കുക"</string>
     <string name="open_app" msgid="3717639178595958667">"ആപ്പ് തുറക്കുക"</string>
     <string name="dismiss" msgid="6192859333764711227">"നിരസിക്കുക"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mn/strings.xml b/packages/VpnDialogs/res/values-mn/strings.xml
index a0d8418..8eb3289 100644
--- a/packages/VpnDialogs/res/values-mn/strings.xml
+++ b/packages/VpnDialogs/res/values-mn/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Салгах"</string>
     <string name="open_app" msgid="3717639178595958667">"Апп нээх"</string>
     <string name="dismiss" msgid="6192859333764711227">"Хаах"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-mr/strings.xml b/packages/VpnDialogs/res/values-mr/strings.xml
index 6aeb9e7..cccf369 100644
--- a/packages/VpnDialogs/res/values-mr/strings.xml
+++ b/packages/VpnDialogs/res/values-mr/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"‍डिस्कनेक्ट करा"</string>
     <string name="open_app" msgid="3717639178595958667">"अ‍ॅप उघडा"</string>
     <string name="dismiss" msgid="6192859333764711227">"डिसमिस करा"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ms/strings.xml b/packages/VpnDialogs/res/values-ms/strings.xml
index fe2f433..ad42abb 100644
--- a/packages/VpnDialogs/res/values-ms/strings.xml
+++ b/packages/VpnDialogs/res/values-ms/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Putuskan sambungan"</string>
     <string name="open_app" msgid="3717639178595958667">"Buka apl"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ketepikan"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-my/strings.xml b/packages/VpnDialogs/res/values-my/strings.xml
index 02bb68d..bc212a2 100644
--- a/packages/VpnDialogs/res/values-my/strings.xml
+++ b/packages/VpnDialogs/res/values-my/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ချိတ်ဆက်မှုဖြုတ်ရန်"</string>
     <string name="open_app" msgid="3717639178595958667">"အက်ပ်ကို ဖွင့်ရန်"</string>
     <string name="dismiss" msgid="6192859333764711227">"ပယ်ရန်"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nb/strings.xml b/packages/VpnDialogs/res/values-nb/strings.xml
index 9904745..bca01d0 100644
--- a/packages/VpnDialogs/res/values-nb/strings.xml
+++ b/packages/VpnDialogs/res/values-nb/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Koble fra"</string>
     <string name="open_app" msgid="3717639178595958667">"Åpne appen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Lukk"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ne/strings.xml b/packages/VpnDialogs/res/values-ne/strings.xml
index 1453dfb..675a76d 100644
--- a/packages/VpnDialogs/res/values-ne/strings.xml
+++ b/packages/VpnDialogs/res/values-ne/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"डिस्कनेक्ट गर्नुहोस्"</string>
     <string name="open_app" msgid="3717639178595958667">"एप खोल्नुहोस्"</string>
     <string name="dismiss" msgid="6192859333764711227">"खारेज गर्नुहोस्"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-nl/strings.xml b/packages/VpnDialogs/res/values-nl/strings.xml
index 4223cf4..80e7f1b 100644
--- a/packages/VpnDialogs/res/values-nl/strings.xml
+++ b/packages/VpnDialogs/res/values-nl/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Verbinding verbreken"</string>
     <string name="open_app" msgid="3717639178595958667">"App openen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Sluiten"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-or/strings.xml b/packages/VpnDialogs/res/values-or/strings.xml
index 2714af3..2f5a3dd 100644
--- a/packages/VpnDialogs/res/values-or/strings.xml
+++ b/packages/VpnDialogs/res/values-or/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ବିଚ୍ଛିନ୍ନ କରନ୍ତୁ"</string>
     <string name="open_app" msgid="3717639178595958667">"ଆପ୍‌ ଖୋଲନ୍ତୁ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ଖାରଜ କରନ୍ତୁ"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pa/strings.xml b/packages/VpnDialogs/res/values-pa/strings.xml
index 969d5e2..427cf86 100644
--- a/packages/VpnDialogs/res/values-pa/strings.xml
+++ b/packages/VpnDialogs/res/values-pa/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"ਡਿਸਕਨੈਕਟ ਕਰੋ"</string>
     <string name="open_app" msgid="3717639178595958667">"ਐਪ ਖੋਲ੍ਹੋ"</string>
     <string name="dismiss" msgid="6192859333764711227">"ਖਾਰਜ ਕਰੋ"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pl/strings.xml b/packages/VpnDialogs/res/values-pl/strings.xml
index 199988f..1bd89bb 100644
--- a/packages/VpnDialogs/res/values-pl/strings.xml
+++ b/packages/VpnDialogs/res/values-pl/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Rozłącz"</string>
     <string name="open_app" msgid="3717639178595958667">"Otwórz aplikację"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zamknij"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt-rBR/strings.xml b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
index 8718d76..53d65af 100644
--- a/packages/VpnDialogs/res/values-pt-rBR/strings.xml
+++ b/packages/VpnDialogs/res/values-pt-rBR/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-pt/strings.xml b/packages/VpnDialogs/res/values-pt/strings.xml
index 8718d76..53d65af 100644
--- a/packages/VpnDialogs/res/values-pt/strings.xml
+++ b/packages/VpnDialogs/res/values-pt/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Desconectar"</string>
     <string name="open_app" msgid="3717639178595958667">"Abrir app"</string>
     <string name="dismiss" msgid="6192859333764711227">"Dispensar"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ro/strings.xml b/packages/VpnDialogs/res/values-ro/strings.xml
index 1b18afa..f45609b 100644
--- a/packages/VpnDialogs/res/values-ro/strings.xml
+++ b/packages/VpnDialogs/res/values-ro/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Deconectează"</string>
     <string name="open_app" msgid="3717639178595958667">"Deschide aplicația"</string>
     <string name="dismiss" msgid="6192859333764711227">"Închide"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ru/strings.xml b/packages/VpnDialogs/res/values-ru/strings.xml
index 06d7e02..2e346d3 100644
--- a/packages/VpnDialogs/res/values-ru/strings.xml
+++ b/packages/VpnDialogs/res/values-ru/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Разъединить"</string>
     <string name="open_app" msgid="3717639178595958667">"Открыть приложение"</string>
     <string name="dismiss" msgid="6192859333764711227">"Закрыть"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-si/strings.xml b/packages/VpnDialogs/res/values-si/strings.xml
index 23c8c22..fa5a70f 100644
--- a/packages/VpnDialogs/res/values-si/strings.xml
+++ b/packages/VpnDialogs/res/values-si/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"විසන්ධි කරන්න"</string>
     <string name="open_app" msgid="3717639178595958667">"යෙදුම විවෘත කරන්න"</string>
     <string name="dismiss" msgid="6192859333764711227">"ඉවතලන්න"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sk/strings.xml b/packages/VpnDialogs/res/values-sk/strings.xml
index 22f390c..755abb2 100644
--- a/packages/VpnDialogs/res/values-sk/strings.xml
+++ b/packages/VpnDialogs/res/values-sk/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Odpojiť"</string>
     <string name="open_app" msgid="3717639178595958667">"Otvoriť aplikáciu"</string>
     <string name="dismiss" msgid="6192859333764711227">"Zavrieť"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sl/strings.xml b/packages/VpnDialogs/res/values-sl/strings.xml
index 2f35e34..b473ce0 100644
--- a/packages/VpnDialogs/res/values-sl/strings.xml
+++ b/packages/VpnDialogs/res/values-sl/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Prekini povezavo"</string>
     <string name="open_app" msgid="3717639178595958667">"Odpri aplikacijo"</string>
     <string name="dismiss" msgid="6192859333764711227">"Opusti"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g> … (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sq/strings.xml b/packages/VpnDialogs/res/values-sq/strings.xml
index 174b278..ad9f66e 100644
--- a/packages/VpnDialogs/res/values-sq/strings.xml
+++ b/packages/VpnDialogs/res/values-sq/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Shkëputu"</string>
     <string name="open_app" msgid="3717639178595958667">"Hap aplikacionin"</string>
     <string name="dismiss" msgid="6192859333764711227">"Hiq"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sr/strings.xml b/packages/VpnDialogs/res/values-sr/strings.xml
index 019a5b4..eaa0aef 100644
--- a/packages/VpnDialogs/res/values-sr/strings.xml
+++ b/packages/VpnDialogs/res/values-sr/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Прекини везу"</string>
     <string name="open_app" msgid="3717639178595958667">"Отвори апликацију"</string>
     <string name="dismiss" msgid="6192859333764711227">"Одбаци"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sv/strings.xml b/packages/VpnDialogs/res/values-sv/strings.xml
index 5e0aec3..175ebba 100644
--- a/packages/VpnDialogs/res/values-sv/strings.xml
+++ b/packages/VpnDialogs/res/values-sv/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Koppla från"</string>
     <string name="open_app" msgid="3717639178595958667">"Öppna appen"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ignorera"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-sw/strings.xml b/packages/VpnDialogs/res/values-sw/strings.xml
index 1dfbe7a..66c2899 100644
--- a/packages/VpnDialogs/res/values-sw/strings.xml
+++ b/packages/VpnDialogs/res/values-sw/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Tenganisha"</string>
     <string name="open_app" msgid="3717639178595958667">"Fungua programu"</string>
     <string name="dismiss" msgid="6192859333764711227">"Ondoa"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml
index 87f64de..31602a6 100644
--- a/packages/VpnDialogs/res/values-ta/strings.xml
+++ b/packages/VpnDialogs/res/values-ta/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"தொடர்பைத் துண்டி"</string>
     <string name="open_app" msgid="3717639178595958667">"பயன்பாட்டைத் திற"</string>
     <string name="dismiss" msgid="6192859333764711227">"நிராகரி"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-te/strings.xml b/packages/VpnDialogs/res/values-te/strings.xml
index fcf54bc..685dd26 100644
--- a/packages/VpnDialogs/res/values-te/strings.xml
+++ b/packages/VpnDialogs/res/values-te/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"డిస్‌కనెక్ట్ చేయి"</string>
     <string name="open_app" msgid="3717639178595958667">"యాప్‌ని తెరవండి"</string>
     <string name="dismiss" msgid="6192859333764711227">"తీసివేయండి"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-tl/strings.xml b/packages/VpnDialogs/res/values-tl/strings.xml
index bb099e7..0b4a106 100644
--- a/packages/VpnDialogs/res/values-tl/strings.xml
+++ b/packages/VpnDialogs/res/values-tl/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Idiskonekta"</string>
     <string name="open_app" msgid="3717639178595958667">"Buksan ang app"</string>
     <string name="dismiss" msgid="6192859333764711227">"I-dismiss"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-tr/strings.xml b/packages/VpnDialogs/res/values-tr/strings.xml
index 8204234..e3606ef 100644
--- a/packages/VpnDialogs/res/values-tr/strings.xml
+++ b/packages/VpnDialogs/res/values-tr/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Bağlantıyı kes"</string>
     <string name="open_app" msgid="3717639178595958667">"Uygulamayı aç"</string>
     <string name="dismiss" msgid="6192859333764711227">"Kapat"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-uk/strings.xml b/packages/VpnDialogs/res/values-uk/strings.xml
index 3890096..1dd0e8a 100644
--- a/packages/VpnDialogs/res/values-uk/strings.xml
+++ b/packages/VpnDialogs/res/values-uk/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Від’єднати"</string>
     <string name="open_app" msgid="3717639178595958667">"Відкрити додаток"</string>
     <string name="dismiss" msgid="6192859333764711227">"Закрити"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-ur/strings.xml b/packages/VpnDialogs/res/values-ur/strings.xml
index 7fa828a..803f042 100644
--- a/packages/VpnDialogs/res/values-ur/strings.xml
+++ b/packages/VpnDialogs/res/values-ur/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"منقطع کریں"</string>
     <string name="open_app" msgid="3717639178595958667">"ایپ کھولیں"</string>
     <string name="dismiss" msgid="6192859333764711227">"برخاست کریں"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-uz/strings.xml b/packages/VpnDialogs/res/values-uz/strings.xml
index 80dcf94..a54fa08 100644
--- a/packages/VpnDialogs/res/values-uz/strings.xml
+++ b/packages/VpnDialogs/res/values-uz/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Aloqani uzish"</string>
     <string name="open_app" msgid="3717639178595958667">"Ilovani ochish"</string>
     <string name="dismiss" msgid="6192859333764711227">"Yopish"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-vi/strings.xml b/packages/VpnDialogs/res/values-vi/strings.xml
index 7d8cc86..6ce9f39 100644
--- a/packages/VpnDialogs/res/values-vi/strings.xml
+++ b/packages/VpnDialogs/res/values-vi/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ngắt kết nối"</string>
     <string name="open_app" msgid="3717639178595958667">"Mở ứng dụng"</string>
     <string name="dismiss" msgid="6192859333764711227">"Loại bỏ"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rCN/strings.xml b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
index 1d8adbb..38a2e8d 100644
--- a/packages/VpnDialogs/res/values-zh-rCN/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rCN/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"断开连接"</string>
     <string name="open_app" msgid="3717639178595958667">"打开应用"</string>
     <string name="dismiss" msgid="6192859333764711227">"关闭"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>…(<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rHK/strings.xml b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
index a0d6ee0..f3abf3c 100644
--- a/packages/VpnDialogs/res/values-zh-rHK/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rHK/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
     <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string>
     <string name="dismiss" msgid="6192859333764711227">"關閉"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zh-rTW/strings.xml b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
index 948bc59..3f1336b 100644
--- a/packages/VpnDialogs/res/values-zh-rTW/strings.xml
+++ b/packages/VpnDialogs/res/values-zh-rTW/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"中斷連線"</string>
     <string name="open_app" msgid="3717639178595958667">"開啟應用程式"</string>
     <string name="dismiss" msgid="6192859333764711227">"關閉"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… (<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> (<xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/packages/VpnDialogs/res/values-zu/strings.xml b/packages/VpnDialogs/res/values-zu/strings.xml
index 875873f..563ed0f5 100644
--- a/packages/VpnDialogs/res/values-zu/strings.xml
+++ b/packages/VpnDialogs/res/values-zu/strings.xml
@@ -34,8 +34,6 @@
     <string name="disconnect" msgid="971412338304200056">"Ayixhumekile kwi-inthanethi"</string>
     <string name="open_app" msgid="3717639178595958667">"Vula uhlelo lokusebenza"</string>
     <string name="dismiss" msgid="6192859333764711227">"Cashisa"</string>
-    <!-- no translation found for sanitized_vpn_label_with_ellipsis (7014327474633422235) -->
-    <skip />
-    <!-- no translation found for sanitized_vpn_label (1877415015009794766) -->
-    <skip />
+    <string name="sanitized_vpn_label_with_ellipsis" msgid="7014327474633422235">"<xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_0">%1$s</xliff:g>… ( <xliff:g id="SANITIZED_VPN_LABEL_WITH_ELLIPSIS_1">%2$s</xliff:g>)"</string>
+    <string name="sanitized_vpn_label" msgid="1877415015009794766">"<xliff:g id="SANITIZED_VPN_LABEL_0">%1$s</xliff:g> ( <xliff:g id="SANITIZED_VPN_LABEL_1">%2$s</xliff:g>)"</string>
 </resources>
diff --git a/services/OWNERS b/services/OWNERS
index 495c0737..eace906 100644
--- a/services/OWNERS
+++ b/services/OWNERS
@@ -3,7 +3,7 @@
 # art-team@ manages the system server profile
 per-file art-profile* = calin@google.com, ngeoffray@google.com, vmarko@google.com
 
-per-file java/com/android/server/* = toddke@google.com,patb@google.com
+per-file java/com/android/server/* = patb@google.com #{LAST_RESORT_SUGGESTION}
 per-file tests/servicestests/src/com/android/server/systemconfig/* = patb@google.com
 
 per-file proguard.flags = jdduke@google.com
diff --git a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
index 786d407..e92150b 100644
--- a/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/AbstractAccessibilityServiceConnection.java
@@ -74,8 +74,10 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
+import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
+import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.View;
 import android.view.WindowInfo;
@@ -200,6 +202,8 @@
 
     final ComponentName mComponentName;
 
+    int mGenericMotionEventSources;
+
     // the events pending events to be dispatched to this service
     final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
 
@@ -362,6 +366,7 @@
         }
         mNotificationTimeout = info.notificationTimeout;
         mIsDefault = (info.flags & DEFAULT) != 0;
+        mGenericMotionEventSources = info.getMotionEventSources();
 
         if (supportsFlagForNotImportantViews(info)) {
             if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
@@ -1751,6 +1756,11 @@
         return mSystemSupport.getWindowTransformationMatrixAndMagnificationSpec(resolvedWindowId);
     }
 
+    public boolean wantsGenericMotionEvent(MotionEvent event) {
+        final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
+        return (mGenericMotionEventSources & eventSourceWithoutClass) != 0;
+    }
+
     /**
      * Called by the invocation handler to notify the service that the
      * state of magnification has changed.
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index d80117d..c87d1c8 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -141,6 +141,9 @@
      */
     static final int FLAG_SEND_MOTION_EVENTS = 0x00000400;
 
+    /** Flag for intercepting generic motion events. */
+    static final int FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS = 0x00000800;
+
     static final int FEATURES_AFFECTING_MOTION_EVENTS =
             FLAG_FEATURE_INJECT_MOTION_EVENTS
                     | FLAG_FEATURE_AUTOCLICK
@@ -149,7 +152,8 @@
                     | FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER
                     | FLAG_SERVICE_HANDLES_DOUBLE_TAP
                     | FLAG_REQUEST_MULTI_FINGER_GESTURES
-                    | FLAG_REQUEST_2_FINGER_PASSTHROUGH;
+                    | FLAG_REQUEST_2_FINGER_PASSTHROUGH
+                    | FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
 
     private final Context mContext;
 
@@ -182,6 +186,10 @@
 
     private final SparseArray<EventStreamState> mTouchScreenStreamStates = new SparseArray<>(0);
 
+    // State tracking for generic MotionEvents is display-agnostic so we only need one.
+    private GenericMotionEventStreamState mGenericMotionEventStreamState;
+    private int mCombinedGenericMotionEventSources = 0;
+
     private EventStreamState mKeyboardStreamState;
 
     AccessibilityInputFilter(Context context, AccessibilityManagerService service) {
@@ -205,6 +213,7 @@
         mInstalled = true;
         disableFeatures();
         enableFeatures();
+        mAms.onInputFilterInstalled(true);
         super.onInstalled();
     }
 
@@ -215,6 +224,7 @@
         }
         mInstalled = false;
         disableFeatures();
+        mAms.onInputFilterInstalled(false);
         super.onUninstalled();
     }
 
@@ -296,7 +306,13 @@
     private EventStreamState getEventStreamState(InputEvent event) {
         if (event instanceof MotionEvent) {
             final int displayId = event.getDisplayId();
+            if (mGenericMotionEventStreamState == null) {
+                mGenericMotionEventStreamState = new GenericMotionEventStreamState();
+            }
 
+            if (mGenericMotionEventStreamState.shouldProcessMotionEvent((MotionEvent) event)) {
+                return mGenericMotionEventStreamState;
+            }
             if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)) {
                 EventStreamState touchScreenStreamState = mTouchScreenStreamStates.get(displayId);
                 if (touchScreenStreamState == null) {
@@ -362,8 +378,11 @@
         mPm.userActivity(event.getEventTime(), false);
         MotionEvent transformedEvent = MotionEvent.obtain(event);
         final int displayId = event.getDisplayId();
-        mEventHandler.get(isDisplayIdValid(displayId) ? displayId : Display.DEFAULT_DISPLAY)
-                .onMotionEvent(transformedEvent, event, policyFlags);
+        EventStreamTransformation eventStreamTransformation = mEventHandler.get(
+                isDisplayIdValid(displayId) ? displayId : Display.DEFAULT_DISPLAY);
+        if (eventStreamTransformation != null) {
+            eventStreamTransformation.onMotionEvent(transformedEvent, event, policyFlags);
+        }
         transformedEvent.recycle();
     }
 
@@ -490,6 +509,19 @@
             mTouchExplorer.put(displayId, explorer);
         }
 
+        if ((mEnabledFeatures & FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS) != 0) {
+            addFirstEventHandler(displayId, new BaseEventStreamTransformation() {
+                @Override
+                public void onMotionEvent(MotionEvent event, MotionEvent rawEvent,
+                        int policyFlags) {
+                    if (!anyServiceWantsGenericMotionEvent(rawEvent)
+                            || !mAms.sendMotionEventToListeningServices(rawEvent)) {
+                        super.onMotionEvent(event, rawEvent, policyFlags);
+                    }
+                }
+            });
+        }
+
         if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
                 || ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0)
                 || ((mEnabledFeatures & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0)) {
@@ -842,6 +874,32 @@
         }
     }
 
+    private class GenericMotionEventStreamState extends EventStreamState {
+        @Override
+        public boolean shouldProcessMotionEvent(MotionEvent event) {
+            return anyServiceWantsGenericMotionEvent(event);
+        }
+        @Override
+        public boolean shouldProcessScroll() {
+            return true;
+        }
+    }
+
+    private boolean anyServiceWantsGenericMotionEvent(MotionEvent event) {
+        // Disable SOURCE_TOUCHSCREEN generic event interception if any service is performing
+        // touch exploration.
+        if (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
+                && (mEnabledFeatures & FLAG_FEATURE_TOUCH_EXPLORATION) != 0) {
+            return false;
+        }
+        final int eventSourceWithoutClass = event.getSource() & ~InputDevice.SOURCE_CLASS_MASK;
+        return (mCombinedGenericMotionEventSources & eventSourceWithoutClass) != 0;
+    }
+
+    public void setCombinedGenericMotionEventSources(int sources) {
+        mCombinedGenericMotionEventSources = sources;
+    }
+
     /**
      * Keeps state of streams of events from all keyboard devices.
      */
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 87d1668..3145139 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -106,6 +106,8 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.IWindow;
+import android.view.InputDevice;
+import android.view.InputEvent;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
 import android.view.MotionEvent;
@@ -147,6 +149,7 @@
 import com.android.server.accessibility.magnification.WindowMagnificationManager;
 import com.android.server.inputmethod.InputMethodManagerInternal;
 import com.android.server.pm.UserManagerInternal;
+import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.ActivityTaskManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -190,7 +193,7 @@
 
     // TODO: Restructure service initialization so services aren't connected before all of
     //       their capabilities are ready.
-    private static final int WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS = 1000;
+    private static final int WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS = 1000;
 
 
     // This postpones state changes events when a window doesn't exist with the expectation that
@@ -258,6 +261,8 @@
 
     private boolean mHasInputFilter;
 
+    private boolean mInputFilterInstalled;
+
     private KeyEventDispatcher mKeyEventDispatcher;
 
     private SparseArray<MotionEventInjector> mMotionEventInjectors;
@@ -517,6 +522,16 @@
         return mFingerprintGestureDispatcher;
     }
 
+    /**
+     * Called by the {@link AccessibilityInputFilter} when the filter install state changes.
+     */
+    public void onInputFilterInstalled(boolean installed) {
+        synchronized (mLock) {
+            mInputFilterInstalled = installed;
+            mLock.notifyAll();
+        }
+    }
+
     private void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
             if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)) {
@@ -860,7 +875,8 @@
                     Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
                 }
                 return IntPair.of(
-                        getClientStateLocked(userState),
+                        combineUserStateAndProxyState(getClientStateLocked(userState),
+                                mProxyManager.getStateLocked()),
                         client.mLastSentRelevantEventTypes);
             } else {
                 userState.mUserClients.register(callback, client);
@@ -872,7 +888,9 @@
                             + " and userId:" + mCurrentUserId);
                 }
                 return IntPair.of(
-                        (resolvedUserId == mCurrentUserId) ? getClientStateLocked(userState) : 0,
+                        (resolvedUserId == mCurrentUserId) ? combineUserStateAndProxyState(
+                                getClientStateLocked(userState), mProxyManager.getStateLocked())
+                                : 0,
                         client.mLastSentRelevantEventTypes);
             }
         }
@@ -1003,6 +1021,7 @@
         notifyAccessibilityServicesDelayedLocked(event, false);
         notifyAccessibilityServicesDelayedLocked(event, true);
         mUiAutomationManager.sendAccessibilityEventLocked(event);
+        mProxyManager.sendAccessibilityEvent(event);
     }
 
     private void sendAccessibilityEventToInputFilter(AccessibilityEvent event) {
@@ -1143,9 +1162,9 @@
             }
             List<AccessibilityServiceConnection> services =
                     getUserStateLocked(resolvedUserId).mBoundServices;
-            int numServices = services.size();
+            int numServices = services.size() + mProxyManager.getNumProxys();
             interfacesToInterrupt = new ArrayList<>(numServices);
-            for (int i = 0; i < numServices; i++) {
+            for (int i = 0; i < services.size(); i++) {
                 AccessibilityServiceConnection service = services.get(i);
                 IBinder a11yServiceBinder = service.mService;
                 IAccessibilityServiceClient a11yServiceInterface = service.mServiceInterface;
@@ -1153,6 +1172,7 @@
                     interfacesToInterrupt.add(a11yServiceInterface);
                 }
             }
+            mProxyManager.addServiceInterfaces(interfacesToInterrupt);
         }
         for (int i = 0, count = interfacesToInterrupt.size(); i < count; i++) {
             try {
@@ -1345,7 +1365,7 @@
         }
     }
 
-    /** Send a motion event to the service to allow it to perform gesture detection. */
+    /** Send a motion event to the services. */
     public boolean sendMotionEventToListeningServices(MotionEvent event) {
         boolean result;
         event = MotionEvent.obtain(event);
@@ -1448,7 +1468,7 @@
 
     @Override
     public @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId) {
-        final long endMillis = SystemClock.uptimeMillis() + WAIT_MOTION_INJECTOR_TIMEOUT_MILLIS;
+        final long endMillis = SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS;
         MotionEventInjector motionEventInjector = null;
         while ((mMotionEventInjectors == null) && (SystemClock.uptimeMillis() < endMillis)) {
             try {
@@ -1702,7 +1722,9 @@
             AccessibilityUserState state = getCurrentUserStateLocked();
             for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
                 AccessibilityServiceConnection service = state.mBoundServices.get(i);
-                if (service.isServiceDetectsGesturesEnabled(displayId)) {
+                if (service.wantsGenericMotionEvent(event)
+                        || (event.isFromSource(InputDevice.SOURCE_TOUCHSCREEN)
+                        && service.isServiceDetectsGesturesEnabled(displayId))) {
                     service.notifyMotionEvent(event);
                     result = true;
                 }
@@ -1941,6 +1963,7 @@
                 mUiAutomationManager.getServiceInfo(), client)
                 ? mUiAutomationManager.getRelevantEventTypes()
                 : 0;
+        relevantEventTypes |= mProxyManager.getRelevantEventTypes();
         return relevantEventTypes;
     }
 
@@ -2178,21 +2201,25 @@
         updateAccessibilityEnabledSettingLocked(userState);
     }
 
-    void scheduleUpdateClientsIfNeeded(AccessibilityUserState userState) {
-        synchronized (mLock) {
-            scheduleUpdateClientsIfNeededLocked(userState);
-        }
+    private int combineUserStateAndProxyState(int userState, int proxyState) {
+        return userState | proxyState;
     }
 
     void scheduleUpdateClientsIfNeededLocked(AccessibilityUserState userState) {
         final int clientState = getClientStateLocked(userState);
-        if (userState.getLastSentClientStateLocked() != clientState
+        final int proxyState = mProxyManager.getStateLocked();
+        if ((userState.getLastSentClientStateLocked() != clientState
+                || mProxyManager.getLastSentStateLocked() != proxyState)
                 && (mGlobalClients.getRegisteredCallbackCount() > 0
-                        || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
+                || userState.mUserClients.getRegisteredCallbackCount() > 0)) {
             userState.setLastSentClientStateLocked(clientState);
+            mProxyManager.setLastStateLocked(proxyState);
+            // Send both the user and proxy state to the app for now.
+            // TODO(b/250929565): Send proxy state to proxy clients
             mMainHandler.sendMessage(obtainMessage(
                     AccessibilityManagerService::sendStateToAllClients,
-                    this, clientState, userState.mUserId));
+                    this, combineUserStateAndProxyState(clientState, proxyState),
+                    userState.mUserId));
         }
     }
 
@@ -2292,6 +2319,13 @@
             if (userState.isPerformGesturesEnabledLocked()) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_INJECT_MOTION_EVENTS;
             }
+            int combinedGenericMotionEventSources = 0;
+            for (AccessibilityServiceConnection connection : userState.mBoundServices) {
+                combinedGenericMotionEventSources |= connection.mGenericMotionEventSources;
+            }
+            if (combinedGenericMotionEventSources != 0) {
+                flags |= AccessibilityInputFilter.FLAG_FEATURE_INTERCEPT_GENERIC_MOTION_EVENTS;
+            }
             if (flags != 0) {
                 if (!mHasInputFilter) {
                     mHasInputFilter = true;
@@ -2304,6 +2338,8 @@
                     setInputFilter = true;
                 }
                 mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
+                mInputFilter.setCombinedGenericMotionEventSources(
+                        combinedGenericMotionEventSources);
             } else {
                 if (mHasInputFilter) {
                     mHasInputFilter = false;
@@ -2434,7 +2470,8 @@
         // binding we do an update pass after each bind event, so we run this
         // code and register the callback if needed.
 
-        boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked();
+        boolean observingWindows = mUiAutomationManager.canRetrieveInteractiveWindowsLocked()
+                || mProxyManager.canRetrieveInteractiveWindowsLocked();
         List<AccessibilityServiceConnection> boundServices = userState.mBoundServices;
         final int boundServiceCount = boundServices.size();
         for (int i = 0; !observingWindows && (i < boundServiceCount); i++) {
@@ -3657,7 +3694,9 @@
                     + "proxy-ed");
         }
 
-        mProxyManager.registerProxy(client, displayId);
+        mProxyManager.registerProxy(client, displayId, mContext,
+                sIdCounter++, mMainHandler, mSecurityPolicy, this, getTraceManager(),
+                mWindowManagerService, mA11yWindowManager);
         return true;
     }
 
@@ -4633,6 +4672,29 @@
         }
     }
 
+    @Override
+    public void injectInputEventToInputFilter(InputEvent event) {
+        synchronized (mLock) {
+            final long endMillis =
+                    SystemClock.uptimeMillis() + WAIT_INPUT_FILTER_INSTALL_TIMEOUT_MS;
+            while (!mInputFilterInstalled && (SystemClock.uptimeMillis() < endMillis)) {
+                try {
+                    mLock.wait(endMillis - SystemClock.uptimeMillis());
+                } catch (InterruptedException ie) {
+                    /* ignore */
+                }
+            }
+        }
+
+        if (mInputFilterInstalled && mInputFilter != null) {
+            mInputFilter.onInputEvent(event,
+                    WindowManagerPolicy.FLAG_PASS_TO_USER | WindowManagerPolicy.FLAG_INJECTED);
+        } else {
+            Slog.w(LOG_TAG, "Cannot injectInputEventToInputFilter because the "
+                    + "AccessibilityInputFilter is not installed.");
+        }
+    }
+
     private final class SendWindowStateChangedEventRunnable implements Runnable {
 
         private final AccessibilityEvent mPendingEvent;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
index e5e1d02..ce269f5 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilitySecurityPolicy.java
@@ -696,7 +696,7 @@
         final ResolveInfo resolveInfo = service.getServiceInfo().getResolveInfo();
 
         if (resolveInfo == null) {
-            // For InteractionBridge and UiAutomation
+            // For InteractionBridge, UiAutomation, and Proxy.
             return true;
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
index 247f320..d7f9c12 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyAccessibilityServiceConnection.java
@@ -16,8 +16,12 @@
 
 package com.android.server.accessibility;
 
+import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_CLASS_NAME;
+import static com.android.server.accessibility.ProxyManager.PROXY_COMPONENT_PACKAGE_NAME;
+
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accessibilityservice.AccessibilityTrace;
+import android.accessibilityservice.IAccessibilityServiceClient;
 import android.accessibilityservice.MagnificationConfig;
 import android.annotation.NonNull;
 import android.content.ComponentName;
@@ -31,6 +35,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteCallback;
+import android.os.RemoteException;
 import android.view.KeyEvent;
 import android.view.accessibility.AccessibilityDisplayProxy;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -53,10 +58,6 @@
  * TODO(241429275): Initialize this when a proxy is registered.
  */
 public class ProxyAccessibilityServiceConnection extends AccessibilityServiceConnection {
-    // Names used to populate ComponentName and ResolveInfo
-    private static final String PROXY_COMPONENT_PACKAGE_NAME = "ProxyPackage";
-    private static final String PROXY_COMPONENT_CLASS_NAME = "ProxyClass";
-
     private int mDisplayId;
     private List<AccessibilityServiceInfo> mInstalledAndEnabledServices;
 
@@ -76,6 +77,16 @@
     }
 
     /**
+     * Called when the proxy is registered.
+     */
+    void initializeServiceInterface(IAccessibilityServiceClient serviceInterface)
+            throws RemoteException {
+        mServiceInterface = serviceInterface;
+        mService = serviceInterface.asBinder();
+        mServiceInterface.init(this, mId, this.mOverlayWindowTokens.get(mDisplayId));
+    }
+
+    /**
      * Keeps mAccessibilityServiceInfo in sync with the proxy's list of AccessibilityServiceInfos.
      *
      * <p>This also sets the properties that are assumed to be populated by installed packages.
@@ -89,7 +100,7 @@
             synchronized (mLock) {
                 mInstalledAndEnabledServices = infos;
                 final AccessibilityServiceInfo proxyInfo = mAccessibilityServiceInfo;
-                // Reset values.
+                // Reset values. mAccessibilityServiceInfo is not completely reset since it is final
                 proxyInfo.flags = 0;
                 proxyInfo.eventTypes = 0;
                 proxyInfo.notificationTimeout = 0;
diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
index a2ce610..2184878 100644
--- a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
+++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java
@@ -14,9 +14,21 @@
  * limitations under the License.
  */
 package com.android.server.accessibility;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.AccessibilityTrace;
 import android.accessibilityservice.IAccessibilityServiceClient;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.SparseArray;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 
-import java.util.HashSet;
+import com.android.server.wm.WindowManagerInternal;
+
+import java.util.List;
 
 /**
  * Manages proxy connections.
@@ -27,32 +39,185 @@
  * TODO(241117292): Remove or cut down during simultaneous user refactoring.
  */
 public class ProxyManager {
+    // Names used to populate ComponentName and ResolveInfo in connection.mA11yServiceInfo and in
+    // the infos of connection.setInstalledAndEnabledServices
+    static final String PROXY_COMPONENT_PACKAGE_NAME = "ProxyPackage";
+    static final String PROXY_COMPONENT_CLASS_NAME = "ProxyClass";
+
     private final Object mLock;
-    private final HashSet<Integer> mDisplayIds = new HashSet<>();
+
+    // Used to determine if we should notify AccessibilityManager clients of updates.
+    // TODO(254545943): Separate this so each display id has its own state. Currently there is no
+    // way to identify from AccessibilityManager which proxy state should be returned.
+    private int mLastState = -1;
+
+    private SparseArray<ProxyAccessibilityServiceConnection> mProxyA11yServiceConnections =
+            new SparseArray<>();
 
     ProxyManager(Object lock) {
         mLock = lock;
     }
 
     /**
-     * TODO: Create the proxy service connection.
+     * Creates the service connection.
      */
-    public void registerProxy(IAccessibilityServiceClient client, int displayId) {
-        mDisplayIds.add(displayId);
+    public void registerProxy(IAccessibilityServiceClient client, int displayId,
+            Context context,
+            int id, Handler mainHandler,
+            AccessibilitySecurityPolicy securityPolicy,
+            AbstractAccessibilityServiceConnection.SystemSupport systemSupport,
+            AccessibilityTrace trace,
+            WindowManagerInternal windowManagerInternal,
+            AccessibilityWindowManager awm) throws RemoteException {
+
+        // Set a default AccessibilityServiceInfo that is used before the proxy's info is
+        // populated. A proxy has the touch exploration and window capabilities.
+        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        info.setCapabilities(AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
+                | AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT);
+        final String componentClassDisplayName = PROXY_COMPONENT_CLASS_NAME + displayId;
+        info.setComponentName(new ComponentName(PROXY_COMPONENT_PACKAGE_NAME,
+                componentClassDisplayName));
+        ProxyAccessibilityServiceConnection connection =
+                new ProxyAccessibilityServiceConnection(context, info.getComponentName(), info,
+                        id, mainHandler, mLock, securityPolicy, systemSupport, trace,
+                        windowManagerInternal,
+                        awm, displayId);
+
+        mProxyA11yServiceConnections.put(displayId, connection);
+
+        // If the client dies, make sure to remove the connection.
+        IBinder.DeathRecipient deathRecipient =
+                new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        client.asBinder().unlinkToDeath(this, 0);
+                        clearConnection(displayId);
+                    }
+                };
+        client.asBinder().linkToDeath(deathRecipient, 0);
+        // Notify apps that the service state has changed.
+        // A11yManager#A11yServicesStateChangeListener
+        connection.mSystemSupport.onClientChangeLocked(true);
+
+        connection.initializeServiceInterface(client);
     }
 
     /**
-     * TODO: Unregister the proxy service connection based on display id.
+     * Unregister the proxy based on display id.
      */
     public boolean unregisterProxy(int displayId) {
-        mDisplayIds.remove(displayId);
-        return true;
+        return clearConnection(displayId);
+    }
+
+    private boolean clearConnection(int displayId) {
+        if (mProxyA11yServiceConnections.contains(displayId)) {
+            mProxyA11yServiceConnections.remove(displayId);
+            return true;
+        }
+        return false;
     }
 
     /**
      * Checks if a display id is being proxy-ed.
      */
     public boolean isProxyed(int displayId) {
-        return mDisplayIds.contains(displayId);
+        return mProxyA11yServiceConnections.contains(displayId);
     }
-}
+
+    /**
+     * Sends AccessibilityEvents to all proxies.
+     * {@link android.view.accessibility.AccessibilityDisplayProxy} will filter based on display.
+     * TODO(b/250929565): Filtering should happen in the system, not in the proxy.
+     */
+    public void sendAccessibilityEvent(AccessibilityEvent event) {
+        for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+            ProxyAccessibilityServiceConnection proxy =
+                    mProxyA11yServiceConnections.valueAt(i);
+            proxy.notifyAccessibilityEvent(event);
+        }
+    }
+
+    /**
+     * Returns {@code true} if any proxy can retrieve windows.
+     * TODO(b/250929565): Retrieve per connection/user state.
+     */
+    public boolean canRetrieveInteractiveWindowsLocked() {
+        boolean observingWindows = false;
+        for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+            final ProxyAccessibilityServiceConnection proxy =
+                    mProxyA11yServiceConnections.valueAt(i);
+            if (proxy.mRetrieveInteractiveWindows) {
+                observingWindows = true;
+                break;
+            }
+        }
+        return observingWindows;
+    }
+
+    /**
+     * If there is at least one proxy, accessibility is enabled.
+     */
+    public int getStateLocked() {
+        int clientState = 0;
+        final boolean a11yEnabled = mProxyA11yServiceConnections.size() > 0;
+        if (a11yEnabled) {
+            clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+        }
+        return clientState;
+        // TODO(b/254545943): When A11yManager is separated, include support for other properties
+        // like isTouchExplorationEnabled.
+    }
+
+    /**
+     * Gets the last state.
+     */
+    public int getLastSentStateLocked() {
+        return mLastState;
+    }
+
+    /**
+     * Sets the last state.
+     */
+    public void setLastStateLocked(int proxyState) {
+        mLastState = proxyState;
+    }
+
+    /**
+     * Returns the relevant event types of every proxy.
+     * TODO(254545943): When A11yManager is separated, return based on the A11yManager display.
+     */
+    public int getRelevantEventTypes() {
+        int relevantEventTypes = 0;
+        for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+            ProxyAccessibilityServiceConnection proxy =
+                    mProxyA11yServiceConnections.valueAt(i);
+            relevantEventTypes |= proxy.getRelevantEventTypes();
+        }
+        return relevantEventTypes;
+    }
+
+    /**
+     * Gets the number of current proxy connections.
+     * @return
+     */
+    public int getNumProxys() {
+        return mProxyA11yServiceConnections.size();
+    }
+
+    /**
+     * Adds the service interfaces to a list.
+     * @param interfaces
+     */
+    public void addServiceInterfaces(List<IAccessibilityServiceClient> interfaces) {
+        for (int i = 0; i < mProxyA11yServiceConnections.size(); i++) {
+            final ProxyAccessibilityServiceConnection proxy =
+                    mProxyA11yServiceConnections.valueAt(i);
+            final IBinder proxyBinder = proxy.mService;
+            final IAccessibilityServiceClient proxyInterface = proxy.mServiceInterface;
+            if ((proxyBinder != null) && (proxyInterface != null)) {
+                interfaces.add(proxyInterface);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/api/current.txt b/services/api/current.txt
index 42ae10e..834ed2f 100644
--- a/services/api/current.txt
+++ b/services/api/current.txt
@@ -76,6 +76,7 @@
     method @Nullable public String getSdkLibraryName();
     method @NonNull public java.util.List<com.android.server.pm.pkg.AndroidPackageSplit> getSplits();
     method @Nullable public String getStaticSharedLibraryName();
+    method @NonNull public java.util.UUID getStorageUuid();
     method public int getTargetSdkVersion();
     method public boolean isDebuggable();
     method public boolean isIsolatedSplitLoading();
@@ -99,6 +100,7 @@
     method public int getAppId();
     method @NonNull public String getPackageName();
     method @Nullable public String getPrimaryCpuAbi();
+    method @Nullable public String getSeInfo();
     method @Nullable public String getSecondaryCpuAbi();
     method @NonNull public com.android.server.pm.pkg.PackageUserState getStateForUser(@NonNull android.os.UserHandle);
     method @NonNull public java.util.List<com.android.server.pm.pkg.SharedLibrary> getUsesLibraries();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 3cfae60..8baae53a 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -35,6 +35,7 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.AppOpsManagerInternal;
+import android.app.BroadcastOptions;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
 import android.app.KeyguardManager;
@@ -257,6 +258,9 @@
     private boolean mIsProviderInfoPersisted;
     private boolean mIsCombinedBroadcastEnabled;
 
+    // Mark widget lifecycle broadcasts as 'interactive'
+    private Bundle mInteractiveBroadcast;
+
     AppWidgetServiceImpl(Context context) {
         mContext = context;
     }
@@ -286,6 +290,11 @@
             Slog.d(TAG, "App widget provider info will not be persisted on this device");
         }
 
+        BroadcastOptions opts = BroadcastOptions.makeBasic();
+        opts.setBackgroundActivityStartsAllowed(false);
+        opts.setInteractive(true);
+        mInteractiveBroadcast = opts.toBundle();
+
         computeMaximumWidgetBitmapMemory();
         registerBroadcastReceiver();
         registerOnCrossProfileProvidersChangedListener();
@@ -2379,33 +2388,40 @@
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLE_AND_UPDATE);
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
         intent.setComponent(p.id.componentName);
-        sendBroadcastAsUser(intent, p.id.getProfile());
+        // Placing a widget is something users expect to be UX-responsive, so mark this
+        // broadcast as interactive
+        sendBroadcastAsUser(intent, p.id.getProfile(), true);
     }
 
     private void sendEnableIntentLocked(Provider p) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
         intent.setComponent(p.id.componentName);
-        sendBroadcastAsUser(intent, p.id.getProfile());
+        // Enabling the widget is something users expect to be UX-responsive, so mark this
+        // broadcast as interactive
+        sendBroadcastAsUser(intent, p.id.getProfile(), true);
     }
 
     private void sendUpdateIntentLocked(Provider provider, int[] appWidgetIds) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
         intent.setComponent(provider.id.componentName);
-        sendBroadcastAsUser(intent, provider.id.getProfile());
+        // Periodic background widget update heartbeats are not an interactive use case
+        sendBroadcastAsUser(intent, provider.id.getProfile(), false);
     }
 
     private void sendDeletedIntentLocked(Widget widget) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
         intent.setComponent(widget.provider.id.componentName);
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
-        sendBroadcastAsUser(intent, widget.provider.id.getProfile());
+        // Cleanup after deletion isn't an interactive UX case
+        sendBroadcastAsUser(intent, widget.provider.id.getProfile(), false);
     }
 
     private void sendDisabledIntentLocked(Provider provider) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
         intent.setComponent(provider.id.componentName);
-        sendBroadcastAsUser(intent, provider.id.getProfile());
+        // Cleanup after disable isn't an interactive UX case
+        sendBroadcastAsUser(intent, provider.id.getProfile(), false);
     }
 
     public void sendOptionsChangedIntentLocked(Widget widget) {
@@ -2413,7 +2429,9 @@
         intent.setComponent(widget.provider.id.componentName);
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widget.appWidgetId);
         intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, widget.options);
-        sendBroadcastAsUser(intent, widget.provider.id.getProfile());
+        // The user's changed the options, so seeing them take effect promptly is
+        // an interactive UX expectation
+        sendBroadcastAsUser(intent, widget.provider.id.getProfile(), true);
     }
 
     @GuardedBy("mLock")
@@ -3666,10 +3684,17 @@
         return null;
     }
 
-    private void sendBroadcastAsUser(Intent intent, UserHandle userHandle) {
+    /**
+     * Sends a widget lifecycle broadcast within the specified user.  If {@code isInteractive}
+     * is specified as {@code true}, the broadcast dispatch mechanism will be told that it
+     * is related to a UX flow with user-visible expectations about timely dispatch.  This
+     * should only be used for broadcast flows that do have such expectations.
+     */
+    private void sendBroadcastAsUser(Intent intent, UserHandle userHandle, boolean isInteractive) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            mContext.sendBroadcastAsUser(intent, userHandle);
+            mContext.sendBroadcastAsUser(intent, userHandle, null,
+                    isInteractive ? mInteractiveBroadcast : null);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -5008,18 +5033,20 @@
 
         private void sendWidgetRestoreBroadcastLocked(String action, Provider provider,
                 Host host, int[] oldIds, int[] newIds, UserHandle userHandle) {
+            // Users expect restore to emplace widgets properly ASAP, so flag these as
+            // being interactive broadcast dispatches
             Intent intent = new Intent(action);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OLD_IDS, oldIds);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, newIds);
             if (provider != null) {
                 intent.setComponent(provider.id.componentName);
-                sendBroadcastAsUser(intent, userHandle);
+                sendBroadcastAsUser(intent, userHandle, true);
             }
             if (host != null) {
                 intent.setComponent(null);
                 intent.setPackage(host.id.packageName);
                 intent.putExtra(AppWidgetManager.EXTRA_HOST_ID, host.id.hostId);
-                sendBroadcastAsUser(intent, userHandle);
+                sendBroadcastAsUser(intent, userHandle, true);
             }
         }
 
diff --git a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
index 0fe90b1..f5d6836 100644
--- a/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/KeyValueAdbBackupEngine.java
@@ -9,7 +9,7 @@
 
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
-import android.app.backup.BackupManager;
+import android.app.backup.BackupAnnotations;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.IBackupCallback;
@@ -148,7 +148,7 @@
         try {
             return mBackupManagerService.bindToAgentSynchronous(targetApp,
                     ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
-                    BackupManager.OperationType.BACKUP);
+                    BackupAnnotations.BackupDestination.CLOUD);
         } catch (SecurityException e) {
             Slog.e(TAG, "error in binding to agent for package " + targetApp.packageName
                     + ". " + e);
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 4cf63b3..ce3e628 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -46,8 +46,8 @@
 import android.app.IBackupAgent;
 import android.app.PendingIntent;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
 import android.app.backup.BackupManagerMonitor;
 import android.app.backup.FullBackup;
 import android.app.backup.IBackupManager;
@@ -405,7 +405,7 @@
     private long mAncestralToken = 0;
     private long mCurrentToken = 0;
     @Nullable private File mAncestralSerialNumberFile;
-    @OperationType private volatile long mAncestralOperationType;
+    @BackupDestination private volatile long mAncestralBackupDestination;
 
     private final ContentObserver mSetupObserver;
     private final BroadcastReceiver mRunInitReceiver;
@@ -550,7 +550,7 @@
         mActivityManager = ActivityManager.getService();
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mScheduledBackupEligibility = getEligibilityRules(mPackageManager, userId,
-                OperationType.BACKUP);
+                BackupDestination.CLOUD);
 
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
@@ -844,8 +844,8 @@
         mAncestralToken = ancestralToken;
     }
 
-    public void setAncestralOperationType(@OperationType int operationType) {
-        mAncestralOperationType = operationType;
+    public void setAncestralBackupDestination(@BackupDestination int backupDestination) {
+        mAncestralBackupDestination = backupDestination;
     }
 
     public long getCurrentToken() {
@@ -1619,14 +1619,14 @@
     /** Fires off a backup agent, blocking until it attaches or times out. */
     @Nullable
     public IBackupAgent bindToAgentSynchronous(ApplicationInfo app, int mode,
-            @OperationType int operationType) {
+            @BackupDestination int backupDestination) {
         IBackupAgent agent = null;
         synchronized (mAgentConnectLock) {
             mConnecting = true;
             mConnectedAgent = null;
             try {
                 if (mActivityManager.bindBackupAgent(app.packageName, mode, mUserId,
-                        operationType)) {
+                        backupDestination)) {
                     Slog.d(TAG, addUserIdToLogMessage(mUserId, "awaiting agent for " + app));
 
                     // success; wait for the agent to arrive
@@ -1776,8 +1776,9 @@
     }
 
     private BackupEligibilityRules getEligibilityRulesForRestoreAtInstall(long restoreToken) {
-        if (mAncestralOperationType == OperationType.MIGRATION && restoreToken == mAncestralToken) {
-            return getEligibilityRulesForOperation(OperationType.MIGRATION);
+        if (mAncestralBackupDestination == BackupDestination.DEVICE_TRANSFER
+                && restoreToken == mAncestralToken) {
+            return getEligibilityRulesForOperation(BackupDestination.DEVICE_TRANSFER);
         } else {
             // If we're not using the ancestral data set, it means we're restoring from a backup
             // that happened on this device.
@@ -1856,14 +1857,14 @@
 
         final TransportConnection transportConnection;
         final String transportDirName;
-        int operationType;
+        int backupDestination;
         try {
             transportDirName =
                     mTransportManager.getTransportDirName(
                             mTransportManager.getCurrentTransportName());
             transportConnection =
                     mTransportManager.getCurrentTransportClientOrThrow("BMS.requestBackup()");
-            operationType = getOperationTypeFromTransport(transportConnection);
+            backupDestination = getBackupDestinationFromTransport(transportConnection);
         } catch (TransportNotRegisteredException | TransportNotAvailableException
                 | RemoteException e) {
             BackupObserverUtils.sendBackupFinished(observer, BackupManager.ERROR_TRANSPORT_ABORTED);
@@ -1876,7 +1877,7 @@
         OnTaskFinishedListener listener =
                 caller -> mTransportManager.disposeOfTransportClient(transportConnection, caller);
         BackupEligibilityRules backupEligibilityRules = getEligibilityRulesForOperation(
-                operationType);
+                backupDestination);
 
         Message msg = mBackupHandler.obtainMessage(MSG_REQUEST_BACKUP);
         msg.obj = getRequestBackupParams(packages, observer, monitor, flags, backupEligibilityRules,
@@ -2373,7 +2374,7 @@
                             /* monitor */ null,
                             /* userInitiated */ false,
                             "BMS.beginFullBackup()",
-                            getEligibilityRulesForOperation(OperationType.BACKUP));
+                            getEligibilityRulesForOperation(BackupDestination.CLOUD));
                 } catch (IllegalStateException e) {
                     Slog.w(TAG, "Failed to start backup", e);
                     runBackup = false;
@@ -2835,7 +2836,7 @@
             Slog.i(TAG, addUserIdToLogMessage(mUserId, "Beginning adb backup..."));
 
             BackupEligibilityRules eligibilityRules = getEligibilityRulesForOperation(
-                    OperationType.ADB_BACKUP);
+                    BackupDestination.ADB_BACKUP);
             AdbBackupParams params = new AdbBackupParams(fd, includeApks, includeObbs,
                     includeShared, doWidgets, doAllApps, includeSystem, compress, doKeyValue,
                     pkgList, eligibilityRules);
@@ -2924,7 +2925,7 @@
                         /* monitor */ null,
                         /* userInitiated */ false,
                         "BMS.fullTransportBackup()",
-                        getEligibilityRulesForOperation(OperationType.BACKUP));
+                        getEligibilityRulesForOperation(BackupDestination.CLOUD));
                 // Acquiring wakelock for PerformFullTransportBackupTask before its start.
                 mWakelock.acquire();
                 (new Thread(task, "full-transport-master")).start();
@@ -3917,12 +3918,12 @@
             }
         }
 
-        int operationType;
+        int backupDestination;
         TransportConnection transportConnection = null;
         try {
             transportConnection = mTransportManager.getTransportClientOrThrow(
                     transport, /* caller */"BMS.beginRestoreSession");
-            operationType = getOperationTypeFromTransport(transportConnection);
+            backupDestination = getBackupDestinationFromTransport(transportConnection);
         } catch (TransportNotAvailableException | TransportNotRegisteredException
                 | RemoteException e) {
             Slog.w(TAG, "Failed to get operation type from transport: " + e);
@@ -3951,7 +3952,7 @@
                 return null;
             }
             mActiveRestoreSession = new ActiveRestoreSession(this, packageName, transport,
-                    getEligibilityRulesForOperation(operationType));
+                    getEligibilityRulesForOperation(backupDestination));
             mBackupHandler.sendEmptyMessageDelayed(MSG_RESTORE_SESSION_TIMEOUT,
                     mAgentTimeoutParameters.getRestoreSessionTimeoutMillis());
         }
@@ -4037,14 +4038,14 @@
     }
 
     public BackupEligibilityRules getEligibilityRulesForOperation(
-            @OperationType int operationType) {
-        return getEligibilityRules(mPackageManager, mUserId, operationType);
+            @BackupDestination int backupDestination) {
+        return getEligibilityRules(mPackageManager, mUserId, backupDestination);
     }
 
     private static BackupEligibilityRules getEligibilityRules(PackageManager packageManager,
-            int userId, @OperationType int operationType) {
+            int userId, @BackupDestination int backupDestination) {
         return new BackupEligibilityRules(packageManager,
-                LocalServices.getService(PackageManagerInternal.class), userId, operationType);
+                LocalServices.getService(PackageManagerInternal.class), userId, backupDestination);
     }
 
     /** Prints service state for 'dumpsys backup'. */
@@ -4200,21 +4201,22 @@
     }
 
     @VisibleForTesting
-    @OperationType int getOperationTypeFromTransport(TransportConnection transportConnection)
+    @BackupDestination int getBackupDestinationFromTransport(
+            TransportConnection transportConnection)
             throws TransportNotAvailableException, RemoteException {
         if (!shouldUseNewBackupEligibilityRules()) {
             // Return the default to stick to the legacy behaviour.
-            return OperationType.BACKUP;
+            return BackupDestination.CLOUD;
         }
 
         final long oldCallingId = Binder.clearCallingIdentity();
         try {
             BackupTransportClient transport = transportConnection.connectOrThrow(
-                    /* caller */ "BMS.getOperationTypeFromTransport");
+                    /* caller */ "BMS.getBackupDestinationFromTransport");
             if ((transport.getTransportFlags() & BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER) != 0) {
-                return OperationType.MIGRATION;
+                return BackupDestination.DEVICE_TRANSFER;
             } else {
-                return OperationType.BACKUP;
+                return BackupDestination.CLOUD;
             }
         } finally {
             Binder.restoreCallingIdentity(oldCallingId);
diff --git a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
index 379ae52..65682f4 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/FullBackupEngine.java
@@ -315,7 +315,7 @@
             mAgent =
                     backupManagerService.bindToAgentSynchronous(
                             mPkg.applicationInfo, ApplicationThreadConstants.BACKUP_MODE_FULL,
-                            mBackupEligibilityRules.getOperationType());
+                            mBackupEligibilityRules.getBackupDestination());
         }
         return mAgent != null;
     }
diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
index 95cc289..3ff6ba7 100644
--- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java
+++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java
@@ -20,7 +20,7 @@
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.BackupManagerService.TAG;
 
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.RestoreSet;
 import android.os.Handler;
@@ -240,7 +240,7 @@
                                 /* userInitiated */ false,
                                 /* nonIncremental */ false,
                                 backupManagerService.getEligibilityRulesForOperation(
-                                        OperationType.BACKUP));
+                                        BackupDestination.CLOUD));
                     } catch (Exception e) {
                         // unable to ask the transport its dir name -- transient failure, since
                         // the above check succeeded.  Try again next time.
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index fd9c834..ca92b69 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -741,7 +741,7 @@
             agent =
                     mBackupManagerService.bindToAgentSynchronous(
                             packageInfo.applicationInfo, BACKUP_MODE_INCREMENTAL,
-                            mBackupEligibilityRules.getOperationType());
+                            mBackupEligibilityRules.getBackupDestination());
             if (agent == null) {
                 mReporter.onAgentError(packageName);
                 throw AgentException.transitory();
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 8b1d561..d3e4f13 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -16,8 +16,6 @@
 
 package com.android.server.backup.restore;
 
-import static android.app.backup.BackupManager.OperationType;
-
 import static com.android.server.backup.BackupManagerService.DEBUG;
 import static com.android.server.backup.BackupManagerService.MORE_DEBUG;
 import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT;
@@ -26,6 +24,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IRestoreObserver;
 import android.app.backup.IRestoreSession;
@@ -299,9 +298,9 @@
     private BackupEligibilityRules getBackupEligibilityRules(RestoreSet restoreSet) {
         // TODO(b/182986784): Remove device name comparison once a designated field for operation
         //  type is added to RestoreSet object.
-        int operationType = DEVICE_NAME_FOR_D2D_SET.equals(restoreSet.device)
-                ? OperationType.MIGRATION : OperationType.BACKUP;
-        return mBackupManagerService.getEligibilityRulesForOperation(operationType);
+        int backupDestination = DEVICE_NAME_FOR_D2D_SET.equals(restoreSet.device)
+                ? BackupDestination.DEVICE_TRANSFER : BackupDestination.CLOUD;
+        return mBackupManagerService.getEligibilityRulesForOperation(backupDestination);
     }
 
     public synchronized int restorePackage(String packageName, IRestoreObserver observer,
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index e78c8d1..b042c30 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -28,6 +28,7 @@
 import android.app.ApplicationThreadConstants;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupManager;
 import android.app.backup.FullBackup;
 import android.app.backup.IBackupManagerMonitor;
@@ -398,7 +399,7 @@
                                     FullBackup.KEY_VALUE_DATA_TOKEN.equals(info.domain)
                                             ? ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL
                                             : ApplicationThreadConstants.BACKUP_MODE_RESTORE_FULL,
-                                    mBackupEligibilityRules.getOperationType());
+                                    mBackupEligibilityRules.getBackupDestination());
                             mAgentPackage = pkg;
                         } catch (IOException | NameNotFoundException e) {
                             // fall through to error handling
@@ -707,7 +708,8 @@
     }
 
     private boolean isRestorableFile(FileMetadata info) {
-        if (mBackupEligibilityRules.getOperationType() == BackupManager.OperationType.MIGRATION) {
+        if (mBackupEligibilityRules.getBackupDestination()
+                == BackupAnnotations.BackupDestination.DEVICE_TRANSFER) {
             // Everything is eligible for device-to-device migration.
             return true;
         }
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index 22af19e..515a172 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -24,7 +24,7 @@
 import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_HEADER_MAGIC;
 import static com.android.server.backup.UserBackupManagerService.BACKUP_FILE_VERSION;
 
-import android.app.backup.BackupManager;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.content.pm.PackageManagerInternal;
 import android.os.ParcelFileDescriptor;
@@ -112,7 +112,7 @@
             BackupEligibilityRules eligibilityRules = new BackupEligibilityRules(
                     mBackupManagerService.getPackageManager(),
                     LocalServices.getService(PackageManagerInternal.class),
-                    mBackupManagerService.getUserId(), BackupManager.OperationType.ADB_BACKUP);
+                    mBackupManagerService.getUserId(), BackupDestination.ADB_BACKUP);
             FullRestoreEngine mEngine = new FullRestoreEngine(mBackupManagerService,
                     mOperationStorage, null, mObserver, null, null,
                     true, 0 /*unused*/, true, eligibilityRules);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 9f89339..18e28de 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -675,7 +675,7 @@
         mAgent = backupManagerService.bindToAgentSynchronous(
                 mCurrentPackage.applicationInfo,
                 ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL,
-                mBackupEligibilityRules.getOperationType());
+                mBackupEligibilityRules.getBackupDestination());
         if (mAgent == null) {
             Slog.w(TAG, "Can't find backup agent for " + packageName);
             mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
@@ -1160,8 +1160,8 @@
         if (mIsSystemRestore && mPmAgent != null) {
             backupManagerService.setAncestralPackages(mPmAgent.getRestoredPackages());
             backupManagerService.setAncestralToken(mToken);
-            backupManagerService.setAncestralOperationType(
-                    mBackupEligibilityRules.getOperationType());
+            backupManagerService.setAncestralBackupDestination(
+                    mBackupEligibilityRules.getBackupDestination());
             backupManagerService.writeRestoreTokens();
         }
 
diff --git a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
index d0300ff..7f0b56f 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupEligibilityRules.java
@@ -23,7 +23,7 @@
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.BackupTransport;
 import android.app.compat.CompatChanges;
 import android.compat.annotation.ChangeId;
@@ -61,7 +61,7 @@
     private final PackageManager mPackageManager;
     private final PackageManagerInternal mPackageManagerInternal;
     private final int mUserId;
-    @OperationType  private final int mOperationType;
+    @BackupDestination  private final int mBackupDestination;
 
     /**
      * When  this change is enabled, {@code adb backup}  is automatically turned on for apps
@@ -85,17 +85,17 @@
             PackageManagerInternal packageManagerInternal,
             int userId) {
         return new BackupEligibilityRules(packageManager, packageManagerInternal, userId,
-                OperationType.BACKUP);
+                BackupDestination.CLOUD);
     }
 
     public BackupEligibilityRules(PackageManager packageManager,
             PackageManagerInternal packageManagerInternal,
             int userId,
-            @OperationType int operationType) {
+            @BackupDestination int backupDestination) {
         mPackageManager = packageManager;
         mPackageManagerInternal = packageManagerInternal;
         mUserId = userId;
-        mOperationType = operationType;
+        mBackupDestination = backupDestination;
     }
 
     /**
@@ -111,7 +111,7 @@
      * </ol>
      *
      * However, the above eligibility rules are ignored for non-system apps in in case of
-     * device-to-device migration, see {@link OperationType}.
+     * device-to-device migration, see {@link BackupDestination}.
      */
     @VisibleForTesting
     public boolean appIsEligibleForBackup(ApplicationInfo app) {
@@ -152,22 +152,22 @@
     /**
     * Check if this app allows backup. Apps can opt out of backup by stating
     * android:allowBackup="false" in their manifest. However, this flag is ignored for non-system
-    * apps during device-to-device migrations, see {@link OperationType}.
+    * apps during device-to-device migrations, see {@link BackupDestination}.
     *
     * @param app The app under check.
     * @return boolean indicating whether backup is allowed.
     */
     public boolean isAppBackupAllowed(ApplicationInfo app) {
         boolean allowBackup = (app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;
-        switch (mOperationType) {
-            case OperationType.MIGRATION:
+        switch (mBackupDestination) {
+            case BackupDestination.DEVICE_TRANSFER:
                 // Backup / restore of all non-system apps is force allowed during
                 // device-to-device migration.
                 boolean isSystemApp = (app.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 boolean ignoreAllowBackup = !isSystemApp && CompatChanges.isChangeEnabled(
                         IGNORE_ALLOW_BACKUP_IN_D2D, app.packageName, UserHandle.of(mUserId));
                 return ignoreAllowBackup || allowBackup;
-            case OperationType.ADB_BACKUP:
+            case BackupDestination.ADB_BACKUP:
                 String packageName = app.packageName;
                 if (packageName == null) {
                     Slog.w(TAG, "Invalid ApplicationInfo object");
@@ -207,10 +207,10 @@
                     // All other apps can use adb backup only when running in debuggable mode.
                     return isDebuggable;
                 }
-            case OperationType.BACKUP:
+            case BackupDestination.CLOUD:
                 return allowBackup;
             default:
-                Slog.w(TAG, "Unknown operation type:" + mOperationType);
+                Slog.w(TAG, "Unknown operation type:" + mBackupDestination);
                 return false;
         }
     }
@@ -398,7 +398,7 @@
         }
     }
 
-    public int getOperationType() {
-        return mOperationType;
+    public int getBackupDestination() {
+        return mBackupDestination;
     }
 }
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index ce7854d..f1ba5ff 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -130,6 +130,7 @@
     @Nullable
     private final @AssociationRequest.DeviceProfile String mDeviceProfile;
     @Nullable private final SecureWindowCallback mSecureWindowCallback;
+    @Nullable private final List<String> mDisplayCategories;
 
     /**
      * Creates a window policy controller that is generic to the different use cases of virtual
@@ -168,7 +169,8 @@
             @NonNull PipBlockedCallback pipBlockedCallback,
             @NonNull ActivityBlockedCallback activityBlockedCallback,
             @NonNull SecureWindowCallback secureWindowCallback,
-            @AssociationRequest.DeviceProfile String deviceProfile) {
+            @AssociationRequest.DeviceProfile String deviceProfile,
+            @NonNull List<String> displayCategories) {
         super();
         mAllowedUsers = allowedUsers;
         mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
@@ -182,6 +184,7 @@
         mDeviceProfile = deviceProfile;
         mPipBlockedCallback = pipBlockedCallback;
         mSecureWindowCallback = secureWindowCallback;
+        mDisplayCategories = displayCategories;
     }
 
     /**
@@ -319,7 +322,7 @@
         if (mDeviceProfile == null) {
             return true;
         }
-       // TODO(b/234075973) : Remove this once proper API is ready.
+        // TODO(b/234075973) : Remove this once proper API is ready.
         switch (mDeviceProfile) {
             case DEVICE_PROFILE_AUTOMOTIVE_PROJECTION:
                 return false;
@@ -350,6 +353,15 @@
         }
     }
 
+    private boolean activityMatchesDisplayCategory(ActivityInfo activityInfo) {
+        if (mDisplayCategories.isEmpty()) {
+            return activityInfo.requiredDisplayCategory == null;
+        }
+        return activityInfo.requiredDisplayCategory != null
+                    && mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
+
+    }
+
     private boolean canContainActivity(ActivityInfo activityInfo, int windowFlags,
             int systemWindowFlags) {
         if ((activityInfo.flags & FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES) == 0) {
@@ -357,9 +369,17 @@
         }
         ComponentName activityComponent = activityInfo.getComponentName();
         if (BLOCKED_APP_STREAMING_COMPONENT.equals(activityComponent)) {
-            // The error dialog alerting users that streaming is blocked is always allowed.
+            // The error dialog alerting users that streaming is blocked is always allowed. Need to
+            // run before the clauses below to ensure error dialog always shows up.
             return true;
         }
+        if (!activityMatchesDisplayCategory(activityInfo)) {
+            Slog.d(TAG, String.format(
+                    "The activity's required display category: %s is not found on virtual display"
+                            + " with the following categories: %s",
+                    activityInfo.requiredDisplayCategory, mDisplayCategories.toString()));
+            return false;
+        }
         final UserHandle activityUser =
                 UserHandle.getUserHandleForUid(activityInfo.applicationInfo.uid);
         if (!mAllowedUsers.contains(activityUser)) {
diff --git a/services/companion/java/com/android/server/companion/virtual/InputController.java b/services/companion/java/com/android/server/companion/virtual/InputController.java
index 02053cc..96c71e5 100644
--- a/services/companion/java/com/android/server/companion/virtual/InputController.java
+++ b/services/companion/java/com/android/server/companion/virtual/InputController.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.StringDef;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.InputDeviceIdentifier;
@@ -178,13 +177,14 @@
             int productId,
             @NonNull IBinder deviceToken,
             int displayId,
-            @NonNull Point screenSize) {
+            int height,
+            int width) {
         final String phys = createPhys(PHYS_TYPE_TOUCHSCREEN);
         try {
             createDeviceInternal(InputDeviceDescriptor.TYPE_TOUCHSCREEN, deviceName, vendorId,
                     productId, deviceToken, displayId, phys,
                     () -> mNativeWrapper.openUinputTouchscreen(deviceName, vendorId, productId,
-                            phys, screenSize.y, screenSize.x));
+                            phys, height, width));
         } catch (DeviceCreationException e) {
             throw new RuntimeException(
                     "Failed to create virtual touchscreen device '" + deviceName + "'.", e);
@@ -414,17 +414,25 @@
     }
 
     @VisibleForTesting
-    void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId,
-            String phys, int inputDeviceId) {
+    void addDeviceForTesting(IBinder deviceToken, int fd, int type, int displayId, String phys,
+            int inputDeviceId) {
         synchronized (mLock) {
-            mInputDeviceDescriptors.put(deviceToken,
-                    new InputDeviceDescriptor(fd, () -> {}, type, displayId, phys,
-                            inputDeviceId));
+            mInputDeviceDescriptors.put(deviceToken, new InputDeviceDescriptor(fd, () -> {
+            }, type, displayId, phys, inputDeviceId));
         }
     }
 
-    private static native int nativeOpenUinputDpad(String deviceName, int vendorId,
-            int productId, String phys);
+    @VisibleForTesting
+    Map<IBinder, InputDeviceDescriptor> getInputDeviceDescriptors() {
+        final Map<IBinder, InputDeviceDescriptor> inputDeviceDescriptors = new ArrayMap<>();
+        synchronized (mLock) {
+            inputDeviceDescriptors.putAll(mInputDeviceDescriptors);
+        }
+        return inputDeviceDescriptors;
+    }
+
+    private static native int nativeOpenUinputDpad(String deviceName, int vendorId, int productId,
+            String phys);
     private static native int nativeOpenUinputKeyboard(String deviceName, int vendorId,
             int productId, String phys);
     private static native int nativeOpenUinputMouse(String deviceName, int vendorId, int productId,
diff --git a/services/companion/java/com/android/server/companion/virtual/SensorController.java b/services/companion/java/com/android/server/companion/virtual/SensorController.java
new file mode 100644
index 0000000..ec7e993
--- /dev/null
+++ b/services/companion/java/com/android/server/companion/virtual/SensorController.java
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual;
+
+import android.annotation.NonNull;
+import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
+import android.companion.virtual.sensor.VirtualSensorConfig;
+import android.companion.virtual.sensor.VirtualSensorEvent;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
+import com.android.server.sensors.SensorManagerInternal;
+
+import java.io.PrintWriter;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Objects;
+
+/** Controls virtual sensors, including their lifecycle and sensor event dispatch. */
+public class SensorController {
+
+    private static final String TAG = "SensorController";
+
+    private final Object mLock;
+    private final int mVirtualDeviceId;
+    @GuardedBy("mLock")
+    private final Map<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
+
+    private final SensorManagerInternal mSensorManagerInternal;
+
+    public SensorController(@NonNull Object lock, int virtualDeviceId) {
+        mLock = lock;
+        mVirtualDeviceId = virtualDeviceId;
+        mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
+    }
+
+    void close() {
+        synchronized (mLock) {
+            final Iterator<Map.Entry<IBinder, SensorDescriptor>> iterator =
+                    mSensorDescriptors.entrySet().iterator();
+            if (iterator.hasNext()) {
+                final Map.Entry<IBinder, SensorDescriptor> entry = iterator.next();
+                final IBinder token = entry.getKey();
+                final SensorDescriptor sensorDescriptor = entry.getValue();
+                iterator.remove();
+                closeSensorDescriptorLocked(token, sensorDescriptor);
+            }
+        }
+    }
+
+    void createSensor(@NonNull IBinder deviceToken, @NonNull VirtualSensorConfig config) {
+        Objects.requireNonNull(deviceToken);
+        Objects.requireNonNull(config);
+        try {
+            createSensorInternal(deviceToken, config);
+        } catch (SensorCreationException e) {
+            throw new RuntimeException(
+                    "Failed to create virtual sensor '" + config.getName() + "'.", e);
+        }
+    }
+
+    private void createSensorInternal(IBinder deviceToken, VirtualSensorConfig config)
+            throws SensorCreationException {
+        final SensorManagerInternal.RuntimeSensorStateChangeCallback runtimeSensorCallback =
+                (enabled, samplingPeriodMicros, batchReportLatencyMicros) -> {
+                    IVirtualSensorStateChangeCallback callback = config.getStateChangeCallback();
+                    if (callback != null) {
+                        try {
+                            callback.onStateChanged(
+                                    enabled, samplingPeriodMicros, batchReportLatencyMicros);
+                        } catch (RemoteException e) {
+                            throw new RuntimeException("Failed to call sensor callback.", e);
+                        }
+                    }
+                };
+
+        final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
+                config.getType(), config.getName(),
+                config.getVendor() == null ? "" : config.getVendor(),
+                runtimeSensorCallback);
+        if (handle <= 0) {
+            throw new SensorCreationException("Received an invalid virtual sensor handle.");
+        }
+
+        // The handle is valid from here, so ensure that all failures clean it up.
+        final BinderDeathRecipient binderDeathRecipient;
+        try {
+            binderDeathRecipient = new BinderDeathRecipient(deviceToken);
+            deviceToken.linkToDeath(binderDeathRecipient, /* flags= */ 0);
+        } catch (RemoteException e) {
+            mSensorManagerInternal.removeRuntimeSensor(handle);
+            throw new SensorCreationException("Client died before sensor could be created.", e);
+        }
+
+        synchronized (mLock) {
+            SensorDescriptor sensorDescriptor = new SensorDescriptor(
+                    handle, config.getType(), config.getName(), binderDeathRecipient);
+            mSensorDescriptors.put(deviceToken, sensorDescriptor);
+        }
+    }
+
+    boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
+        Objects.requireNonNull(token);
+        Objects.requireNonNull(event);
+        synchronized (mLock) {
+            final SensorDescriptor sensorDescriptor = mSensorDescriptors.get(token);
+            if (sensorDescriptor == null) {
+                throw new IllegalArgumentException("Could not send sensor event for given token");
+            }
+            return mSensorManagerInternal.sendSensorEvent(
+                    sensorDescriptor.getHandle(), sensorDescriptor.getType(),
+                    event.getTimestampNanos(), event.getValues());
+        }
+    }
+
+    void unregisterSensor(@NonNull IBinder token) {
+        Objects.requireNonNull(token);
+        synchronized (mLock) {
+            final SensorDescriptor sensorDescriptor = mSensorDescriptors.remove(token);
+            if (sensorDescriptor == null) {
+                throw new IllegalArgumentException("Could not unregister sensor for given token");
+            }
+            closeSensorDescriptorLocked(token, sensorDescriptor);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void closeSensorDescriptorLocked(IBinder token, SensorDescriptor sensorDescriptor) {
+        token.unlinkToDeath(sensorDescriptor.getDeathRecipient(), /* flags= */ 0);
+        final int handle = sensorDescriptor.getHandle();
+        mSensorManagerInternal.removeRuntimeSensor(handle);
+    }
+
+
+    void dump(@NonNull PrintWriter fout) {
+        fout.println("    SensorController: ");
+        synchronized (mLock) {
+            fout.println("      Active descriptors: ");
+            for (SensorDescriptor sensorDescriptor : mSensorDescriptors.values()) {
+                fout.println("        handle: " + sensorDescriptor.getHandle());
+                fout.println("          type: " + sensorDescriptor.getType());
+                fout.println("          name: " + sensorDescriptor.getName());
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void addSensorForTesting(IBinder deviceToken, int handle, int type, String name) {
+        synchronized (mLock) {
+            mSensorDescriptors.put(deviceToken,
+                    new SensorDescriptor(handle, type, name, () -> {}));
+        }
+    }
+
+    @VisibleForTesting
+    Map<IBinder, SensorDescriptor> getSensorDescriptors() {
+        synchronized (mLock) {
+            return mSensorDescriptors;
+        }
+    }
+
+    @VisibleForTesting
+    static final class SensorDescriptor {
+
+        private final int mHandle;
+        private final IBinder.DeathRecipient mDeathRecipient;
+        private final int mType;
+        private final String mName;
+
+        SensorDescriptor(int handle, int type, String name, IBinder.DeathRecipient deathRecipient) {
+            mHandle = handle;
+            mDeathRecipient = deathRecipient;
+            mType = type;
+            mName = name;
+        }
+        public int getHandle() {
+            return mHandle;
+        }
+        public int getType() {
+            return mType;
+        }
+        public String getName() {
+            return mName;
+        }
+        public IBinder.DeathRecipient getDeathRecipient() {
+            return mDeathRecipient;
+        }
+    }
+
+    private final class BinderDeathRecipient implements IBinder.DeathRecipient {
+        private final IBinder mDeviceToken;
+
+        BinderDeathRecipient(IBinder deviceToken) {
+            mDeviceToken = deviceToken;
+        }
+
+        @Override
+        public void binderDied() {
+            // All callers are expected to call {@link VirtualDevice#unregisterSensor} before
+            // quitting, which removes this death recipient. If this is invoked, the remote end
+            // died, or they disposed of the object without properly unregistering.
+            Slog.e(TAG, "Virtual sensor controller binder died");
+            unregisterSensor(mDeviceToken);
+        }
+    }
+
+    /** An internal exception that is thrown to indicate an error when opening a virtual sensor. */
+    private static class SensorCreationException extends Exception {
+        SensorCreationException(String message) {
+            super(message);
+        }
+        SensorCreationException(String message, Exception cause) {
+            super(message, cause);
+        }
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index d83c80f..ef93810 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -38,18 +38,23 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.sensor.VirtualSensorConfig;
+import android.companion.virtual.sensor.VirtualSensorEvent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
-import android.graphics.Point;
 import android.graphics.PointF;
 import android.hardware.display.DisplayManager;
+import android.hardware.input.VirtualDpadConfig;
 import android.hardware.input.VirtualKeyEvent;
+import android.hardware.input.VirtualKeyboardConfig;
 import android.hardware.input.VirtualMouseButtonEvent;
+import android.hardware.input.VirtualMouseConfig;
 import android.hardware.input.VirtualMouseRelativeEvent;
 import android.hardware.input.VirtualMouseScrollEvent;
 import android.hardware.input.VirtualTouchEvent;
+import android.hardware.input.VirtualTouchscreenConfig;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Looper;
@@ -74,7 +79,9 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
 
@@ -97,6 +104,7 @@
     private final int mOwnerUid;
     private final int mDeviceId;
     private final InputController mInputController;
+    private final SensorController mSensorController;
     private VirtualAudioController mVirtualAudioController;
     @VisibleForTesting
     final Set<Integer> mVirtualDisplayIds = new ArraySet<>();
@@ -159,6 +167,7 @@
                 ownerUid,
                 deviceId,
                 /* inputController= */ null,
+                /* sensorController= */ null,
                 listener,
                 pendingTrampolineCallback,
                 activityListener,
@@ -174,6 +183,7 @@
             int ownerUid,
             int deviceId,
             InputController inputController,
+            SensorController sensorController,
             OnDeviceCloseListener listener,
             PendingTrampolineCallback pendingTrampolineCallback,
             IVirtualDeviceActivityListener activityListener,
@@ -197,6 +207,11 @@
         } else {
             mInputController = inputController;
         }
+        if (sensorController == null) {
+            mSensorController = new SensorController(mVirtualDeviceLock, mDeviceId);
+        } else {
+            mSensorController = sensorController;
+        }
         mListener = listener;
         try {
             token.linkToDeath(this, 0);
@@ -318,11 +333,12 @@
         mListener.onClose(mAssociationInfo.getId());
         mAppToken.unlinkToDeath(this, 0);
 
-        final long token = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             mInputController.close();
+            mSensorController.close();
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -384,115 +400,93 @@
         }
     }
 
-    @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
     @Override // Binder call
-    public void createVirtualDpad(
-            int displayId,
-            @NonNull String deviceName,
-            int vendorId,
-            int productId,
-            @NonNull IBinder deviceToken) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+    public void createVirtualDpad(VirtualDpadConfig config, @NonNull IBinder deviceToken) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to create a virtual dpad");
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplayIds.contains(displayId)) {
+            if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
                 throw new SecurityException(
                         "Cannot create a virtual dpad for a display not associated with "
                                 + "this virtual device");
             }
         }
-        final long token = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            mInputController.createDpad(deviceName, vendorId, productId, deviceToken,
-                    displayId);
+            mInputController.createDpad(config.getInputDeviceName(), config.getVendorId(),
+                    config.getProductId(), deviceToken, config.getAssociatedDisplayId());
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
-    public void createVirtualKeyboard(
-            int displayId,
-            @NonNull String deviceName,
-            int vendorId,
-            int productId,
-            @NonNull IBinder deviceToken) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+    public void createVirtualKeyboard(VirtualKeyboardConfig config, @NonNull IBinder deviceToken) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to create a virtual keyboard");
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplayIds.contains(displayId)) {
+            if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
                 throw new SecurityException(
                         "Cannot create a virtual keyboard for a display not associated with "
                                 + "this virtual device");
             }
         }
-        final long token = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            mInputController.createKeyboard(deviceName, vendorId, productId, deviceToken,
-                    displayId);
+            mInputController.createKeyboard(config.getInputDeviceName(), config.getVendorId(),
+                    config.getProductId(), deviceToken, config.getAssociatedDisplayId());
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
-    public void createVirtualMouse(
-            int displayId,
-            @NonNull String deviceName,
-            int vendorId,
-            int productId,
-            @NonNull IBinder deviceToken) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+    public void createVirtualMouse(VirtualMouseConfig config, @NonNull IBinder deviceToken) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to create a virtual mouse");
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplayIds.contains(displayId)) {
+            if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
                 throw new SecurityException(
                         "Cannot create a virtual mouse for a display not associated with this "
                                 + "virtual device");
             }
         }
-        final long token = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            mInputController.createMouse(deviceName, vendorId, productId, deviceToken, displayId);
+            mInputController.createMouse(config.getInputDeviceName(), config.getVendorId(),
+                    config.getProductId(), deviceToken, config.getAssociatedDisplayId());
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
-    public void createVirtualTouchscreen(
-            int displayId,
-            @NonNull String deviceName,
-            int vendorId,
-            int productId,
-            @NonNull IBinder deviceToken,
-            @NonNull Point screenSize) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+    public void createVirtualTouchscreen(VirtualTouchscreenConfig config,
+            @NonNull IBinder deviceToken) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to create a virtual touchscreen");
         synchronized (mVirtualDeviceLock) {
-            if (!mVirtualDisplayIds.contains(displayId)) {
+            if (!mVirtualDisplayIds.contains(config.getAssociatedDisplayId())) {
                 throw new SecurityException(
                         "Cannot create a virtual touchscreen for a display not associated with "
                                 + "this virtual device");
             }
         }
-
-        if (screenSize.x <= 0 || screenSize.y <= 0) {
+        int screenHeightPixels = config.getHeightInPixels();
+        int screenWidthPixels = config.getWidthInPixels();
+        if (screenHeightPixels <= 0 || screenWidthPixels <= 0) {
             throw new IllegalArgumentException(
                     "Cannot create a virtual touchscreen, screen dimensions must be positive. Got: "
-                            + screenSize);
+                            + "(" + screenWidthPixels + ", " + screenHeightPixels + ")");
         }
 
-        final long token = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            mInputController.createTouchscreen(deviceName, vendorId, productId,
-                    deviceToken, displayId, screenSize);
+            mInputController.createTouchscreen(config.getInputDeviceName(), config.getVendorId(),
+                    config.getProductId(), deviceToken, config.getAssociatedDisplayId(),
+                    screenHeightPixels, screenWidthPixels);
         } finally {
-            Binder.restoreCallingIdentity(token);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -502,92 +496,92 @@
                 android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to unregister this input device");
 
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             mInputController.unregisterInputDevice(token);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public int getInputDeviceId(IBinder token) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.getInputDeviceId(token);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
 
     @Override // Binder call
     public boolean sendDpadKeyEvent(IBinder token, VirtualKeyEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendDpadKeyEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public boolean sendKeyEvent(IBinder token, VirtualKeyEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendKeyEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public boolean sendButtonEvent(IBinder token, VirtualMouseButtonEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendButtonEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public boolean sendTouchEvent(IBinder token, VirtualTouchEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendTouchEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public boolean sendRelativeEvent(IBinder token, VirtualMouseRelativeEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendRelativeEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public boolean sendScrollEvent(IBinder token, VirtualMouseScrollEvent event) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.sendScrollEvent(token, event);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @Override // Binder call
     public PointF getCursorPosition(IBinder token) {
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             return mInputController.getCursorPosition(token);
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -597,7 +591,7 @@
                 android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
                 "Permission required to unregister this input device");
 
-        final long binderToken = Binder.clearCallingIdentity();
+        final long ident = Binder.clearCallingIdentity();
         try {
             synchronized (mVirtualDeviceLock) {
                 mDefaultShowPointerIcon = showPointerIcon;
@@ -606,7 +600,50 @@
                 }
             }
         } finally {
-            Binder.restoreCallingIdentity(binderToken);
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void createVirtualSensor(
+            @NonNull IBinder deviceToken,
+            @NonNull VirtualSensorConfig config) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+                "Permission required to create a virtual sensor");
+        Objects.requireNonNull(config);
+        Objects.requireNonNull(deviceToken);
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mSensorController.createSensor(deviceToken, config);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public void unregisterSensor(@NonNull IBinder token) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+                "Permission required to unregister a virtual sensor");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mSensorController.unregisterSensor(token);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override // Binder call
+    public boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CREATE_VIRTUAL_DEVICE,
+                "Permission required to send a virtual sensor event");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            return mSensorController.sendSensorEvent(token, event);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
@@ -623,9 +660,11 @@
             fout.println("    mDefaultShowPointerIcon: " + mDefaultShowPointerIcon);
         }
         mInputController.dump(fout);
+        mSensorController.dump(fout);
     }
 
-    GenericWindowPolicyController createWindowPolicyController() {
+    GenericWindowPolicyController createWindowPolicyController(
+            @NonNull List<String> displayCategories) {
         synchronized (mVirtualDeviceLock) {
             final GenericWindowPolicyController gwpc =
                     new GenericWindowPolicyController(FLAG_SECURE,
@@ -640,7 +679,8 @@
                             this::onEnteringPipBlocked,
                             this::onActivityBlocked,
                             this::onSecureWindowShown,
-                            mAssociationInfo.getDeviceProfile());
+                            mAssociationInfo.getDeviceProfile(),
+                            displayCategories);
             gwpc.registerRunningAppsChangedListener(/* listener= */ this);
             return gwpc;
         }
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index a8797a0..2b62f69 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -32,6 +32,7 @@
 import android.companion.virtual.VirtualDeviceManager;
 import android.companion.virtual.VirtualDeviceParams;
 import android.content.Context;
+import android.content.Intent;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
@@ -280,7 +281,22 @@
                             @Override
                             public void onClose(int associationId) {
                                 synchronized (mVirtualDeviceManagerLock) {
-                                    mVirtualDevices.remove(associationId);
+                                    VirtualDeviceImpl removedDevice =
+                                            mVirtualDevices.removeReturnOld(associationId);
+                                    if (removedDevice != null) {
+                                        Intent i = new Intent(
+                                                VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
+                                        i.putExtra(
+                                                VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID,
+                                                removedDevice.getDeviceId());
+                                        i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                                        final long identity = Binder.clearCallingIdentity();
+                                        try {
+                                            getContext().sendBroadcastAsUser(i, UserHandle.ALL);
+                                        } finally {
+                                            Binder.restoreCallingIdentity(identity);
+                                        }
+                                    }
                                     mAppsOnVirtualDevices.remove(associationId);
                                     if (cameraAccessController != null) {
                                         cameraAccessController.stopObservingIfNeeded();
@@ -332,7 +348,8 @@
             GenericWindowPolicyController gwpc;
             final long token = Binder.clearCallingIdentity();
             try {
-                gwpc = virtualDeviceImpl.createWindowPolicyController();
+                gwpc = virtualDeviceImpl.createWindowPolicyController(
+                    virtualDisplayConfig.getDisplayCategories());
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 544dd4e..6cd7ce8 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -73,6 +73,7 @@
 import java.util.Set;
 import java.util.concurrent.Executors;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * @hide
@@ -104,6 +105,9 @@
     @VisibleForTesting
     static final String BUNDLE_CONTENT_DIGEST = "content-digest";
 
+    static final String APEX_PRELOAD_LOCATION = "/system/apex/";
+    static final String APEX_PRELOAD_LOCATION_ERROR = "could-not-be-determined";
+
     // used for indicating any type of error during MBA measurement
     static final int MBA_STATUS_ERROR = 0;
     // used for indicating factory condition preloads
@@ -306,27 +310,27 @@
                 Bundle packageMeasurement = measurePackage(packageInfo);
                 results.add(packageMeasurement);
 
-                if (record) {
+                if (record && (mba_status == MBA_STATUS_UPDATED_PRELOAD)) {
                     // compute digests of signing info
                     String[] signerDigestHexStrings = computePackageSignerSha256Digests(
                             packageInfo.signingInfo);
 
                     // now we should have all the bits for the atom
-                    /*  TODO: Uncomment and test after merging new atom definition.
+                    byte[] cDigest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                     FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                             packageInfo.packageName,
                             packageInfo.getLongVersionCode(),
-                            HexEncoding.encodeToString(packageMeasurement.getByteArray(
-                                    BUNDLE_CONTENT_DIGEST), false),
+                            (cDigest != null) ? HexEncoding.encodeToString(
+                                    packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST),
+                                    false) : null,
                             packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
                             signerDigestHexStrings, // signer_cert_digest
-                            mba_status,                 // mba_status
+                            mba_status,             // mba_status
                             null,                   // initiator
                             null,                   // initiator_signer_digest
                             null,                   // installer
                             null                    // originator
                     );
-                     */
                 }
             }
             if (DEBUG) {
@@ -373,12 +377,13 @@
                     }
 
                     // we should now have all the info needed for the atom
-                    /*  TODO: Uncomment and test after merging new atom definition.
+                    byte[] cDigest = packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST);
                     FrameworkStatsLog.write(FrameworkStatsLog.MOBILE_BUNDLED_APP_INFO_GATHERED,
                             packageInfo.packageName,
                             packageInfo.getLongVersionCode(),
-                            HexEncoding.encodeToString(packageMeasurement.getByteArray(
-                                    BUNDLE_CONTENT_DIGEST), false),
+                            (cDigest != null) ? HexEncoding.encodeToString(
+                                    packageMeasurement.getByteArray(BUNDLE_CONTENT_DIGEST),
+                                    false) : null,
                             packageMeasurement.getInt(BUNDLE_CONTENT_DIGEST_ALGORITHM),
                             signerDigestHexStrings,
                             MBA_STATUS_NEW_INSTALL,   // mba_status
@@ -387,7 +392,6 @@
                             installer,
                             originator
                     );
-                     */
                 }
             }
             if (DEBUG) {
@@ -485,24 +489,10 @@
                         Integer algorithmId = entry.getKey();
                         byte[] contentDigest = entry.getValue();
 
-                        // TODO(b/259348134): consider refactoring the following to a helper method
-                        switch (algorithmId) {
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
-                                pw.print("CHUNKED_SHA256:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
-                                pw.print("CHUNKED_SHA512:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
-                                pw.print("VERITY_CHUNKED_SHA256:");
-                                break;
-                            case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
-                                pw.print("SHA256:");
-                                break;
-                            default:
-                                pw.print("UNKNOWN_ALGO_ID(" + algorithmId + "):");
-                        }
+                        pw.print(translateContentDigestAlgorithmIdToString(algorithmId));
+                        pw.print(":");
                         pw.print(HexEncoding.encodeToString(contentDigest, false));
+                        pw.print("\n");
                     }
                 }
 
@@ -529,31 +519,13 @@
                             pw.println("ERROR: Failed to compute package content digest for "
                                     + origPackageFilepath);
                         } else {
-                            // TODO(b/259348134): consider refactoring this to a helper method
                             for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) {
                                 Integer algorithmId = entry.getKey();
                                 byte[] contentDigest = entry.getValue();
-                                pw.print("|--> Pre-installed package content digest algorithm: ");
-                                switch (algorithmId) {
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
-                                        pw.print("CHUNKED_SHA256");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
-                                        pw.print("CHUNKED_SHA512");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
-                                        pw.print("VERITY_CHUNKED_SHA256");
-                                        break;
-                                    case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
-                                        pw.print("SHA256");
-                                        break;
-                                    default:
-                                        pw.print("UNKNOWN");
-                                }
-                                pw.print("\n");
-                                pw.print("|--> Pre-installed package content digest: ");
-                                pw.print(HexEncoding.encodeToString(contentDigest, false));
-                                pw.print("\n");
+                                pw.println("|--> Pre-installed package content digest: "
+                                        + HexEncoding.encodeToString(contentDigest, false));
+                                pw.println("|--> Pre-installed package content digest algorithm: "
+                                        + translateContentDigestAlgorithmIdToString(algorithmId));
                             }
                         }
                     }
@@ -735,7 +707,6 @@
                         pw.print(packageName + ","
                                 + packageInfo.getLongVersionCode() + ",");
                         printPackageMeasurements(packageInfo, pw);
-                        pw.print("\n");
 
                         if (verbose) {
                             ModuleInfo moduleInfo;
@@ -798,7 +769,6 @@
                             pw.print(packageInfo.packageName + ",");
                             pw.print(packageInfo.getLongVersionCode() + ",");
                             printPackageMeasurements(packageInfo, pw);
-                            pw.print("\n");
 
                             if (verbose) {
                                 printModuleDetails(module, pw);
@@ -854,7 +824,6 @@
                         pw.print(packageInfo.packageName + ",");
                         pw.print(packageInfo.getLongVersionCode() + ",");
                         printPackageMeasurements(packageInfo, pw);
-                        pw.print("\n");
 
                         if (verbose) {
                             printAppDetails(packageInfo, printLibraries, pw);
@@ -1075,6 +1044,21 @@
         FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
     }
 
+    private String translateContentDigestAlgorithmIdToString(int algorithmId) {
+        switch (algorithmId) {
+            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
+                return "CHUNKED_SHA256";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
+                return "CHUNKED_SHA512";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
+                return "VERITY_CHUNKED_SHA256";
+            case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
+                return "SHA256";
+            default:
+                return "UNKNOWN_ALGO_ID(" + algorithmId + ")";
+        }
+    }
+
     @NonNull
     private List<PackageInfo> getCurrentInstalledApexs() {
         List<PackageInfo> results = new ArrayList<>();
@@ -1110,18 +1094,22 @@
         }
     }
 
-    // TODO(b/259349011): Need to be more robust against package name mismatch in the filename
+    @NonNull
     private String getOriginalApexPreinstalledLocation(String packageName,
                                                    String currentInstalledLocation) {
-        if (currentInstalledLocation.contains("/decompressed/")) {
-            String resultPath = "system/apex" + packageName + ".capex";
-            File f = new File(resultPath);
-            if (f.exists()) {
-                return resultPath;
+        // get a listing of all apex files in /system/apex/
+        Set<String> originalApexs = Stream.of(new File(APEX_PRELOAD_LOCATION).listFiles())
+                                        .filter(f -> !f.isDirectory())
+                                        .map(File::getName)
+                                        .collect(Collectors.toSet());
+
+        for (String originalApex : originalApexs) {
+            if (originalApex.startsWith(packageName)) {
+                return APEX_PRELOAD_LOCATION + originalApex;
             }
-            return "/system/apex/" + packageName + ".next.capex";
         }
-        return "/system/apex" + packageName + "apex";
+
+        return APEX_PRELOAD_LOCATION_ERROR;
     }
 
     /**
diff --git a/services/core/java/com/android/server/BootReceiver.java b/services/core/java/com/android/server/BootReceiver.java
index 551ffff..84c033c 100644
--- a/services/core/java/com/android/server/BootReceiver.java
+++ b/services/core/java/com/android/server/BootReceiver.java
@@ -341,7 +341,8 @@
         // non-proto tombstones, even though proto tombstones do not support including the counter
         // of events dropped since rate limiting activated yet.
         DropboxRateLimiter.RateLimitResult rateLimitResult =
-                sDropboxRateLimiter.shouldRateLimit(TAG_TOMBSTONE, processName);
+                sDropboxRateLimiter.shouldRateLimit(
+                       proto ? TAG_TOMBSTONE_PROTO : TAG_TOMBSTONE, processName);
         if (rateLimitResult.shouldRateLimit()) return;
 
         HashMap<String, Long> timestamps = readTimestamps();
diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java
index 104d10d..3487613 100644
--- a/services/core/java/com/android/server/DockObserver.java
+++ b/services/core/java/com/android/server/DockObserver.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.database.ContentObserver;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -73,6 +74,7 @@
     private final boolean mAllowTheaterModeWakeFromDock;
 
     private final List<ExtconStateConfig> mExtconStateConfigs;
+    private DeviceProvisionedObserver mDeviceProvisionedObserver;
 
     static final class ExtconStateProvider {
         private final Map<String, String> mState;
@@ -110,7 +112,7 @@
                 Slog.w(TAG, "No state file found at: " + stateFilePath);
                 return new ExtconStateProvider(new HashMap<>());
             } catch (Exception e) {
-                Slog.e(TAG, "" , e);
+                Slog.e(TAG, "", e);
                 return new ExtconStateProvider(new HashMap<>());
             }
         }
@@ -136,7 +138,7 @@
 
     private static List<ExtconStateConfig> loadExtconStateConfigs(Context context) {
         String[] rows = context.getResources().getStringArray(
-            com.android.internal.R.array.config_dockExtconStateMapping);
+                com.android.internal.R.array.config_dockExtconStateMapping);
         try {
             ArrayList<ExtconStateConfig> configs = new ArrayList<>();
             for (String row : rows) {
@@ -167,6 +169,7 @@
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromDock);
         mKeepDreamingWhenUndocking = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_keepDreamingWhenUndocking);
+        mDeviceProvisionedObserver = new DeviceProvisionedObserver(mHandler);
 
         mExtconStateConfigs = loadExtconStateConfigs(context);
 
@@ -199,15 +202,19 @@
         if (phase == PHASE_ACTIVITY_MANAGER_READY) {
             synchronized (mLock) {
                 mSystemReady = true;
-
-                // don't bother broadcasting undocked here
-                if (mReportedDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
-                    updateLocked();
-                }
+                mDeviceProvisionedObserver.onSystemReady();
+                updateIfDockedLocked();
             }
         }
     }
 
+    private void updateIfDockedLocked() {
+        // don't bother broadcasting undocked here
+        if (mReportedDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+            updateLocked();
+        }
+    }
+
     private void setActualDockStateLocked(int newState) {
         mActualDockState = newState;
         if (!mUpdatesStopped) {
@@ -252,8 +259,7 @@
 
             // Skip the dock intent if not yet provisioned.
             final ContentResolver cr = getContext().getContentResolver();
-            if (Settings.Global.getInt(cr,
-                    Settings.Global.DEVICE_PROVISIONED, 0) == 0) {
+            if (!mDeviceProvisionedObserver.isDeviceProvisioned()) {
                 Slog.i(TAG, "Device not provisioned, skipping dock broadcast");
                 return;
             }
@@ -302,6 +308,7 @@
                                     getContext(), soundUri);
                             if (sfx != null) {
                                 sfx.setStreamType(AudioManager.STREAM_SYSTEM);
+                                sfx.preferBuiltinDevice(true);
                                 sfx.play();
                             }
                         }
@@ -418,4 +425,48 @@
             }
         }
     }
+
+    private final class DeviceProvisionedObserver extends ContentObserver {
+        private boolean mRegistered;
+
+        public DeviceProvisionedObserver(Handler handler) {
+            super(handler);
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            synchronized (mLock) {
+                updateRegistration();
+                if (isDeviceProvisioned()) {
+                    // Send the dock broadcast if device is docked after provisioning.
+                    updateIfDockedLocked();
+                }
+            }
+        }
+
+        void onSystemReady() {
+            updateRegistration();
+        }
+
+        private void updateRegistration() {
+            boolean register = !isDeviceProvisioned();
+            if (register == mRegistered) {
+                return;
+            }
+            final ContentResolver resolver = getContext().getContentResolver();
+            if (register) {
+                resolver.registerContentObserver(
+                        Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
+                        false, this);
+            } else {
+                resolver.unregisterContentObserver(this);
+            }
+            mRegistered = register;
+        }
+
+        boolean isDeviceProvisioned() {
+            return Settings.Global.getInt(getContext().getContentResolver(),
+                    Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index 02c6ca2..27ee627 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -91,7 +91,7 @@
     private static final int DEFAULT_MAX_FILES_LOWRAM = 300;
     private static final int DEFAULT_QUOTA_KB = 10 * 1024;
     private static final int DEFAULT_QUOTA_PERCENT = 10;
-    private static final int DEFAULT_RESERVE_PERCENT = 10;
+    private static final int DEFAULT_RESERVE_PERCENT = 0;
     private static final int QUOTA_RESCAN_MILLIS = 5000;
 
     private static final boolean PROFILE_DUMP = false;
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index b56d1fc..b4ab254 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -447,6 +447,13 @@
                 thread.start();
                 break;
             case LEVEL_FACTORY_RESET:
+                // Before the completion of Reboot, if any crash happens then PackageWatchdog
+                // escalates to next level i.e. factory reset, as they happen in separate threads.
+                // Adding a check to prevent factory reset to execute before above reboot completes.
+                // Note: this reboot property is not persistent resets after reboot is completed.
+                if (isRebootPropertySet()) {
+                    break;
+                }
                 SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
                 runnable = new Runnable() {
                     @Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ca86021c..bd90d85 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,8 +52,8 @@
 import android.telephony.Annotation.RadioPowerState;
 import android.telephony.Annotation.SrvccState;
 import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
 import android.telephony.CallQuality;
+import android.telephony.CallState;
 import android.telephony.CellIdentity;
 import android.telephony.CellInfo;
 import android.telephony.CellSignalStrength;
@@ -82,6 +82,7 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
 import android.telephony.ims.ImsReasonInfo;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -349,9 +350,9 @@
 
     private CallQuality[] mCallQuality;
 
-    private CallAttributes[] mCallAttributes;
+    private ArrayList<List<CallState>> mCallStateLists;
 
-    // network type of the call associated with the mCallAttributes and mCallQuality
+    // network type of the call associated with the mCallStateLists and mCallQuality
     private int[] mCallNetworkType;
 
     private int[] mSrvccState;
@@ -687,7 +688,6 @@
             mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
             mCallQuality = copyOf(mCallQuality, mNumPhones);
             mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
-            mCallAttributes = copyOf(mCallAttributes, mNumPhones);
             mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
             mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
             mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
@@ -707,6 +707,7 @@
                 cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
                 cutListToSize(mCarrierPrivilegeStates, mNumPhones);
                 cutListToSize(mCarrierServiceStates, mNumPhones);
+                cutListToSize(mCallStateLists, mNumPhones);
                 return;
             }
 
@@ -730,8 +731,7 @@
                 mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
                 mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
                 mCallQuality[i] = createCallQuality();
-                mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
-                        TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+                mCallStateLists.add(i, new ArrayList<>());
                 mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
                 mPreciseCallState[i] = createPreciseCallState();
                 mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -799,7 +799,7 @@
         mCallPreciseDisconnectCause = new int[numPhones];
         mCallQuality = new CallQuality[numPhones];
         mCallNetworkType = new int[numPhones];
-        mCallAttributes = new CallAttributes[numPhones];
+        mCallStateLists = new ArrayList<>();
         mPreciseDataConnectionStates = new ArrayList<>();
         mCellInfo = new ArrayList<>(numPhones);
         mImsReasonInfo = new ArrayList<>();
@@ -837,8 +837,7 @@
             mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
             mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
             mCallQuality[i] = createCallQuality();
-            mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
-                    TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+            mCallStateLists.add(i, new ArrayList<>());
             mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
             mPreciseCallState[i] = createPreciseCallState();
             mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -1336,7 +1335,7 @@
                 }
                 if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) {
                     try {
-                        r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]);
+                        r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId));
                     } catch (RemoteException ex) {
                         remove(r.binder);
                     }
@@ -2171,11 +2170,30 @@
         }
     }
 
-    public void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
-                                       int foregroundCallState, int backgroundCallState) {
+    /**
+     * Send a notification to registrants that the precise call state has changed.
+     *
+     * @param phoneId the phoneId carrying the data connection
+     * @param subId the subscriptionId for the data connection
+     * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+     * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId()} for
+     *                   ringing, foreground & background calls.
+     * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+     *                        background calls.
+     * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
+     */
+    public void notifyPreciseCallState(int phoneId, int subId,
+            @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+            @Annotation.ImsCallServiceType int[] imsServiceTypes,
+            @Annotation.ImsCallType int[] imsCallTypes) {
         if (!checkNotifyPermission("notifyPreciseCallState()")) {
             return;
         }
+
+        int ringingCallState = callStates[CallState.CALL_CLASSIFICATION_RINGING];
+        int foregroundCallState = callStates[CallState.CALL_CLASSIFICATION_FOREGROUND];
+        int backgroundCallState = callStates[CallState.CALL_CLASSIFICATION_BACKGROUND];
+
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
                 mRingingCallState[phoneId] = ringingCallState;
@@ -2186,11 +2204,11 @@
                         backgroundCallState,
                         DisconnectCause.NOT_VALID,
                         PreciseDisconnectCause.NOT_VALID);
-                boolean notifyCallAttributes = true;
+                boolean notifyCallState = true;
                 if (mCallQuality == null) {
                     log("notifyPreciseCallState: mCallQuality is null, "
                             + "skipping call attributes");
-                    notifyCallAttributes = false;
+                    notifyCallState = false;
                 } else {
                     // If the precise call state is no longer active, reset the call network type
                     // and call quality.
@@ -2199,8 +2217,65 @@
                         mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
                         mCallQuality[phoneId] = createCallQuality();
                     }
-                    mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
-                            mCallNetworkType[phoneId], mCallQuality[phoneId]);
+                    mCallStateLists.get(phoneId).clear();
+                    if (foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallQuality callQuality = mCallQuality[phoneId];
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(callQuality)
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_FOREGROUND);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_FOREGROUND]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
+                    if (backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(createCallQuality())
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_BACKGROUND);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_BACKGROUND]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
+                    if (ringingCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+                            && ringingCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+                        CallState.Builder builder = new CallState.Builder(
+                                callStates[CallState.CALL_CLASSIFICATION_RINGING])
+                                .setNetworkType(mCallNetworkType[phoneId])
+                                .setCallQuality(createCallQuality())
+                                .setCallClassification(
+                                        CallState.CALL_CLASSIFICATION_RINGING);
+                        if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+                            builder = builder
+                                    .setImsCallSessionId(imsCallIds[
+                                            CallState.CALL_CLASSIFICATION_RINGING])
+                                    .setImsCallServiceType(imsServiceTypes[
+                                            CallState.CALL_CLASSIFICATION_RINGING])
+                                    .setImsCallType(imsCallTypes[
+                                            CallState.CALL_CLASSIFICATION_RINGING]);
+                        }
+                        mCallStateLists.get(phoneId).add(builder.build());
+                    }
                 }
 
                 for (Record r : mRecords) {
@@ -2213,11 +2288,11 @@
                             mRemoveList.add(r.binder);
                         }
                     }
-                    if (notifyCallAttributes && r.matchTelephonyCallbackEvent(
+                    if (notifyCallState && r.matchTelephonyCallbackEvent(
                             TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r, subId, phoneId)) {
                         try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                            r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2515,15 +2590,29 @@
                 // merge CallQuality with PreciseCallState and network type
                 mCallQuality[phoneId] = callQuality;
                 mCallNetworkType[phoneId] = callNetworkType;
-                mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
-                        callNetworkType, callQuality);
+                if (mCallStateLists.get(phoneId).size() > 0
+                        && mCallStateLists.get(phoneId).get(0).getCallState()
+                        == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
+                    CallState prev = mCallStateLists.get(phoneId).remove(0);
+                    mCallStateLists.get(phoneId).add(
+                            0, new CallState.Builder(prev.getCallState())
+                                    .setNetworkType(callNetworkType)
+                                    .setCallQuality(callQuality)
+                                    .setCallClassification(prev.getCallClassification())
+                                    .setImsCallSessionId(prev.getImsCallSessionId())
+                                    .setImsCallServiceType(prev.getImsCallServiceType())
+                                    .setImsCallType(prev.getImsCallType()).build());
+                } else {
+                    log("There is no active call to report CallQaulity");
+                    return;
+                }
 
                 for (Record r : mRecords) {
                     if (r.matchTelephonyCallbackEvent(
                             TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
                             && idMatch(r, subId, phoneId)) {
                         try {
-                            r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+                            r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
                         } catch (RemoteException ex) {
                             mRemoveList.add(r.binder);
                         }
@@ -2991,7 +3080,6 @@
                 pw.println("mSrvccState=" + mSrvccState[i]);
                 pw.println("mCallPreciseDisconnectCause=" + mCallPreciseDisconnectCause[i]);
                 pw.println("mCallQuality=" + mCallQuality[i]);
-                pw.println("mCallAttributes=" + mCallAttributes[i]);
                 pw.println("mCallNetworkType=" + mCallNetworkType[i]);
                 pw.println("mPreciseDataConnectionStates=" + mPreciseDataConnectionStates.get(i));
                 pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1534e63..0d672bd 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -32,6 +32,8 @@
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
 import static android.os.PowerExemptionManager.REASON_ACTIVE_DEVICE_ADMIN;
 import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
 import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
@@ -110,7 +112,6 @@
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.ForegroundServiceStartNotAllowedException;
-import android.app.ForegroundServiceTypeNotAllowedException;
 import android.app.ForegroundServiceTypePolicy;
 import android.app.ForegroundServiceTypePolicy.ForegroundServicePolicyCheckCode;
 import android.app.ForegroundServiceTypePolicy.ForegroundServiceTypePermission;
@@ -118,6 +119,8 @@
 import android.app.IApplicationThread;
 import android.app.IForegroundServiceObserver;
 import android.app.IServiceConnection;
+import android.app.InvalidForegroundServiceTypeException;
+import android.app.MissingForegroundServiceTypeException;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -129,6 +132,7 @@
 import android.app.usage.UsageEvents;
 import android.appwidget.AppWidgetManagerInternal;
 import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledAfter;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.Overridable;
 import android.content.ComponentName;
@@ -147,6 +151,7 @@
 import android.content.pm.ServiceInfo.ForegroundServiceType;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Build.VERSION_CODES;
 import android.os.Bundle;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -225,7 +230,8 @@
     private static final boolean DEBUG_DELAYED_SERVICE = DEBUG_SERVICE;
     private static final boolean DEBUG_DELAYED_STARTS = DEBUG_DELAYED_SERVICE;
 
-    private static final boolean DEBUG_SHORT_SERVICE = DEBUG_SERVICE;
+    // STOPSHIP(b/260012573) turn it off.
+    private static final boolean DEBUG_SHORT_SERVICE = true; // DEBUG_SERVICE;
 
     private static final boolean LOG_SERVICE_START_STOP = DEBUG_SERVICE;
 
@@ -386,6 +392,14 @@
     @EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
     static final long FGS_START_EXCEPTION_CHANGE_ID = 174041399L;
 
+    /**
+     * If enabled, the FGS type check against the manifest FSG type will be enabled for
+     * instant apps too. Before U, this check was only done for non-instant apps.
+     */
+    @ChangeId
+    @EnabledAfter(targetSdkVersion = VERSION_CODES.TIRAMISU)
+    static final long FGS_TYPE_CHECK_FOR_INSTANT_APPS = 261055255L;
+
     final Runnable mLastAnrDumpClearer = new Runnable() {
         @Override public void run() {
             synchronized (mAm) {
@@ -1284,6 +1298,8 @@
                 return;
             }
 
+            maybeStopShortFgsTimeoutLocked(service);
+
             final int uid = service.appInfo.uid;
             final String packageName = service.name.getPackageName();
             final String serviceName = service.name.getClassName();
@@ -1467,6 +1483,8 @@
                 }
             }
 
+            maybeStopShortFgsTimeoutLocked(r);
+
             final int uid = r.appInfo.uid;
             final String packageName = r.name.getPackageName();
             final String serviceName = r.name.getClassName();
@@ -1781,6 +1799,7 @@
             if (notification == null) {
                 throw new IllegalArgumentException("null notification");
             }
+            final int foregroundServiceStartType = foregroundServiceType;
             // Instant apps need permission to create foreground services.
             if (r.appInfo.isInstantApp()) {
                 final int mode = mAm.getAppOpsManager().checkOpNoThrow(
@@ -1809,31 +1828,44 @@
                             android.Manifest.permission.FOREGROUND_SERVICE,
                             r.app.getPid(), r.appInfo.uid, "startForeground");
                 }
+            }
+            final int manifestType = r.serviceInfo.getForegroundServiceType();
+            // If passed in foreground service type is FOREGROUND_SERVICE_TYPE_MANIFEST,
+            // consider it is the same as manifest foreground service type.
+            if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_MANIFEST) {
+                foregroundServiceType = manifestType;
+            }
 
-                // TODO(short-service): This part really should be above the if block,
-                // so we'll apply the same check for instant apps too.
-                int manifestType = r.serviceInfo.getForegroundServiceType();
-                // If passed in foreground service type is FOREGROUND_SERVICE_TYPE_MANIFEST,
-                // consider it is the same as manifest foreground service type.
-                if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_MANIFEST) {
-                    foregroundServiceType = manifestType;
-                }
-
-                // Check the passed in foreground service type flags is a subset of manifest
-                // foreground service type flags.
-                final String prop = "debug.skip_fgs_manifest_type_check";
-                if (((foregroundServiceType & manifestType) != foregroundServiceType)
-                        // When building a test app on Studio, the SDK may not have all the
-                        // FGS types yet. This debug flag will allow using FGS types that are
-                        // not set in the manifest.
-                        && !SystemProperties.getBoolean(prop, false)) {
-                    throw new IllegalArgumentException("foregroundServiceType "
+            // Check the passed in foreground service type flags is a subset of manifest
+            // foreground service type flags.
+            final String prop = "debug.skip_fgs_manifest_type_check";
+            if (((foregroundServiceType & manifestType) != foregroundServiceType)
+                    // When building a test app on Studio, the SDK may not have all the
+                    // FGS types yet. This debug flag will allow using FGS types that are
+                    // not set in the manifest.
+                    && !SystemProperties.getBoolean(prop, false)) {
+                final String message = "foregroundServiceType "
                         + String.format("0x%08X", foregroundServiceType)
                         + " is not a subset of foregroundServiceType attribute "
-                        +  String.format("0x%08X", manifestType)
-                        + " in service element of manifest file");
+                        + String.format("0x%08X", manifestType)
+                        + " in service element of manifest file";
+                if (!r.appInfo.isInstantApp()
+                        || CompatChanges.isChangeEnabled(FGS_TYPE_CHECK_FOR_INSTANT_APPS,
+                        r.appInfo.uid)) {
+                    throw new IllegalArgumentException(message);
+                } else {
+                    Slog.w(TAG, message + "\n"
+                            + "This will be an exception once the target SDK level is UDC");
                 }
             }
+            if ((foregroundServiceType & FOREGROUND_SERVICE_TYPE_SHORT_SERVICE) != 0
+                    && foregroundServiceType != FOREGROUND_SERVICE_TYPE_SHORT_SERVICE) {
+                Slog.w(TAG_SERVICE, "startForeground(): FOREGROUND_SERVICE_TYPE_SHORT_SERVICE"
+                        + " is combined with other types. SHORT_SERVICE will be ignored.");
+                // In this case, the service will be handled as a non-short, regular FGS
+                // anyway, so we just remove the SHORT_SERVICE type.
+                foregroundServiceType &= ~FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+            }
 
             boolean alreadyStartedOp = false;
             boolean stopProcStatsOp = false;
@@ -1883,14 +1915,51 @@
 
                 int fgsTypeCheckCode = FGS_TYPE_POLICY_CHECK_UNKNOWN;
                 if (!ignoreForeground) {
-                    // TODO(short-service): There's a known long-standing bug that allows
-                    // a abound service to become "foreground" if setForeground() is called
-                    // (without actually "starting" it).
-                    // Unfortunately we can't just "fix" it because some apps are relying on it,
-                    // but this will cause a problem to short-fgs, so we should disallow it if
-                    // this happens and the type is SHORT_SERVICE.
-                    //
-                    // OTOH, if a valid short-service (which has to be "started"), happens to
+                    if (foregroundServiceType == FOREGROUND_SERVICE_TYPE_SHORT_SERVICE
+                            && !r.startRequested) {
+                        // There's a long standing bug that allows a bound service to become
+                        // a foreground service *even when it's not started*.
+                        // Unfortunately, there are apps relying on this behavior, so we can't just
+                        // suddenly disallow it.
+                        // However, this would be very problematic if used with a short-FGS, so we
+                        // explicitly disallow this combination.
+                        // TODO(short-service): Change to another exception type?
+                        throw new IllegalStateException(
+                                "startForeground(SHORT_SERVICE) called on a service that's not"
+                                + " started.");
+                    }
+                    // If the service is already an FGS, and the type is changing, then we
+                    // may need to do some extra work here.
+                    if (r.isForeground && (r.foregroundServiceType != foregroundServiceType)) {
+                        // TODO(short-service): Consider transitions:
+                        //   A. Short -> other types:
+                        //     Apply the BG restriction again. Don't just allow it.
+                        //     i.e. unless the app is in a situation where it's allowed to start
+                        //     a FGS, this transition shouldn't be allowed.
+                        //     ... But think about it more, there may be a case this should be
+                        //     allowed.
+                        //
+                        //     If the transition is allowed, stop the timeout.
+                        //     If the transition is _not_ allowed... keep the timeout?
+                        //
+                        //   B. Short -> Short:
+                        //     Allowed, but the timeout won't reset. The original timeout is used.
+                        //   C. Other -> short:
+                        //     This should always be allowed.
+                        //     A timeout should start.
+
+                        // For now, let's just disallow transition from / to SHORT_SERVICE.
+                        final boolean isNewTypeShortFgs =
+                                foregroundServiceType == FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+                        if (r.isShortFgs() != isNewTypeShortFgs) {
+                            // TODO(short-service): We should (probably) allow it.
+                            throw new IllegalArgumentException(
+                                    "setForeground(): Changing foreground service type from / to "
+                                    + " SHORT_SERVICE is now allowed");
+                        }
+                    }
+
+                    // If a valid short-service (which has to be "started"), happens to
                     // also be bound, then we still _will_ apply a timeout, because it still has
                     // to be stopped.
                     if (r.mStartForegroundCount == 0) {
@@ -1929,24 +1998,6 @@
                         // on the same sarvice after it's created, regardless of whether
                         // stopForeground() has been called or not.
 
-                        // TODO(short-service): Consider transitions:
-                        //   A. Short -> other types:
-                        //     Apply the BG restriction again. Don't just allow it.
-                        //     i.e. unless the app is in a situation where it's allowed to start
-                        //     a FGS, this transition shouldn't be allowed.
-                        //     ... But think about it more, there may be a case this should be
-                        //     allowed.
-                        //
-                        //     If the transition is allowed, stop the timeout.
-                        //     If the transition is _not_ allowed... keep the timeout?
-                        //
-                        //   B. Short -> Short:
-                        //     This should be the same as case A
-                        //     If this is allowed, the new timeout should start.
-                        //   C. Other -> short:
-                        //     This should always be allowed.
-                        //     A timeout should start.
-
                         // The second or later time startForeground() is called after service is
                         // started. Check for app state again.
                         setFgsRestrictionLocked(r.serviceInfo.packageName, r.app.getPid(),
@@ -1985,7 +2036,8 @@
                         if (foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE) {
                             fgsTypeResult = validateForegroundServiceType(r,
                                     foregroundServiceType,
-                                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+                                    ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE,
+                                    foregroundServiceStartType);
                         } else {
                             int fgsTypes = foregroundServiceType;
                             // If the service has declared some unknown types which might be coming
@@ -2000,7 +2052,7 @@
                                     serviceType != 0;
                                     serviceType = Integer.highestOneBit(fgsTypes)) {
                                 fgsTypeResult = validateForegroundServiceType(r,
-                                        serviceType, defaultFgsTypes);
+                                        serviceType, defaultFgsTypes, foregroundServiceStartType);
                                 fgsTypes &= ~serviceType;
                                 if (fgsTypeResult.first != FGS_TYPE_POLICY_CHECK_OK) {
                                     break;
@@ -2102,8 +2154,11 @@
                     mAm.notifyPackageUse(r.serviceInfo.packageName,
                             PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
 
-                    // TODO(short-service): Start counting a timeout.
-
+                    // Note, we'll get here if setForeground(SHORT_SERVICE) is called on a
+                    // already short-fgs.
+                    // In that case, because ShortFgsInfo is already set, this method
+                    // will be noop.
+                    maybeStartShortFgsTimeoutAndUpdateShortFgsInfoLocked(r);
                 } else {
                     if (DEBUG_FOREGROUND_SERVICE) {
                         Slog.d(TAG, "Suppressing startForeground() for FAS " + r);
@@ -2137,7 +2192,7 @@
                     decActiveForegroundAppLocked(smap, r);
                 }
 
-                // TODO(short-service): Stop the timeout. (any better place to do it?)
+                maybeStopShortFgsTimeoutLocked(r);
 
                 // Adjust notification handling before setting isForeground to false, because
                 // that state is relevant to the notification policy side.
@@ -2227,7 +2282,8 @@
     @NonNull
     private Pair<Integer, RuntimeException> validateForegroundServiceType(ServiceRecord r,
             @ForegroundServiceType int type,
-            @ForegroundServiceType int defaultToType) {
+            @ForegroundServiceType int defaultToType,
+            @ForegroundServiceType int startType) {
         final ForegroundServiceTypePolicy policy = ForegroundServiceTypePolicy.getDefaultPolicy();
         final ForegroundServiceTypePolicyInfo policyInfo =
                 policy.getForegroundServiceTypePolicyInfo(type, defaultToType);
@@ -2246,12 +2302,20 @@
                 Slog.w(TAG, msg);
             } break;
             case FGS_TYPE_POLICY_CHECK_DISABLED: {
-                exception = new ForegroundServiceTypeNotAllowedException(
-                        "Starting FGS with type "
-                        + ServiceInfo.foregroundServiceTypeToLabel(type)
-                        + " callerApp=" + r.app
-                        + " targetSDK=" + r.app.info.targetSdkVersion
-                        + " has been prohibited");
+                if (startType == FOREGROUND_SERVICE_TYPE_MANIFEST
+                        && type == FOREGROUND_SERVICE_TYPE_NONE) {
+                    exception = new MissingForegroundServiceTypeException(
+                            "Starting FGS without a type "
+                            + " callerApp=" + r.app
+                            + " targetSDK=" + r.app.info.targetSdkVersion);
+                } else {
+                    exception = new InvalidForegroundServiceTypeException(
+                            "Starting FGS with type "
+                            + ServiceInfo.foregroundServiceTypeToLabel(type)
+                            + " callerApp=" + r.app
+                            + " targetSDK=" + r.app.info.targetSdkVersion
+                            + " has been prohibited");
+                }
             } break;
             case FGS_TYPE_POLICY_CHECK_PERMISSION_DENIED_PERMISSIVE: {
                 final String msg = "Starting FGS with type "
@@ -2873,6 +2937,103 @@
         psr.setHasReportedForegroundServices(anyForeground);
     }
 
+    void unscheduleShortFgsTimeoutLocked(ServiceRecord sr) {
+        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
+        mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
+    }
+
+    /**
+     * If {@code sr} is of a short-fgs, start a short-FGS timeout.
+     */
+    private void maybeStartShortFgsTimeoutAndUpdateShortFgsInfoLocked(ServiceRecord sr) {
+        if (!sr.isShortFgs()) {
+            return;
+        }
+        if (DEBUG_SHORT_SERVICE) {
+            Slog.i(TAG_SERVICE, "Short FGS started: " + sr);
+        }
+        if (sr.hasShortFgsInfo()) {
+            sr.getShortFgsInfo().update();
+        } else {
+            sr.setShortFgsInfo(SystemClock.uptimeMillis());
+        }
+        unscheduleShortFgsTimeoutLocked(sr); // Do it just in case
+
+        final Message msg = mAm.mHandler.obtainMessage(
+                ActivityManagerService.SERVICE_SHORT_FGS_TIMEOUT_MSG, sr);
+        mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getTimeoutTime());
+    }
+
+    /**
+     * Stop the timeout for a ServiceRecord, if it's of a short-FGS.
+     */
+    private void maybeStopShortFgsTimeoutLocked(ServiceRecord sr) {
+        if (!sr.isShortFgs()) {
+            return;
+        }
+        if (DEBUG_SHORT_SERVICE) {
+            Slog.i(TAG_SERVICE, "Stop short FGS timeout: " + sr);
+        }
+        sr.clearShortFgsInfo();
+        unscheduleShortFgsTimeoutLocked(sr);
+    }
+
+    void onShortFgsTimeout(ServiceRecord sr) {
+        synchronized (mAm) {
+            if (!sr.shouldTriggerShortFgsTimeout()) {
+                return;
+            }
+            Slog.e(TAG_SERVICE, "Short FGS timed out: " + sr);
+            try {
+                sr.app.getThread().scheduleTimeoutService(sr, sr.getShortFgsInfo().getStartId());
+            } catch (RemoteException e) {
+                // TODO(short-service): Anything to do here?
+            }
+            // Schedule the ANR timeout.
+            final Message msg = mAm.mHandler.obtainMessage(
+                    ActivityManagerService.SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG, sr);
+            mAm.mHandler.sendMessageAtTime(msg, sr.getShortFgsInfo().getAnrTime());
+        }
+    }
+
+    boolean shouldServiceTimeOutLocked(ComponentName className, IBinder token) {
+        final int userId = UserHandle.getCallingUserId();
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            ServiceRecord sr = findServiceLocked(className, token, userId);
+            if (sr == null) {
+                return false;
+            }
+            return sr.shouldTriggerShortFgsTimeout();
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    void onShortFgsAnrTimeout(ServiceRecord sr) {
+        final String reason = "A foreground service of FOREGROUND_SERVICE_TYPE_SHORT_SERVICE"
+                + " did not stop within a timeout: " + sr.getComponentName();
+
+        final TimeoutRecord tr = TimeoutRecord.forShortFgsTimeout(reason);
+
+        tr.mLatencyTracker.waitingOnAMSLockStarted();
+        synchronized (mAm) {
+            tr.mLatencyTracker.waitingOnAMSLockEnded();
+
+            if (!sr.shouldTriggerShortFgsAnr()) {
+                return;
+            }
+
+            final String message = "Short FGS ANR'ed: " + sr;
+            if (DEBUG_SHORT_SERVICE) {
+                Slog.wtf(TAG_SERVICE, message);
+            } else {
+                Slog.e(TAG_SERVICE, message);
+            }
+            mAm.appNotResponding(sr.app, tr);
+        }
+    }
+
     private void updateAllowlistManagerLocked(ProcessServiceRecord psr) {
         psr.mAllowlistManager = false;
         for (int i = psr.numberOfRunningServices() - 1; i >= 0; i--) {
@@ -2884,6 +3045,7 @@
         }
     }
 
+    // TODO(short-service): Hmm what is it? Should we stop the timeout here?
     private void stopServiceAndUpdateAllowlistManagerLocked(ServiceRecord service) {
         final ProcessServiceRecord psr = service.app.mServices;
         psr.stopService(service);
@@ -3675,6 +3837,11 @@
                             throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
                                     + className + " is not an isolatedProcess");
                         }
+                        if (AppGlobals.getPackageManager().getPackageUid(callingPackage,
+                                0, userId) != callingUid) {
+                            throw new SecurityException("BIND_EXTERNAL_SERVICE failed, "
+                                    + "calling package not owned by calling UID ");
+                        }
                         // Run the service under the calling package's application.
                         ApplicationInfo aInfo = AppGlobals.getPackageManager().getApplicationInfo(
                                 callingPackage, ActivityManagerService.STOCK_PM_FLAGS, userId);
@@ -4165,7 +4332,7 @@
     /**
      * Reschedule service restarts based on if the extra delays are enabled or not.
      *
-     * @param prevEnable The previous state of whether or not it's enabled.
+     * @param prevEnabled The previous state of whether or not it's enabled.
      * @param curEnabled The current state of whether or not it's enabled.
      * @param now The uptimeMillis
      */
@@ -4850,13 +5017,6 @@
             Slog.i(TAG, "Bring down service for " + debugReason + " :" + r.toString());
         }
 
-        // TODO(short-service): Hmm, when the app stops a short-fgs, we should stop the timeout
-        // here.
-        // However we have a couple if's here and if these conditions are met, we stop here
-        // without bringing down the service.
-        // We need to make sure this can't be used (somehow) to keep having a short-FGS running
-        // while having the timeout stopped.
-
         if (isServiceNeededLocked(r, knowConn, hasConn)) {
             return;
         }
@@ -4873,6 +5033,13 @@
         //Slog.i(TAG, "Bring down service:");
         //r.dump("  ");
 
+        if (r.isShortFgs()) {
+            // FGS can be stopped without the app calling stopService() or stopSelf(),
+            // due to force-app-standby, or from Task Manager.
+            Slog.w(TAG_SERVICE, "Short FGS brought down without stopping: " + r);
+            maybeStopShortFgsTimeoutLocked(r);
+        }
+
         // Report to all of the connections that the service is no longer
         // available.
         ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
@@ -5258,6 +5425,13 @@
                 // This is a call from a service start...  take care of
                 // book-keeping.
                 r.callStart = true;
+
+                // Set the result to startCommandResult.
+                // START_TASK_REMOVED_COMPLETE is _not_ a result from onStartCommand(), so
+                // let's ignore.
+                if (res != Service.START_TASK_REMOVED_COMPLETE) {
+                    r.startCommandResult = res;
+                }
                 switch (res) {
                     case Service.START_STICKY_COMPATIBILITY:
                     case Service.START_STICKY: {
diff --git a/services/core/java/com/android/server/am/ActivityManagerConstants.java b/services/core/java/com/android/server/am/ActivityManagerConstants.java
index 046403d..2d69667 100644
--- a/services/core/java/com/android/server/am/ActivityManagerConstants.java
+++ b/services/core/java/com/android/server/am/ActivityManagerConstants.java
@@ -954,7 +954,7 @@
     static final long DEFAULT_SHORT_FGS_TIMEOUT_DURATION = 60_000;
 
     /** @see #KEY_SHORT_FGS_TIMEOUT_DURATION */
-    public static volatile long mShortFgsTimeoutDuration = DEFAULT_SHORT_FGS_TIMEOUT_DURATION;
+    public volatile long mShortFgsTimeoutDuration = DEFAULT_SHORT_FGS_TIMEOUT_DURATION;
 
     /**
      * If a "short service" doesn't finish within this after the timeout (
@@ -967,7 +967,7 @@
     static final long DEFAULT_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION = 5_000;
 
     /** @see #KEY_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION */
-    public static volatile long mShortFgsProcStateExtraWaitDuration =
+    public volatile long mShortFgsProcStateExtraWaitDuration =
             DEFAULT_SHORT_FGS_PROC_STATE_EXTRA_WAIT_DURATION;
 
     /**
@@ -983,7 +983,7 @@
     static final long DEFAULT_SHORT_FGS_ANR_EXTRA_WAIT_DURATION = 10_000;
 
     /** @see #KEY_SHORT_FGS_ANR_EXTRA_WAIT_DURATION */
-    public static volatile long mShortFgsAnrExtraWaitDuration =
+    public volatile long mShortFgsAnrExtraWaitDuration =
             DEFAULT_SHORT_FGS_ANR_EXTRA_WAIT_DURATION;
 
     private final OnPropertiesChangedListener mOnDeviceConfigChangedListener =
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c779ea9..7566bab 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -87,6 +87,7 @@
 import static android.os.Process.isSdkSandboxUid;
 import static android.os.Process.isThreadInProcess;
 import static android.os.Process.killProcess;
+import static android.os.Process.killProcessGroup;
 import static android.os.Process.killProcessQuiet;
 import static android.os.Process.myPid;
 import static android.os.Process.myUid;
@@ -206,7 +207,7 @@
 import android.app.SyncNotedAppOp;
 import android.app.WaitResult;
 import android.app.assist.ActivityId;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.IBackupManager;
 import android.app.compat.CompatChanges;
 import android.app.job.JobParameters;
@@ -952,13 +953,6 @@
             }
             return false;
         }
-
-        boolean doRemoveIfNoThreadInternal(int pid, ProcessRecord app) {
-            if (app == null || app.getThread() != null) {
-                return false;
-            }
-            return doRemoveInternal(pid, app);
-        }
     }
 
     private final PendingStartActivityUids mPendingStartActivityUids;
@@ -990,7 +984,7 @@
      * method.
      */
     @GuardedBy("this")
-    void removePidLocked(int pid, ProcessRecord app) {
+    boolean removePidLocked(int pid, ProcessRecord app) {
         final boolean removed;
         synchronized (mPidsSelfLocked) {
             removed = mPidsSelfLocked.doRemoveInternal(pid, app);
@@ -1001,26 +995,6 @@
             }
             mAtmInternal.onProcessUnMapped(pid);
         }
-    }
-
-    /**
-     * Removes the process record from the map if it doesn't have a thread.
-     * <p>NOTE: Callers should avoid acquiring the mPidsSelfLocked lock before calling this
-     * method.
-     */
-    @GuardedBy("this")
-    private boolean removePidIfNoThreadLocked(ProcessRecord app) {
-        final boolean removed;
-        final int pid = app.getPid();
-        synchronized (mPidsSelfLocked) {
-            removed = mPidsSelfLocked.doRemoveIfNoThreadInternal(pid, app);
-        }
-        if (removed) {
-            synchronized (sActiveProcessInfoSelfLocked) {
-                sActiveProcessInfoSelfLocked.remove(pid);
-            }
-            mAtmInternal.onProcessUnMapped(pid);
-        }
         return removed;
     }
 
@@ -1563,6 +1537,8 @@
     static final int WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG = 73;
     static final int DISPATCH_SENDING_BROADCAST_EVENT = 74;
     static final int DISPATCH_BINDING_SERVICE_EVENT = 75;
+    static final int SERVICE_SHORT_FGS_TIMEOUT_MSG = 76;
+    static final int SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG = 77;
 
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
 
@@ -1897,6 +1873,12 @@
                     mBindServiceEventListeners.forEach(l ->
                             l.onBindingService((String) msg.obj, msg.arg1));
                 } break;
+                case SERVICE_SHORT_FGS_TIMEOUT_MSG: {
+                    mServices.onShortFgsTimeout((ServiceRecord) msg.obj);
+                } break;
+                case SERVICE_SHORT_FGS_ANR_TIMEOUT_MSG: {
+                    mServices.onShortFgsAnrTimeout((ServiceRecord) msg.obj);
+                } break;
             }
         }
     }
@@ -2356,7 +2338,7 @@
         mAppErrors = null;
         mPackageWatchdog = null;
         mAppOpsService = mInjector.getAppOpsService(null /* file */, null /* handler */);
-        mBatteryStatsService = null;
+        mBatteryStatsService = mInjector.getBatteryStatsService();
         mHandler = new MainHandler(handlerThread.getLooper());
         mHandlerThread = handlerThread;
         mConstants = new ActivityManagerConstants(mContext, this, mHandler);
@@ -2371,7 +2353,7 @@
         mIntentFirewall = null;
         mProcessStats = new ProcessStatsService(this, mContext.getCacheDir());
         mCpHelper = new ContentProviderHelper(this, false);
-        mServices = null;
+        mServices = mInjector.getActiveServices(this);
         mSystemThread = null;
         mUiHandler = injector.getUiHandler(null /* service */);
         mUidObserverController = new UidObserverController(mUiHandler);
@@ -4763,7 +4745,7 @@
     @GuardedBy("this")
     void handleProcessStartOrKillTimeoutLocked(ProcessRecord app, boolean isKillTimeout) {
         final int pid = app.getPid();
-        boolean gone = isKillTimeout || removePidIfNoThreadLocked(app);
+        boolean gone = isKillTimeout || removePidLocked(pid, app);
 
         if (gone) {
             if (isKillTimeout) {
@@ -4844,7 +4826,7 @@
     }
 
     @GuardedBy("this")
-    private boolean attachApplicationLocked(@NonNull IApplicationThread thread,
+    private void attachApplicationLocked(@NonNull IApplicationThread thread,
             int pid, int callingUid, long startSeq) {
 
         // Find the application record that is being attached...  either via
@@ -4909,7 +4891,7 @@
                     // Ignore exceptions.
                 }
             }
-            return false;
+            return;
         }
 
         // If this application record is still attached to a previous
@@ -4934,7 +4916,7 @@
             mProcessList.startProcessLocked(app,
                     new HostingRecord(HostingRecord.HOSTING_TYPE_LINK_FAIL, processName),
                     ZYGOTE_POLICY_FLAG_EMPTY);
-            return false;
+            return;
         }
 
         EventLogTags.writeAmProcBound(app.userId, pid, app.processName);
@@ -4957,8 +4939,6 @@
             app.setUnlocked(StorageManager.isUserKeyUnlocked(app.userId));
         }
 
-        mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
-
         boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
         List<ProviderInfo> providers = normalMode
                                             ? mCpHelper.generateApplicationProvidersLocked(app)
@@ -5124,7 +5104,7 @@
             app.killLocked("error during bind", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
                     true);
             handleAppDiedLocked(app, pid, false, true, false /* fromBinderDied */);
-            return false;
+            return;
         }
 
         // Remove this record from the list of starting applications.
@@ -5132,90 +5112,6 @@
         if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG_PROCESSES,
                 "Attach application locked removing on hold: " + app);
         mProcessesOnHold.remove(app);
-
-        boolean badApp = false;
-        boolean didSomething = false;
-
-        // See if the top visible activity is waiting to run in this process...
-        if (normalMode) {
-            try {
-                didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
-            } catch (Exception e) {
-                Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
-                badApp = true;
-            }
-        }
-
-        // Find any services that should be running in this process...
-        if (!badApp) {
-            try {
-                didSomething |= mServices.attachApplicationLocked(app, processName);
-                checkTime(startTime, "attachApplicationLocked: after mServices.attachApplicationLocked");
-            } catch (Exception e) {
-                Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
-                badApp = true;
-            }
-        }
-
-        // Check if a next-broadcast receiver is in this process...
-        if (!badApp) {
-            try {
-                for (BroadcastQueue queue : mBroadcastQueues) {
-                    didSomething |= queue.onApplicationAttachedLocked(app);
-                }
-                checkTime(startTime, "attachApplicationLocked: after dispatching broadcasts");
-            } catch (Exception e) {
-                // If the app died trying to launch the receiver we declare it 'bad'
-                Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
-                badApp = true;
-            }
-        }
-
-        // Check whether the next backup agent is in this process...
-        if (!badApp && backupTarget != null && backupTarget.app == app) {
-            if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
-                    "New app is backup target, launching agent for " + app);
-            notifyPackageUse(backupTarget.appInfo.packageName,
-                             PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
-            try {
-                thread.scheduleCreateBackupAgent(backupTarget.appInfo,
-                        backupTarget.backupMode, backupTarget.userId, backupTarget.operationType);
-            } catch (Exception e) {
-                Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
-                badApp = true;
-            }
-        }
-
-        if (badApp) {
-            app.killLocked("error during init", ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
-                    true);
-            handleAppDiedLocked(app, pid, false, true, false /* fromBinderDied */);
-            return false;
-        }
-
-        if (!didSomething) {
-            updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
-            checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
-        }
-
-
-        final HostingRecord hostingRecord = app.getHostingRecord();
-        String shortAction = getShortAction(hostingRecord.getAction());
-        FrameworkStatsLog.write(
-                FrameworkStatsLog.PROCESS_START_TIME,
-                app.info.uid,
-                pid,
-                app.info.packageName,
-                FrameworkStatsLog.PROCESS_START_TIME__TYPE__COLD,
-                app.getStartElapsedTime(),
-                (int) (bindApplicationTimeMillis - app.getStartUptime()),
-                (int) (SystemClock.uptimeMillis() - app.getStartUptime()),
-                hostingRecord.getType(),
-                hostingRecord.getName(),
-                shortAction,
-                HostingRecord.getHostingTypeIdStatsd(hostingRecord.getType()),
-                HostingRecord.getTriggerTypeForStatsd(hostingRecord.getTriggerType()));
-        return true;
     }
 
     @Override
@@ -5232,6 +5128,145 @@
         }
     }
 
+    private void finishAttachApplicationInner(long startSeq, int uid, int pid) {
+        final long startTime = SystemClock.uptimeMillis();
+        // Find the application record that is being attached...  either via
+        // the pid if we are running in multiple processes, or just pull the
+        // next app record if we are emulating process with anonymous threads.
+        final ProcessRecord app;
+        synchronized (mPidsSelfLocked) {
+            app = mPidsSelfLocked.get(pid);
+        }
+
+        if (app != null && app.getStartUid() == uid && app.getStartSeq() == startSeq) {
+            mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
+        } else {
+            Slog.wtf(TAG, "Mismatched or missing ProcessRecord: " + app + ". Pid: " + pid
+                    + ". Uid: " + uid);
+            killProcess(pid);
+            killProcessGroup(uid, pid);
+            mProcessList.noteAppKill(pid, uid,
+                    ApplicationExitInfo.REASON_INITIALIZATION_FAILURE,
+                    ApplicationExitInfo.SUBREASON_UNKNOWN,
+                    "wrong startSeq");
+            synchronized (this) {
+                app.killLocked("unexpected process record",
+                        ApplicationExitInfo.REASON_OTHER, true);
+            }
+            return;
+        }
+
+        synchronized (this) {
+            final boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
+            final String processName = app.processName;
+            boolean badApp = false;
+            boolean didSomething = false;
+
+            // See if the top visible activity is waiting to run in this process...
+            if (normalMode) {
+                try {
+                    didSomething = mAtmInternal.attachApplication(app.getWindowProcessController());
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);
+                    badApp = true;
+                }
+            }
+
+            // Find any services that should be running in this process...
+            if (!badApp) {
+                try {
+                    didSomething |= mServices.attachApplicationLocked(app, processName);
+                    checkTime(startTime, "finishAttachApplicationInner: "
+                            + "after mServices.attachApplicationLocked");
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Exception thrown starting services in " + app, e);
+                    badApp = true;
+                }
+            }
+
+            // Check if a next-broadcast receiver is in this process...
+            if (!badApp) {
+                try {
+                    for (BroadcastQueue queue : mBroadcastQueues) {
+                        didSomething |= queue.onApplicationAttachedLocked(app);
+                    }
+                    checkTime(startTime, "finishAttachApplicationInner: "
+                            + "after dispatching broadcasts");
+                } catch (Exception e) {
+                    // If the app died trying to launch the receiver we declare it 'bad'
+                    Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
+                    badApp = true;
+                }
+            }
+
+            // Check whether the next backup agent is in this process...
+            final BackupRecord backupTarget = mBackupTargets.get(app.userId);
+            if (!badApp && backupTarget != null && backupTarget.app == app) {
+                if (DEBUG_BACKUP) {
+                    Slog.v(TAG_BACKUP,
+                            "New app is backup target, launching agent for " + app);
+                }
+
+                notifyPackageUse(backupTarget.appInfo.packageName,
+                        PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
+                try {
+                    app.getThread().scheduleCreateBackupAgent(backupTarget.appInfo,
+                            backupTarget.backupMode, backupTarget.userId,
+                            backupTarget.backupDestination);
+                } catch (Exception e) {
+                    Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e);
+                    badApp = true;
+                }
+            }
+
+            if (badApp) {
+                app.killLocked("error during init",
+                        ApplicationExitInfo.REASON_INITIALIZATION_FAILURE, true);
+                handleAppDiedLocked(app, pid, false, true, false /* fromBinderDied */);
+                return;
+            }
+
+            if (!didSomething) {
+                updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
+                checkTime(startTime, "finishAttachApplicationInner: after updateOomAdjLocked");
+            }
+
+            final HostingRecord hostingRecord = app.getHostingRecord();
+            final String shortAction = getShortAction(hostingRecord.getAction());
+            FrameworkStatsLog.write(
+                    FrameworkStatsLog.PROCESS_START_TIME,
+                    app.info.uid,
+                    pid,
+                    app.info.packageName,
+                    FrameworkStatsLog.PROCESS_START_TIME__TYPE__COLD,
+                    app.getStartElapsedTime(),
+                    (int) (app.getBindApplicationTime() - app.getStartUptime()),
+                    (int) (SystemClock.uptimeMillis() - app.getStartUptime()),
+                    hostingRecord.getType(),
+                    hostingRecord.getName(),
+                    shortAction,
+                    HostingRecord.getHostingTypeIdStatsd(hostingRecord.getType()),
+                    HostingRecord.getTriggerTypeForStatsd(hostingRecord.getTriggerType()));
+        }
+    }
+
+    @Override
+    public final void finishAttachApplication(long startSeq) {
+        final int pid = Binder.getCallingPid();
+        final int uid = Binder.getCallingUid();
+
+        if (pid == MY_PID && uid == SYSTEM_UID) {
+            return;
+        }
+
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            finishAttachApplicationInner(startSeq, uid, pid);
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
     /**
      * @return The last part of the string of an intent's action.
      */
@@ -6141,6 +6176,7 @@
     /**
      * This can be called with or without the global lock held.
      */
+    @PermissionMethod(anyOf = true)
     private void enforceCallingHasAtLeastOnePermission(String func, String... permissions) {
         for (String permission : permissions) {
             if (checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED) {
@@ -12947,6 +12983,13 @@
     }
 
     @Override
+    public boolean shouldServiceTimeOut(ComponentName className, IBinder token) {
+        synchronized (this) {
+            return mServices.shouldServiceTimeOutLocked(className, token);
+        }
+    }
+
+    @Override
     public int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll,
             boolean requireFull, String name, String callerPackage) {
         return mUserController.handleIncomingUser(callingPid, callingUid, userId, allowAll,
@@ -13129,7 +13172,7 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(String packageName, int backupMode, int targetUserId,
-            @OperationType int operationType) {
+            @BackupDestination int backupDestination) {
         if (DEBUG_BACKUP) {
             Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode
                     + " targetUserId=" + targetUserId + " callingUid = " + Binder.getCallingUid()
@@ -13196,7 +13239,7 @@
                         + app.packageName + ": " + e);
             }
 
-            BackupRecord r = new BackupRecord(app, backupMode, targetUserId, operationType);
+            BackupRecord r = new BackupRecord(app, backupMode, targetUserId, backupDestination);
             ComponentName hostingName =
                     (backupMode == ApplicationThreadConstants.BACKUP_MODE_INCREMENTAL)
                             ? new ComponentName(app.packageName, app.backupAgentName)
@@ -13238,7 +13281,7 @@
                 if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "Agent proc already running: " + proc);
                 try {
                     thread.scheduleCreateBackupAgent(app, backupMode, targetUserId,
-                            operationType);
+                            backupDestination);
                 } catch (RemoteException e) {
                     // Will time out on the backup manager side
                 }
@@ -18795,6 +18838,21 @@
             return new ProcessList();
         }
 
+        /**
+         * Returns the {@link BatteryStatsService} instance
+         */
+        public BatteryStatsService getBatteryStatsService() {
+            return new BatteryStatsService(mContext, SystemServiceManager.ensureSystemDir(),
+                BackgroundThread.get().getHandler());
+        }
+
+        /**
+         * Returns the {@link ActiveServices} instance
+         */
+        public ActiveServices getActiveServices(ActivityManagerService service) {
+            return new ActiveServices(service);
+        }
+
         private boolean ensureHasNetworkManagementInternal() {
             if (mNmi == null) {
                 mNmi = LocalServices.getService(NetworkManagementInternal.class);
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 10f5a36..0b94798 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -257,6 +257,8 @@
                     return runForceStop(pw);
                 case "stop-app":
                     return runStopApp(pw);
+                case "clear-recent-apps":
+                    return runClearRecentApps(pw);
                 case "fgs-notification-rate-limit":
                     return runFgsNotificationRateLimit(pw);
                 case "crash":
@@ -904,7 +906,8 @@
         }
     }
 
-    // TODO(b/239982558): might need to support --displayId as well
+    // NOTE: current profiles can only be started on default display (even on automotive builds with
+    // passenger displays), so there's no need to pass a display-id
     private int runProfile(PrintWriter pw) throws RemoteException {
         final PrintWriter err = getErrPrintWriter();
         String profileFile = null;
@@ -1239,6 +1242,11 @@
         return 0;
     }
 
+    int runClearRecentApps(PrintWriter pw) throws RemoteException {
+        mTaskInterface.removeAllVisibleRecentTasks();
+        return 0;
+    }
+
     int runFgsNotificationRateLimit(PrintWriter pw) throws RemoteException {
         final String toggleValue = getNextArgRequired();
         final boolean enable;
diff --git a/services/core/java/com/android/server/am/BackupRecord.java b/services/core/java/com/android/server/am/BackupRecord.java
index d419856..0b056d7 100644
--- a/services/core/java/com/android/server/am/BackupRecord.java
+++ b/services/core/java/com/android/server/am/BackupRecord.java
@@ -16,8 +16,7 @@
 
 package com.android.server.am;
 
-import android.app.backup.BackupManager;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.content.pm.ApplicationInfo;
 
 /** @hide */
@@ -32,16 +31,16 @@
     final ApplicationInfo appInfo;         // information about BackupAgent's app
     final int userId;                      // user for which backup is performed
     final int backupMode;                  // full backup / incremental / restore
-    @OperationType  final int operationType; // see BackupManager#OperationType
+    @BackupDestination final int backupDestination; // see BackupAnnotations#BackupDestination
     ProcessRecord app;                     // where this agent is running or null
 
     // ----- Implementation -----
 
-    BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _operationType) {
+    BackupRecord(ApplicationInfo _appInfo, int _backupMode, int _userId, int _backupDestination) {
         appInfo = _appInfo;
         backupMode = _backupMode;
         userId = _userId;
-        operationType = _operationType;
+        backupDestination = _backupDestination;
     }
 
     public String toString() {
diff --git a/services/core/java/com/android/server/am/BroadcastConstants.java b/services/core/java/com/android/server/am/BroadcastConstants.java
index 04ba757..1eebd01 100644
--- a/services/core/java/com/android/server/am/BroadcastConstants.java
+++ b/services/core/java/com/android/server/am/BroadcastConstants.java
@@ -153,6 +153,11 @@
             "bcast_extra_running_urgent_process_queues";
     private static final int DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES = 1;
 
+    public int MAX_CONSECUTIVE_URGENT_DISPATCHES = DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES;
+    private static final String KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES =
+            "bcast_max_consecutive_urgent_dispatches";
+    private static final int DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES = 3;
+
     /**
      * For {@link BroadcastQueueModernImpl}: Maximum number of active broadcasts
      * to dispatch to a "running" process queue before we retire them back to
@@ -333,6 +338,9 @@
             EXTRA_RUNNING_URGENT_PROCESS_QUEUES = getDeviceConfigInt(
                     KEY_EXTRA_RUNNING_URGENT_PROCESS_QUEUES,
                     DEFAULT_EXTRA_RUNNING_URGENT_PROCESS_QUEUES);
+            MAX_CONSECUTIVE_URGENT_DISPATCHES = getDeviceConfigInt(
+                    KEY_MAX_CONSECUTIVE_URGENT_DISPATCHES,
+                    DEFAULT_MAX_CONSECUTIVE_URGENT_DISPATCHES);
             MAX_RUNNING_ACTIVE_BROADCASTS = getDeviceConfigInt(KEY_MAX_RUNNING_ACTIVE_BROADCASTS,
                     DEFAULT_MAX_RUNNING_ACTIVE_BROADCASTS);
             MAX_PENDING_BROADCASTS = getDeviceConfigInt(KEY_MAX_PENDING_BROADCASTS,
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 0f9c775..66d7fc9 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -147,6 +147,12 @@
     private boolean mActiveViaColdStart;
 
     /**
+     * Number of consecutive urgent broadcasts that have been dispatched
+     * since the last non-urgent dispatch.
+     */
+    private int mActiveCountConsecutiveUrgent;
+
+    /**
      * Count of pending broadcasts of these various flavors.
      */
     private int mCountForeground;
@@ -546,19 +552,47 @@
      * {@link #isEmpty()} being false.
      */
     SomeArgs removeNextBroadcast() {
-        ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
+        final ArrayDeque<SomeArgs> queue = queueForNextBroadcast();
+        if (queue == mPendingUrgent) {
+            mActiveCountConsecutiveUrgent++;
+        } else {
+            mActiveCountConsecutiveUrgent = 0;
+        }
         return queue.removeFirst();
     }
 
     @Nullable ArrayDeque<SomeArgs> queueForNextBroadcast() {
-        if (!mPendingUrgent.isEmpty()) {
-            return mPendingUrgent;
-        } else if (!mPending.isEmpty()) {
-            return mPending;
+        ArrayDeque<SomeArgs> nextUrgent = mPendingUrgent.isEmpty() ? null : mPendingUrgent;
+        ArrayDeque<SomeArgs> nextNormal = null;
+        if (!mPending.isEmpty()) {
+            nextNormal = mPending;
         } else if (!mPendingOffload.isEmpty()) {
-            return mPendingOffload;
+            nextNormal = mPendingOffload;
         }
-        return null;
+        // nothing urgent pending, no further decisionmaking
+        if (nextUrgent == null) {
+            return nextNormal;
+        }
+        // nothing but urgent pending, also no further decisionmaking
+        if (nextNormal == null) {
+            return nextUrgent;
+        }
+
+        // Starvation mitigation: although we prioritize urgent broadcasts by default,
+        // we allow non-urgent deliveries to make steady progress even if urgent
+        // broadcasts are arriving faster than they can be dispatched.
+        //
+        // We do not try to defer to the next non-urgent broadcast if that broadcast
+        // is ordered and still blocked on delivery to other recipients.
+        final SomeArgs nextNormalArgs = nextNormal.peekFirst();
+        final BroadcastRecord rNormal = (BroadcastRecord) nextNormalArgs.arg1;
+        final int nextNormalIndex = nextNormalArgs.argi1;
+        final BroadcastRecord rUrgent = (BroadcastRecord) nextUrgent.peekFirst().arg1;
+        final boolean canTakeNormal =
+                mActiveCountConsecutiveUrgent >= constants.MAX_CONSECUTIVE_URGENT_DISPATCHES
+                        && rNormal.enqueueTime <= rUrgent.enqueueTime
+                        && !blockedOnOrderedDispatch(rNormal, nextNormalIndex);
+        return canTakeNormal ? nextNormal : nextUrgent;
     }
 
     /**
@@ -710,6 +744,18 @@
         }
     }
 
+    private boolean blockedOnOrderedDispatch(BroadcastRecord r, int index) {
+        final int blockedUntilTerminalCount = r.blockedUntilTerminalCount[index];
+
+        // We might be blocked waiting for other receivers to finish,
+        // typically for an ordered broadcast or priority traunches
+        if (r.terminalCount < blockedUntilTerminalCount
+                && !isDeliveryStateTerminal(r.getDeliveryState(index))) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Update {@link #getRunnableAt()} if it's currently invalidated.
      */
@@ -718,13 +764,11 @@
         if (next != null) {
             final BroadcastRecord r = (BroadcastRecord) next.arg1;
             final int index = next.argi1;
-            final int blockedUntilTerminalCount = r.blockedUntilTerminalCount[index];
             final long runnableAt = r.enqueueTime;
 
-            // We might be blocked waiting for other receivers to finish,
-            // typically for an ordered broadcast or priority traunches
-            if (r.terminalCount < blockedUntilTerminalCount
-                    && !isDeliveryStateTerminal(r.getDeliveryState(index))) {
+            // If we're specifically queued behind other ordered dispatch activity,
+            // we aren't runnable yet
+            if (blockedOnOrderedDispatch(r, index)) {
                 mRunnableAt = Long.MAX_VALUE;
                 mRunnableAtReason = REASON_BLOCKED;
                 return;
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 8082e45..66a8bab 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1818,21 +1818,31 @@
                 newAdj = PERCEPTIBLE_APP_ADJ;
                 newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
 
-            } else if (psr.hasForegroundServices() && !psr.hasNonShortForegroundServices()) {
-                // For short FGS.
-                adjType = "fg-service-short";
-                // We use MEDIUM_APP_ADJ + 1 so we can tell apart EJ (which uses MEDIUM_APP_ADJ + 1)
-                // from short-FGS.
-                // (We use +1 and +2, not +0 and +1, to be consistent with the following
-                // RECENT_FOREGROUND_APP_ADJ tweak)
-                newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 1;
+            } else if (psr.hasForegroundServices()) {
+                // If we get here, hasNonShortForegroundServices() must be false.
 
-                // Short-FGS gets a below-BFGS procstate, so it can't start another FGS from it.
-                newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+                // TODO(short-service): Proactively run OomAjudster when the grace period finish.
+                if (psr.areAllShortForegroundServicesProcstateTimedOut(now)) {
+                    // All the short-FGSes within this process are timed out. Don't promote to FGS.
+                    // TODO(short-service): Should we set some unique oom-adj to make it detectable,
+                    // in a long trace?
+                } else {
+                    // For short FGS.
+                    adjType = "fg-service-short";
+                    // We use MEDIUM_APP_ADJ + 1 so we can tell apart EJ
+                    // (which uses MEDIUM_APP_ADJ + 1)
+                    // from short-FGS.
+                    // (We use +1 and +2, not +0 and +1, to be consistent with the following
+                    // RECENT_FOREGROUND_APP_ADJ tweak)
+                    newAdj = PERCEPTIBLE_MEDIUM_APP_ADJ + 1;
 
-                // Same as EJ, we explicitly grant network access to short FGS,
-                // even when battery saver or data saver is enabled.
-                capabilityFromFGS |= PROCESS_CAPABILITY_NETWORK;
+                    // Short-FGS gets a below-BFGS procstate, so it can't start another FGS from it.
+                    newProcState = PROCESS_STATE_IMPORTANT_FOREGROUND;
+
+                    // Same as EJ, we explicitly grant network access to short FGS,
+                    // even when battery saver or data saver is enabled.
+                    capabilityFromFGS |= PROCESS_CAPABILITY_NETWORK;
+                }
             }
 
             if (adjType != null) {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index ecea96e..4d559b0 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2508,7 +2508,7 @@
     }
 
     @GuardedBy("mService")
-    private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
+    String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
         StringBuilder sb = null;
         if (app.isKilledByAm()) {
             if (sb == null) sb = new StringBuilder();
@@ -4205,7 +4205,7 @@
                     total - mLruProcessServiceStart);
             writeProcessOomListToProto(proto,
                     ActivityManagerServiceDumpProcessesProto.LruProcesses.LIST, mService,
-                    mLruProcesses, false, dumpPackage);
+                    mLruProcesses, true, dumpPackage);
             proto.end(lruToken);
         }
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 0a8c640..4706c268 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -200,6 +200,11 @@
     private volatile long mStartElapsedTime;
 
     /**
+     * When the process was sent the bindApplication request
+     */
+    private volatile long mBindApplicationTime;
+
+    /**
      * This will be same as {@link #uid} usually except for some apps used during factory testing.
      */
     private volatile int mStartUid;
@@ -739,6 +744,10 @@
         return mStartElapsedTime;
     }
 
+    long getBindApplicationTime() {
+        return mBindApplicationTime;
+    }
+
     int getStartUid() {
         return mStartUid;
     }
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 13264db..df442e8 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -175,6 +175,9 @@
         }
     }
 
+    /**
+     * @return true if this process has any foreground services (even timed-out short-FGS)
+     */
     boolean hasForegroundServices() {
         return mHasForegroundServices;
     }
@@ -224,6 +227,33 @@
         return mFgServiceTypes != ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
     }
 
+    /**
+     * @return if this process:
+     * - has at least one short-FGS
+     * - has no other types of FGS
+     * - and all the short-FGSes are procstate-timed out.
+     */
+    boolean areAllShortForegroundServicesProcstateTimedOut(long nowUptime) {
+        if (!mHasForegroundServices) { // Process has no FGS?
+            return false;
+        }
+        if (hasNonShortForegroundServices()) {  // Any non-short FGS running?
+            return false;
+        }
+        // Now we need to look at all short-FGS within the process and see if all of them are
+        // procstate-timed-out or not.
+        for (int i = mServices.size() - 1; i >= 0; i--) {
+            final ServiceRecord sr = mServices.valueAt(i);
+            if (!sr.isShortFgs() || !sr.hasShortFgsInfo()) {
+                continue;
+            }
+            if (sr.getShortFgsInfo().getProcStateDemoteTime() >= nowUptime) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     int getReportedForegroundServiceTypes() {
         return mRepFgServiceTypes;
     }
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 0468152..ef195aa 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -128,6 +128,7 @@
     boolean delayedStop;    // service has been stopped but is in a delayed start?
     boolean stopIfKilled;   // last onStart() said to stop if service killed?
     boolean callStart;      // last onStart() has asked to always be called on restart.
+    int startCommandResult; // last result from onStartCommand(), only for dumpsys.
     int executeNesting;     // number of outstanding operations keeping foreground.
     boolean executeFg;      // should we be executing in the foreground?
     long executingStart;    // start time of last execute request.
@@ -315,6 +316,84 @@
     final ArrayList<StartItem> pendingStarts = new ArrayList<StartItem>();
                             // start() arguments that haven't yet been delivered.
 
+    /**
+     * Information specific to "SHORT_SERVICE" FGS.
+     */
+    class ShortFgsInfo {
+        /** Time FGS started */
+        private final long mStartTime;
+
+        /**
+         * Copied from {@link #mStartForegroundCount}. If this is different from the parent's,
+         * that means this instance is stale.
+         */
+        private int mStartForegroundCount;
+
+        /** Service's "start ID" when this short-service started. */
+        private int mStartId;
+
+        ShortFgsInfo(long startTime) {
+            mStartTime = startTime;
+            update();
+        }
+
+        /**
+         * Update {@link #mStartForegroundCount} and {@link #mStartId}.
+         * (but not {@link #mStartTime})
+         */
+        public void update() {
+            this.mStartForegroundCount = ServiceRecord.this.mStartForegroundCount;
+            this.mStartId = getLastStartId();
+        }
+
+        long getStartTime() {
+            return mStartTime;
+        }
+
+        int getStartForegroundCount() {
+            return mStartForegroundCount;
+        }
+
+        int getStartId() {
+            return mStartId;
+        }
+
+        /**
+         * @return whether this {@link ShortFgsInfo} is still "current" or not -- i.e.
+         * it's "start foreground count" is the same as that of the ServiceRecord's.
+         *
+         * Note, we do _not_ check the "start id" here, because the start id increments if the
+         * app calls startService() or startForegroundService() on the same service,
+         * but that will _not_ update the ShortFgsInfo, and will not extend the timeout.
+         */
+        boolean isCurrent() {
+            return this.mStartForegroundCount == ServiceRecord.this.mStartForegroundCount;
+        }
+
+        /** Time when Service.onTimeout() should be called */
+        long getTimeoutTime() {
+            return mStartTime + ams.mConstants.mShortFgsTimeoutDuration;
+        }
+
+        /** Time when the procstate should be lowered. */
+        long getProcStateDemoteTime() {
+            return mStartTime + ams.mConstants.mShortFgsTimeoutDuration
+                    + ams.mConstants.mShortFgsProcStateExtraWaitDuration;
+        }
+
+        /** Time when the app should be declared ANR. */
+        long getAnrTime() {
+            return mStartTime + ams.mConstants.mShortFgsTimeoutDuration
+                    + ams.mConstants.mShortFgsAnrExtraWaitDuration;
+        }
+    }
+
+    /**
+     * Keep track of short-fgs specific information. This field gets cleared when the timeout
+     * stops.
+     */
+    private ShortFgsInfo mShortFgsInfo;
+
     void dumpStartList(PrintWriter pw, String prefix, List<StartItem> list, long now) {
         final int N = list.size();
         for (int i=0; i<N; i++) {
@@ -400,6 +479,7 @@
             proto.write(ServiceRecordProto.Start.DELAYED_STOP, delayedStop);
             proto.write(ServiceRecordProto.Start.STOP_IF_KILLED, stopIfKilled);
             proto.write(ServiceRecordProto.Start.LAST_START_ID, lastStartId);
+            proto.write(ServiceRecordProto.Start.START_COMMAND_RESULT, startCommandResult);
             proto.end(startToken);
         }
 
@@ -455,6 +535,21 @@
                 }
             }
         }
+        if (mShortFgsInfo != null && mShortFgsInfo.isCurrent()) {
+            final long shortFgsToken = proto.start(ServiceRecordProto.SHORT_FGS_INFO);
+            proto.write(ServiceRecordProto.ShortFgsInfo.START_TIME,
+                    mShortFgsInfo.getStartTime());
+            proto.write(ServiceRecordProto.ShortFgsInfo.START_ID,
+                    mShortFgsInfo.getStartId());
+            proto.write(ServiceRecordProto.ShortFgsInfo.TIMEOUT_TIME,
+                    mShortFgsInfo.getTimeoutTime());
+            proto.write(ServiceRecordProto.ShortFgsInfo.PROC_STATE_DEMOTE_TIME,
+                    mShortFgsInfo.getProcStateDemoteTime());
+            proto.write(ServiceRecordProto.ShortFgsInfo.ANR_TIME,
+                    mShortFgsInfo.getAnrTime());
+            proto.end(shortFgsToken);
+        }
+
         proto.end(token);
     }
 
@@ -508,8 +603,25 @@
         }
         if (isForeground || foregroundId != 0) {
             pw.print(prefix); pw.print("isForeground="); pw.print(isForeground);
-                    pw.print(" foregroundId="); pw.print(foregroundId);
-                    pw.print(" foregroundNoti="); pw.println(foregroundNoti);
+            pw.print(" foregroundId="); pw.print(foregroundId);
+            pw.printf(" types=%08X", foregroundServiceType);
+            pw.print(" foregroundNoti="); pw.println(foregroundNoti);
+
+            if (isShortFgs() && mShortFgsInfo != null) {
+                pw.print(prefix); pw.print("isShortFgs=true");
+                pw.print(" startId="); pw.print(mShortFgsInfo.getStartId());
+                pw.print(" startForegroundCount=");
+                pw.print(mShortFgsInfo.getStartForegroundCount());
+                pw.print(" startTime=");
+                TimeUtils.formatDuration(mShortFgsInfo.getStartTime(), now, pw);
+                pw.print(" timeout=");
+                TimeUtils.formatDuration(mShortFgsInfo.getTimeoutTime(), now, pw);
+                pw.print(" demoteTime=");
+                TimeUtils.formatDuration(mShortFgsInfo.getProcStateDemoteTime(), now, pw);
+                pw.print(" anrTime=");
+                TimeUtils.formatDuration(mShortFgsInfo.getAnrTime(), now, pw);
+                pw.println();
+            }
         }
         if (mIsFgsDelegate) {
             pw.print(prefix); pw.print("isFgsDelegate="); pw.println(mIsFgsDelegate);
@@ -535,6 +647,7 @@
                     pw.print(" stopIfKilled="); pw.print(stopIfKilled);
                     pw.print(" callStart="); pw.print(callStart);
                     pw.print(" lastStartId="); pw.println(lastStartId);
+                    pw.print(" startCommandResult="); pw.println(startCommandResult);
         }
         if (executeNesting != 0) {
             pw.print(prefix); pw.print("executeNesting="); pw.print(executeNesting);
@@ -590,6 +703,32 @@
         }
     }
 
+    /** Used only for tests */
+    private ServiceRecord(ActivityManagerService ams) {
+        this.ams = ams;
+        name = null;
+        instanceName = null;
+        shortInstanceName = null;
+        definingPackageName = null;
+        definingUid = 0;
+        intent = null;
+        serviceInfo = null;
+        userId = 0;
+        packageName = null;
+        processName = null;
+        permission = null;
+        exported = false;
+        restarter = null;
+        createRealTime = 0;
+        isSdkSandbox = false;
+        sdkSandboxClientAppUid = 0;
+        sdkSandboxClientAppPackage = null;
+    }
+
+    public static ServiceRecord newEmptyInstanceForTest(ActivityManagerService ams) {
+        return new ServiceRecord(ams);
+    }
+
     ServiceRecord(ActivityManagerService ams, ComponentName name,
             ComponentName instanceName, String definingPackageName, int definingUid,
             Intent.FilterComparison intent, ServiceInfo sInfo, boolean callerIsFg,
@@ -771,7 +910,9 @@
      *         has no reason to start again. Note this condition doesn't consider the bindings.
      */
     boolean canStopIfKilled(boolean isStartCanceled) {
-        // TODO(short-service): If it's a "short FGS", we should stop it if killed.
+        if (isShortFgs()) { // Short-FGS should always stop if killed.
+            return true;
+        }
         return startRequested && (stopIfKilled || isStartCanceled) && pendingStarts.isEmpty();
     }
 
@@ -1235,7 +1376,71 @@
         // Note if the type contains FOREGROUND_SERVICE_TYPE_SHORT_SERVICE but also other bits
         // set, it's _not_ considered be a short service. (because we shouldn't apply
         // the short-service restrictions)
-        return isForeground
+        // (But we should be preventing mixture of FOREGROUND_SERVICE_TYPE_SHORT_SERVICE
+        // and other types in Service.startForeground().)
+        return startRequested && isForeground
                 && (foregroundServiceType == ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE);
     }
+
+    public ShortFgsInfo getShortFgsInfo() {
+        return isShortFgs() ? mShortFgsInfo : null;
+    }
+
+    /**
+     * Call it when a short FGS starts.
+     */
+    public void setShortFgsInfo(long uptimeNow) {
+        this.mShortFgsInfo = new ShortFgsInfo(uptimeNow);
+    }
+
+    /** @return whether {@link #mShortFgsInfo} is set or not. */
+    public boolean hasShortFgsInfo() {
+        return mShortFgsInfo != null;
+    }
+
+    /**
+     * Call it when a short FGS stops.
+     */
+    public void clearShortFgsInfo() {
+        this.mShortFgsInfo = null;
+    }
+
+    /**
+     * @return true if it's a short FGS that's still up and running, and should be timed out.
+     */
+    public boolean shouldTriggerShortFgsTimeout() {
+        if (!isAppAlive()) {
+            return false;
+        }
+        if (!this.startRequested || !isShortFgs() || mShortFgsInfo == null
+                || !mShortFgsInfo.isCurrent()) {
+            return false;
+        }
+        return mShortFgsInfo.getTimeoutTime() < SystemClock.uptimeMillis();
+    }
+
+    /**
+     * @return true if it's a short FGS that's still up and running, and should be declared
+     * an ANR.
+     */
+    public boolean shouldTriggerShortFgsAnr() {
+        if (!isAppAlive()) {
+            return false;
+        }
+        if (!this.startRequested || !isShortFgs() || mShortFgsInfo == null
+                || !mShortFgsInfo.isCurrent()) {
+            return false;
+        }
+        return mShortFgsInfo.getAnrTime() < SystemClock.uptimeMillis();
+    }
+
+    private boolean isAppAlive() {
+        if (app == null) {
+            return false;
+        }
+        if (app.getThread() == null || app.isKilled() || app.isKilledByAm()) {
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index f16347f..f22624c 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -104,6 +104,7 @@
         DeviceConfig.NAMESPACE_VIRTUALIZATION_FRAMEWORK_NATIVE,
         DeviceConfig.NAMESPACE_WINDOW_MANAGER_NATIVE_BOOT,
         DeviceConfig.NAMESPACE_MEMORY_SAFETY_NATIVE,
+        DeviceConfig.NAMESPACE_HDMI_CONTROL
     };
 
     private final String[] mGlobalSettings;
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 060e3ee..2a69363 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -18,6 +18,34 @@
       ]
     },
     {
+      "name": "CtsAppFgsTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
+      "name": "CtsShortFgsTestCases",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.LargeTest"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    },
+    {
       "name": "FrameworksServicesTests",
       "options": [
         {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4d86140..a7e95fb 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -80,7 +80,6 @@
 import android.os.IProgressListener;
 import android.os.IRemoteCallback;
 import android.os.IUserManager;
-import android.os.Looper;
 import android.os.Message;
 import android.os.PowerWhitelistManager;
 import android.os.Process;
@@ -100,7 +99,6 @@
 import android.util.IntArray;
 import android.util.Pair;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
@@ -177,7 +175,8 @@
     static final int START_USER_SWITCH_FG_MSG = 120;
     static final int COMPLETE_USER_SWITCH_MSG = 130;
     static final int USER_COMPLETED_EVENT_MSG = 140;
-    static final int USER_VISIBILITY_CHANGED_MSG = 150;
+
+    private static final int NO_ARG2 = 0;
 
     // Message constant to clear {@link UserJourneySession} from {@link mUserIdToUserJourneyMap} if
     // the user journey, defined in the UserLifecycleJourneyReported atom for statsd, is not
@@ -437,19 +436,11 @@
     /** @see #getLastUserUnlockingUptime */
     private volatile long mLastUserUnlockingUptime = 0;
 
-    // TODO(b/244333150) remove this array and let UserVisibilityMediator call the listeners
-    // directly, as that class should be responsible for all user visibility logic (for example,
-    // when the foreground user is switched out, its profiles also become invisible)
     /**
-     * List of visible users (as defined by {@link UserManager#isUserVisible()}).
-     *
-     * <p>It's only used to call {@link UserManagerInternal} when the visibility is changed upon
-     * the user starting or stopping.
-     *
-     * <p>Note: only the key is used, not the value.
+     * Pending user starts waiting for shutdown step to complete.
      */
     @GuardedBy("mLock")
-    private final SparseBooleanArray mVisibleUsers = new SparseBooleanArray();
+    private final List<PendingUserStart> mPendingUserStarts = new ArrayList<>();
 
     private final UserLifecycleListener mUserLifecycleListener = new UserLifecycleListener() {
         @Override
@@ -1087,29 +1078,13 @@
             uss.setState(UserState.STATE_STOPPING);
             UserManagerInternal userManagerInternal = mInjector.getUserManagerInternal();
             userManagerInternal.setUserState(userId, uss.state);
-            // TODO(b/239982558): for now we're just updating the user's visibility, but most likely
-            // we'll need to remove this call and handle that as part of the user state workflow
-            // instead.
             userManagerInternal.unassignUserFromDisplayOnStop(userId);
 
-            final boolean visibilityChanged;
-            boolean visibleBefore;
-            synchronized (mLock) {
-                visibleBefore = mVisibleUsers.get(userId);
-                if (visibleBefore) {
-                    deleteVisibleUserLocked(userId);
-                    visibilityChanged = true;
-                } else {
-                    visibilityChanged = false;
-                }
-            }
-
             updateStartedUserArrayLU();
 
             final boolean allowDelayedLockingCopied = allowDelayedLocking;
             Runnable finishUserStoppingAsync = () ->
-                    mHandler.post(() -> finishUserStopping(userId, uss, allowDelayedLockingCopied,
-                            visibilityChanged));
+                    mHandler.post(() -> finishUserStopping(userId, uss, allowDelayedLockingCopied));
 
             if (mInjector.getUserManager().isPreCreated(userId)) {
                 finishUserStoppingAsync.run();
@@ -1146,22 +1121,8 @@
         }
     }
 
-    private void addVisibleUserLocked(@UserIdInt int userId) {
-        if (DEBUG_MU) {
-            Slogf.d(TAG, "adding %d to mVisibleUsers", userId);
-        }
-        mVisibleUsers.put(userId, true);
-    }
-
-    private void deleteVisibleUserLocked(@UserIdInt int userId) {
-        if (DEBUG_MU) {
-            Slogf.d(TAG, "deleting %d from mVisibleUsers", userId);
-        }
-        mVisibleUsers.delete(userId);
-    }
-
     private void finishUserStopping(final int userId, final UserState uss,
-            final boolean allowDelayedLocking, final boolean visibilityChanged) {
+            final boolean allowDelayedLocking) {
         EventLog.writeEvent(EventLogTags.UC_FINISH_USER_STOPPING, userId);
         synchronized (mLock) {
             if (uss.state != UserState.STATE_STOPPING) {
@@ -1179,9 +1140,6 @@
                 BatteryStats.HistoryItem.EVENT_USER_RUNNING_FINISH,
                 Integer.toString(userId), userId);
         mInjector.getSystemServiceManager().onUserStopping(userId);
-        if (visibilityChanged) {
-            mInjector.onUserVisibilityChanged(userId, /* visible= */ false);
-        }
 
         Runnable finishUserStoppedAsync = () ->
                 mHandler.post(() -> finishUserStopped(uss, allowDelayedLocking));
@@ -1231,9 +1189,13 @@
             } else {
                 stopped = true;
                 // User can no longer run.
+                Slogf.i(TAG, "Removing user state from UserController.mStartedUsers for user #"
+                        + userId + " as a result of user being stopped");
                 mStartedUsers.remove(userId);
+
                 mUserLru.remove(Integer.valueOf(userId));
                 updateStartedUserArrayLU();
+
                 if (allowDelayedLocking && !keyEvictedCallbacks.isEmpty()) {
                     Slogf.wtf(TAG,
                             "Delayed locking enabled while KeyEvictedCallbacks not empty, userId:"
@@ -1247,7 +1209,10 @@
             }
         }
         if (stopped) {
+            Slogf.i(TAG, "Removing user state from UserManager.mUserStates for user #" + userId
+                    + " as a result of user being stopped");
             mInjector.getUserManagerInternal().removeUserState(userId);
+
             mInjector.activityManagerOnUserStopped(userId);
             // Clean up all state and processes associated with the user.
             // Kill all the processes for the user.
@@ -1275,10 +1240,13 @@
                     USER_LIFECYCLE_EVENT_STATE_FINISH);
             clearSessionId(userId);
 
-            if (!lockUser) {
-                return;
+            if (lockUser) {
+                dispatchUserLocking(userIdToLock, keyEvictedCallbacks);
             }
-            dispatchUserLocking(userIdToLock, keyEvictedCallbacks);
+
+            // Resume any existing pending user start,
+            // which was paused while the SHUTDOWN flow of the user was in progress.
+            resumePendingUserStarts(userId);
         } else {
             logUserLifecycleEvent(userId, USER_LIFECYCLE_EVENT_STOP_USER,
                     USER_LIFECYCLE_EVENT_STATE_NONE);
@@ -1286,6 +1254,31 @@
         }
     }
 
+    /**
+     * Resume any existing pending user start for the specified userId which was paused
+     * while the shutdown flow of the user was in progress.
+     * Remove all the handled user starts from mPendingUserStarts.
+     * @param userId the id of the user
+     */
+    private void resumePendingUserStarts(@UserIdInt int userId) {
+        synchronized (mLock) {
+            final List<PendingUserStart> handledUserStarts = new ArrayList<>();
+
+            for (PendingUserStart userStart: mPendingUserStarts) {
+                if (userStart.userId == userId) {
+                    Slogf.i(TAG, "resumePendingUserStart for" + userStart);
+                    mHandler.post(() -> startUser(userStart.userId,
+                            userStart.isForeground, userStart.unlockListener));
+
+                    handledUserStarts.add(userStart);
+                }
+            }
+            // remove all the pending user starts which are now handled
+            mPendingUserStarts.removeAll(handledUserStarts);
+        }
+    }
+
+
     private void dispatchUserLocking(@UserIdInt int userId,
             @Nullable List<KeyEvictedCallback> keyEvictedCallbacks) {
         // Evict the user's credential encryption key. Performed on FgThread to make it
@@ -1299,6 +1292,7 @@
                 }
             }
             try {
+                Slogf.i(TAG, "Locking CE storage for user #" + userId);
                 mInjector.getStorageManager().lockUserKey(userId);
             } catch (RemoteException re) {
                 throw re.rethrowAsRuntimeException();
@@ -1549,13 +1543,32 @@
         return startUserNoChecks(userId, Display.DEFAULT_DISPLAY, foreground, unlockListener);
     }
 
-    // TODO(b/239982558): add javadoc (need to wait until the intents / SystemService callbacks are
-    // defined
+    /**
+     * Starts a user in background and make it visible in the given display.
+     *
+     * <p>This call will trigger the usual "user started" lifecycle events (i.e., `SystemService`
+     * callbacks and app intents), plus a call to
+     * {@link UserManagerInternal.UserVisibilityListener#onUserVisibilityChanged(int, boolean)} if
+     * the user visibility changed. Notice that the visibility change is independent of the user
+     * workflow state, and they can mismatch in some corner events (for example, if the user was
+     * already running in the background but not associated with a display, this call for that user
+     * would not trigger any lifecycle event but would trigger {@code onUserVisibilityChanged}).
+     *
+     * <p>See {@link ActivityManager#startUserInBackgroundOnSecondaryDisplay(int, int)} for more
+     * semantics.
+     *
+     * @param userId user to be started
+     * @param displayId display where the user will be visible
+     *
+     * @return whether the user was started
+     */
     boolean startUserOnSecondaryDisplay(@UserIdInt int userId, int displayId) {
         checkCallingHasOneOfThosePermissions("startUserOnSecondaryDisplay",
                 MANAGE_USERS, INTERACT_ACROSS_USERS);
 
         // DEFAULT_DISPLAY is used for the current foreground user only
+        // TODO(b/245939659): might need to move this check to UserVisibilityMediator to support
+        // passenger-only screens
         Preconditions.checkArgument(displayId != Display.DEFAULT_DISPLAY,
                 "Cannot use DEFAULT_DISPLAY");
 
@@ -1563,7 +1576,7 @@
             return startUserNoChecks(userId, displayId, /* foreground= */ false,
                     /* unlockListener= */ null);
         } catch (RuntimeException e) {
-            Slogf.w(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
+            Slogf.e(TAG, "startUserOnSecondaryDisplay(%d, %d) failed: %s", userId, displayId, e);
             return false;
         }
     }
@@ -1655,26 +1668,13 @@
                     userInfo.profileGroupId, foreground, displayId);
             t.traceEnd();
 
-            boolean visible;
-            switch (result) {
-                case UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE:
-                    visible = true;
-                    break;
-                case UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE:
-                    visible = false;
-                    break;
-                default:
-                    Slogf.wtf(TAG, "Wrong result from assignUserToDisplayOnStart(): %d", result);
-                    // Fall through
-                case UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE:
-                    Slogf.e(TAG, "%s user(%d) / display (%d) assignment failed: %s",
-                            (foreground ? "fg" : "bg"), userId, displayId,
-                            UserManagerInternal.userAssignmentResultToString(result));
-                    return false;
+            if (result == UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE) {
+                Slogf.e(TAG, "%s user(%d) / display (%d) assignment failed: %s",
+                        (foreground ? "fg" : "bg"), userId, displayId,
+                        UserManagerInternal.userAssignmentResultToString(result));
+                return false;
             }
 
-
-            // TODO(b/239982558): might need something similar for bg users on secondary display
             if (foreground && isUserSwitchUiEnabled()) {
                 t.traceBegin("startFreezingScreen");
                 mInjector.getWindowManager().startFreezingScreen(
@@ -1698,10 +1698,11 @@
                     updateStartedUserArrayLU();
                     needStart = true;
                     updateUmState = true;
-                } else if (uss.state == UserState.STATE_SHUTDOWN && !isCallingOnHandlerThread()) {
+                } else if (uss.state == UserState.STATE_SHUTDOWN) {
                     Slogf.i(TAG, "User #" + userId
-                            + " is shutting down - will start after full stop");
-                    mHandler.post(() -> startUser(userId, foreground, unlockListener));
+                            + " is shutting down - will start after full shutdown");
+                    mPendingUserStarts.add(new PendingUserStart(userId,
+                            foreground, unlockListener));
                     t.traceEnd(); // updateStartedUserArrayStarting
                     return true;
                 }
@@ -1724,23 +1725,15 @@
                 // Make sure the old user is no longer considering the display to be on.
                 mInjector.reportGlobalUsageEvent(UsageEvents.Event.SCREEN_NON_INTERACTIVE);
                 boolean userSwitchUiEnabled;
-                // TODO(b/244333150): temporary state until the callback logic is moved to
-                // UserVisibilityManager
-                int previousCurrentUserId; boolean notifyPreviousCurrentUserId;
                 synchronized (mLock) {
-                    previousCurrentUserId = mCurrentUserId;
-                    notifyPreviousCurrentUserId = mVisibleUsers.get(previousCurrentUserId);
-                    if (notifyPreviousCurrentUserId) {
-                        deleteVisibleUserLocked(previousCurrentUserId);
-                    }
                     mCurrentUserId = userId;
                     mTargetUserId = UserHandle.USER_NULL; // reset, mCurrentUserId has caught up
                     userSwitchUiEnabled = mUserSwitchUiEnabled;
                 }
                 mInjector.updateUserConfiguration();
-                // TODO(b/244644281): updateProfileRelatedCaches() is called on both if and else
-                // parts, ideally it should be moved outside, but for now it's not as there are many
-                // calls to external components here afterwards
+                // NOTE: updateProfileRelatedCaches() is called on both if and else parts, ideally
+                // it should be moved outside, but for now it's not as there are many calls to
+                // external components here afterwards
                 updateProfileRelatedCaches();
                 mInjector.getWindowManager().setCurrentUser(userId);
                 mInjector.reportCurWakefulnessUsageEvent();
@@ -1753,10 +1746,6 @@
                         mInjector.getWindowManager().lockNow(null);
                     }
                 }
-                if (notifyPreviousCurrentUserId) {
-                    mHandler.sendMessage(mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG,
-                            previousCurrentUserId, 0));
-                }
 
             } else {
                 final Integer currentUserIdInt = mCurrentUserId;
@@ -1768,12 +1757,6 @@
             }
             t.traceEnd();
 
-            if (visible) {
-                synchronized (mLock) {
-                    addVisibleUserLocked(userId);
-                }
-            }
-
             // Make sure user is in the started state.  If it is currently
             // stopping, we need to knock that off.
             if (uss.state == UserState.STATE_STOPPING) {
@@ -1810,20 +1793,10 @@
                 // Booting up a new user, need to tell system services about it.
                 // Note that this is on the same handler as scheduling of broadcasts,
                 // which is important because it needs to go first.
-                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId,
-                        visible ? 1 : 0));
+                mHandler.sendMessage(mHandler.obtainMessage(USER_START_MSG, userId, NO_ARG2));
                 t.traceEnd();
             }
 
-            if (visible) {
-                // User was already running and became visible (for example, when switching to a
-                // user that was started in the background before), so it's necessary to explicitly
-                // notify the services (while when the user starts from BOOTING, USER_START_MSG
-                // takes care of that.
-                mHandler.sendMessage(
-                        mHandler.obtainMessage(USER_VISIBILITY_CHANGED_MSG, userId, 1));
-            }
-
             t.traceBegin("sendMessages");
             if (foreground) {
                 mHandler.sendMessage(mHandler.obtainMessage(USER_CURRENT_MSG, userId, oldUserId));
@@ -1853,7 +1826,7 @@
 
             if (foreground) {
                 t.traceBegin("moveUserToForeground");
-                moveUserToForeground(uss, oldUserId, userId);
+                moveUserToForeground(uss, userId);
                 t.traceEnd();
             } else {
                 t.traceBegin("finishUserBoot");
@@ -1887,10 +1860,6 @@
         return true;
     }
 
-    private boolean isCallingOnHandlerThread() {
-        return Looper.myLooper() == mHandler.getLooper();
-    }
-
     /**
      * Start user, if its not already running, and bring it to foreground.
      */
@@ -2067,21 +2036,25 @@
 
     /** Called on handler thread */
     @VisibleForTesting
-    void dispatchUserSwitchComplete(@UserIdInt int userId) {
+    void dispatchUserSwitchComplete(@UserIdInt int oldUserId, @UserIdInt int newUserId) {
         final TimingsTraceAndSlog t = new TimingsTraceAndSlog();
-        t.traceBegin("dispatchUserSwitchComplete-" + userId);
+        t.traceBegin("dispatchUserSwitchComplete-" + newUserId);
         mInjector.getWindowManager().setSwitchingUser(false);
         final int observerCount = mUserSwitchObservers.beginBroadcast();
         for (int i = 0; i < observerCount; i++) {
             try {
-                t.traceBegin("onUserSwitchComplete-" + userId + " #" + i + " "
+                t.traceBegin("onUserSwitchComplete-" + newUserId + " #" + i + " "
                         + mUserSwitchObservers.getBroadcastCookie(i));
-                mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(userId);
+                mUserSwitchObservers.getBroadcastItem(i).onUserSwitchComplete(newUserId);
                 t.traceEnd();
             } catch (RemoteException e) {
+                // Ignore
             }
         }
         mUserSwitchObservers.finishBroadcast();
+        t.traceBegin("sendUserSwitchBroadcasts-" + oldUserId + "-" + newUserId);
+        sendUserSwitchBroadcasts(oldUserId, newUserId);
+        t.traceEnd();
         t.traceEnd();
     }
 
@@ -2243,22 +2216,18 @@
 
         // Do the keyguard dismiss and unfreeze later
         mHandler.removeMessages(COMPLETE_USER_SWITCH_MSG);
-        mHandler.sendMessage(mHandler.obtainMessage(COMPLETE_USER_SWITCH_MSG, newUserId, 0));
+        mHandler.sendMessage(mHandler.obtainMessage(
+                COMPLETE_USER_SWITCH_MSG, oldUserId, newUserId));
 
         uss.switching = false;
         stopGuestOrEphemeralUserIfBackground(oldUserId);
         stopUserOnSwitchIfEnforced(oldUserId);
-        if (oldUserId == UserHandle.USER_SYSTEM) {
-            // System user is never stopped, but its visibility is changed (as it is brought to the
-            // background)
-            updateSystemUserVisibility(t, /* visible= */ false);
-        }
 
         t.traceEnd(); // end continueUserSwitch
     }
 
     @VisibleForTesting
-    void completeUserSwitch(int newUserId) {
+    void completeUserSwitch(int oldUserId, int newUserId) {
         final boolean isUserSwitchUiEnabled = isUserSwitchUiEnabled();
         final Runnable runnable = () -> {
             if (isUserSwitchUiEnabled) {
@@ -2266,7 +2235,7 @@
             }
             mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
             mHandler.sendMessage(mHandler.obtainMessage(
-                    REPORT_USER_SWITCH_COMPLETE_MSG, newUserId, 0));
+                    REPORT_USER_SWITCH_COMPLETE_MSG, oldUserId, newUserId));
         };
 
         // If there is no challenge set, dismiss the keyguard right away
@@ -2291,7 +2260,7 @@
         t.traceEnd();
     }
 
-    private void moveUserToForeground(UserState uss, int oldUserId, int newUserId) {
+    private void moveUserToForeground(UserState uss, int newUserId) {
         boolean homeInFront = mInjector.taskSupervisorSwitchUser(newUserId, uss);
         if (homeInFront) {
             mInjector.startHomeActivity(newUserId, "moveUserToForeground");
@@ -2299,7 +2268,6 @@
             mInjector.taskSupervisorResumeFocusedStackTopActivity();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
-        sendUserSwitchBroadcasts(oldUserId, newUserId);
     }
 
     void sendUserSwitchBroadcasts(int oldUserId, int newUserId) {
@@ -2614,27 +2582,10 @@
             // Don't need to call on HSUM because it will be called when the system user is
             // restarted on background
             mInjector.onUserStarting(UserHandle.USER_SYSTEM);
-            mInjector.onUserVisibilityChanged(UserHandle.USER_SYSTEM, /* visible= */ true);
+            mInjector.onSystemUserVisibilityChanged(/* visible= */ true);
         }
     }
 
-    private void updateSystemUserVisibility(TimingsTraceAndSlog t, boolean visible) {
-        t.traceBegin("update-system-userVisibility-" + visible);
-        if (DEBUG_MU) {
-            Slogf.d(TAG, "updateSystemUserVisibility(): visible=%b", visible);
-        }
-        int userId = UserHandle.USER_SYSTEM;
-        synchronized (mLock) {
-            if (visible) {
-                addVisibleUserLocked(userId);
-            } else {
-                deleteVisibleUserLocked(userId);
-            }
-        }
-        mInjector.onUserVisibilityChanged(userId, visible);
-        t.traceEnd();
-    }
-
     /**
      * Refreshes the internal caches related to user profiles.
      *
@@ -3032,9 +2983,6 @@
                     proto.end(uToken);
                 }
             }
-            for (int i = 0; i < mVisibleUsers.size(); i++) {
-                proto.write(UserControllerProto.VISIBLE_USERS_ARRAY, mVisibleUsers.keyAt(i));
-            }
             proto.write(UserControllerProto.CURRENT_USER, mCurrentUserId);
             for (int i = 0; i < mCurrentProfileIds.length; i++) {
                 proto.write(UserControllerProto.CURRENT_PROFILES, mCurrentProfileIds[i]);
@@ -3094,7 +3042,6 @@
                 pw.println("  mSwitchingToSystemUserMessage: " + mSwitchingToSystemUserMessage);
             }
             pw.println("  mLastUserUnlockingUptime: " + mLastUserUnlockingUptime);
-            pw.println("  mVisibleUsers: " + mVisibleUsers);
         }
     }
 
@@ -3190,9 +3137,8 @@
                 dispatchForegroundProfileChanged(msg.arg1);
                 break;
             case REPORT_USER_SWITCH_COMPLETE_MSG:
-                dispatchUserSwitchComplete(msg.arg1);
-
-                logUserLifecycleEvent(msg.arg1, USER_LIFECYCLE_EVENT_SWITCH_USER,
+                dispatchUserSwitchComplete(msg.arg1, msg.arg2);
+                logUserLifecycleEvent(msg.arg2, USER_LIFECYCLE_EVENT_SWITCH_USER,
                         USER_LIFECYCLE_EVENT_STATE_FINISH);
                 break;
             case REPORT_LOCKED_BOOT_COMPLETE_MSG:
@@ -3210,11 +3156,7 @@
                 logAndClearSessionId(msg.arg1);
                 break;
             case COMPLETE_USER_SWITCH_MSG:
-                completeUserSwitch(msg.arg1);
-                break;
-            case USER_VISIBILITY_CHANGED_MSG:
-                mInjector.onUserVisibilityChanged(/* userId= */ msg.arg1,
-                        /* visible= */ msg.arg2 == 1);
+                completeUserSwitch(msg.arg1, msg.arg2);
                 break;
         }
         return false;
@@ -3486,6 +3428,32 @@
         }
     }
 
+    /**
+     * Helper class for keeping track of user starts which are paused while user's
+     * shutdown is taking place.
+     */
+    private static class PendingUserStart {
+        public final @UserIdInt int userId;
+        public final boolean isForeground;
+        public final IProgressListener unlockListener;
+
+        PendingUserStart(int userId, boolean foreground,
+                IProgressListener unlockListener) {
+            this.userId = userId;
+            this.isForeground = foreground;
+            this.unlockListener = unlockListener;
+        }
+
+        @Override
+        public String toString() {
+            return "PendingUserStart{"
+                    + "userId=" + userId
+                    + ", isForeground=" + isForeground
+                    + ", unlockListener=" + unlockListener
+                    + '}';
+        }
+    }
+
     @VisibleForTesting
     static class Injector {
         private final ActivityManagerService mService;
@@ -3750,8 +3718,8 @@
             getSystemServiceManager().onUserStarting(TimingsTraceAndSlog.newAsyncLog(), userId);
         }
 
-        void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
-            getUserManagerInternal().onUserVisibilityChanged(userId, visible);
+        void onSystemUserVisibilityChanged(boolean visible) {
+            getUserManagerInternal().onSystemUserVisibilityChanged(visible);
         }
     }
 }
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b92c163..cda18b0 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -40,6 +40,7 @@
 import android.app.GameState;
 import android.app.IGameManagerService;
 import android.app.IGameModeListener;
+import android.app.StatsManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -76,6 +77,7 @@
 import android.util.AttributeSet;
 import android.util.KeyValueListParser;
 import android.util.Slog;
+import android.util.StatsEvent;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
@@ -104,6 +106,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Service to manage game related features.
@@ -115,6 +118,14 @@
  */
 public final class GameManagerService extends IGameManagerService.Stub {
     public static final String TAG = "GameManagerService";
+    // event strings used for logging
+    private static final String EVENT_SET_GAME_MODE = "SET_GAME_MODE";
+    private static final String EVENT_UPDATE_CUSTOM_GAME_MODE_CONFIG =
+            "UPDATE_CUSTOM_GAME_MODE_CONFIG";
+    private static final String EVENT_RECEIVE_SHUTDOWN_INDENT = "RECEIVE_SHUTDOWN_INDENT";
+    private static final String EVENT_ON_USER_STARTING = "ON_USER_STARTING";
+    private static final String EVENT_ON_USER_SWITCHING = "ON_USER_SWITCHING";
+    private static final String EVENT_ON_USER_STOPPING = "ON_USER_STOPPING";
 
     private static final boolean DEBUG = false;
 
@@ -338,7 +349,18 @@
                                     + " and userId " + userId);
                             break;
                         }
+                        if (mHandler.hasMessages(CANCEL_GAME_LOADING_MODE)) {
+                            mHandler.removeMessages(CANCEL_GAME_LOADING_MODE);
+                        }
                         mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+                        if (isLoading) {
+                            int loadingBoostDuration = getLoadingBoostDuration(packageName, userId);
+                            loadingBoostDuration = loadingBoostDuration > 0 ? loadingBoostDuration
+                                    : LOADING_BOOST_MAX_DURATION;
+                            mHandler.sendMessageDelayed(
+                                    mHandler.obtainMessage(CANCEL_GAME_LOADING_MODE),
+                                    loadingBoostDuration);
+                        }
                     }
                     break;
                 }
@@ -438,6 +460,7 @@
     public void setGameState(String packageName, @NonNull GameState gameState,
             @UserIdInt int userId) {
         if (!isPackageGame(packageName, userId)) {
+            Slog.d(TAG, "No-op for attempt to set game state for non-game app: " + packageName);
             // Restrict to games only.
             return;
         }
@@ -921,6 +944,7 @@
         public void onBootPhase(int phase) {
             if (phase == PHASE_BOOT_COMPLETED) {
                 mService.onBootCompleted();
+                mService.registerStatsCallbacks();
             }
         }
 
@@ -964,11 +988,8 @@
         }
     }
 
-    private @GameMode int[] getAvailableGameModesUnchecked(String packageName) {
-        final GamePackageConfiguration config;
-        synchronized (mDeviceConfigLock) {
-            config = mConfigs.get(packageName);
-        }
+    private @GameMode int[] getAvailableGameModesUnchecked(String packageName, int userId) {
+        final GamePackageConfiguration config = getConfig(packageName, userId);
         if (config == null) {
             return new int[]{GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM};
         }
@@ -991,9 +1012,13 @@
      */
     @Override
     @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
-    public @GameMode int[] getAvailableGameModes(String packageName) throws SecurityException {
+    public @GameMode int[] getAvailableGameModes(String packageName, int userId)
+            throws SecurityException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
-        return getAvailableGameModesUnchecked(packageName);
+        if (!isPackageGame(packageName, userId)) {
+            return new int[]{};
+        }
+        return getAvailableGameModesUnchecked(packageName, userId);
     }
 
     private @GameMode int getGameModeFromSettingsUnchecked(String packageName,
@@ -1060,7 +1085,6 @@
         // Check the caller has the necessary permission.
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
 
-        // Restrict to games only.
         if (!isPackageGame(packageName, userId)) {
             return null;
         }
@@ -1090,7 +1114,7 @@
         } else {
             return new GameModeInfo.Builder()
                     .setActiveGameMode(activeGameMode)
-                    .setAvailableGameModes(getAvailableGameModesUnchecked(packageName))
+                    .setAvailableGameModes(getAvailableGameModesUnchecked(packageName, userId))
                     .build();
         }
     }
@@ -1104,9 +1128,11 @@
     public void setGameMode(String packageName, @GameMode int gameMode, int userId)
             throws SecurityException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
-
-        if (!isPackageGame(packageName, userId) || gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
-            // Restrict to games and valid game modes only.
+        if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+            Slog.d(TAG, "No-op for attempt to set UNSUPPORTED mode for app: " + packageName);
+            return;
+        } else if (!isPackageGame(packageName, userId)) {
+            Slog.d(TAG, "No-op for attempt to set game mode for non-game app: " + packageName);
             return;
         }
         int fromGameMode;
@@ -1136,9 +1162,18 @@
                 }
             }
         }
-        sendUserMessage(userId, WRITE_SETTINGS, "SET_GAME_MODE", WRITE_DELAY_MILLIS);
+        sendUserMessage(userId, WRITE_SETTINGS, EVENT_SET_GAME_MODE, WRITE_DELAY_MILLIS);
         sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
-                "SET_GAME_MODE", 0 /*delayMillis*/);
+                EVENT_SET_GAME_MODE, 0 /*delayMillis*/);
+        int gameUid = -1;
+        try {
+            gameUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException ex) {
+            Slog.d(TAG, "Cannot find the UID for package " + packageName + " under user " + userId);
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CHANGED, gameUid,
+                Binder.getCallingUid(), gameModeToStatsdGameMode(fromGameMode),
+                gameModeToStatsdGameMode(gameMode));
     }
 
     /**
@@ -1205,17 +1240,16 @@
                 Binder.getCallingUid(), userId, false, true, "notifyGraphicsEnvironmentSetup",
                 "com.android.server.app.GameManagerService");
 
-        // Restrict to games only.
-        if (!isPackageGame(packageName, userId)) {
-            return;
-        }
-
         if (!isValidPackageName(packageName, userId)) {
+            Slog.d(TAG, "No-op for attempt to notify graphics env setup for different package"
+                    + "than caller with uid: " + Binder.getCallingUid());
             return;
         }
 
         final int gameMode = getGameMode(packageName, userId);
         if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+            Slog.d(TAG, "No-op for attempt to notify graphics env setup for non-game app: "
+                    + packageName);
             return;
         }
         int loadingBoostDuration = getLoadingBoostDuration(packageName, userId);
@@ -1330,6 +1364,11 @@
             GameModeConfiguration gameModeConfig, int userId)
             throws SecurityException, IllegalArgumentException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
+        if (!isPackageGame(packageName, userId)) {
+            Slog.d(TAG, "No-op for attempt to update custom game mode for non-game app: "
+                    + packageName);
+            return;
+        }
         synchronized (mLock) {
             if (!mSettings.containsKey(userId)) {
                 throw new IllegalArgumentException("User " + userId + " wasn't started");
@@ -1353,11 +1392,26 @@
         }
         GamePackageConfiguration.GameModeConfiguration internalConfig =
                 configOverride.getOrAddDefaultGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
+        int gameUid = -1;
+        try {
+            gameUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException ex) {
+            Slog.d(TAG, "Cannot find the UID for package " + packageName + " under user " + userId);
+        }
+        FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CONFIGURATION_CHANGED, gameUid,
+                Binder.getCallingUid(), gameModeToStatsdGameMode(GameManager.GAME_MODE_CUSTOM),
+                internalConfig.getScaling(), gameModeConfig.getScalingFactor(),
+                internalConfig.getFps(), gameModeConfig.getFpsOverride());
         internalConfig.updateFromPublicGameModeConfig(gameModeConfig);
 
         Slog.i(TAG, "Updated custom game mode config for package: " + packageName
                 + " with FPS=" + internalConfig.getFps() + ";Scaling="
-                + internalConfig.getScaling());
+                + internalConfig.getScaling() + " under user " + userId);
+
+        sendUserMessage(userId, WRITE_SETTINGS, EVENT_UPDATE_CUSTOM_GAME_MODE_CONFIG,
+                WRITE_DELAY_MILLIS);
+        sendUserMessage(userId, WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
+                EVENT_UPDATE_CUSTOM_GAME_MODE_CONFIG, WRITE_DELAY_MILLIS /*delayMillis*/);
     }
 
     /**
@@ -1432,9 +1486,10 @@
                         for (Map.Entry<Integer, GameManagerSettings> entry : mSettings.entrySet()) {
                             final int userId = entry.getKey();
                             sendUserMessage(userId, WRITE_SETTINGS,
-                                    Intent.ACTION_SHUTDOWN, 0 /*delayMillis*/);
+                                    EVENT_RECEIVE_SHUTDOWN_INDENT, 0 /*delayMillis*/);
                             sendUserMessage(userId,
-                                    WRITE_GAME_MODE_INTERVENTION_LIST_FILE, Intent.ACTION_SHUTDOWN,
+                                    WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
+                                    EVENT_RECEIVE_SHUTDOWN_INDENT,
                                     0 /*delayMillis*/);
                         }
                     }
@@ -1459,7 +1514,8 @@
                 userSettings.readPersistentDataLocked();
             }
         }
-        sendUserMessage(userId, POPULATE_GAME_MODE_SETTINGS, "ON_USER_STARTING", 0 /*delayMillis*/);
+        sendUserMessage(userId, POPULATE_GAME_MODE_SETTINGS, EVENT_ON_USER_STARTING,
+                0 /*delayMillis*/);
 
         if (mGameServiceController != null) {
             mGameServiceController.notifyUserStarted(user);
@@ -1479,7 +1535,7 @@
             if (!mSettings.containsKey(userId)) {
                 return;
             }
-            sendUserMessage(userId, REMOVE_SETTINGS, "ON_USER_STOPPING", 0 /*delayMillis*/);
+            sendUserMessage(userId, REMOVE_SETTINGS, EVENT_ON_USER_STOPPING, 0 /*delayMillis*/);
         }
 
         if (mGameServiceController != null) {
@@ -1492,7 +1548,7 @@
         // we want to re-populate the setting when switching user as the device config may have
         // changed, which will only update for the previous user, see
         // DeviceConfigListener#onPropertiesChanged.
-        sendUserMessage(toUserId, POPULATE_GAME_MODE_SETTINGS, "ON_USER_SWITCHING",
+        sendUserMessage(toUserId, POPULATE_GAME_MODE_SETTINGS, EVENT_ON_USER_SWITCHING,
                 0 /*delayMillis*/);
 
         if (mGameServiceController != null) {
@@ -1576,6 +1632,34 @@
     public void setGameModeConfigOverride(String packageName, @UserIdInt int userId,
             @GameMode int gameMode, String fpsStr, String scaling) throws SecurityException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
+        int gameUid = -1;
+        try {
+            gameUid = mPackageManager.getPackageUidAsUser(packageName, userId);
+        } catch (NameNotFoundException ex) {
+            Slog.d(TAG, "Cannot find the UID for package " + packageName + " under user " + userId);
+        }
+        GamePackageConfiguration pkgConfig = getConfig(packageName, userId);
+        if (pkgConfig != null && pkgConfig.getGameModeConfiguration(gameMode) != null) {
+            final GamePackageConfiguration.GameModeConfiguration currentModeConfig =
+                    pkgConfig.getGameModeConfiguration(gameMode);
+            FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CONFIGURATION_CHANGED, gameUid,
+                    Binder.getCallingUid(), gameModeToStatsdGameMode(gameMode),
+                    currentModeConfig.getScaling() /* fromScaling */,
+                    scaling == null ? currentModeConfig.getScaling()
+                            : Float.parseFloat(scaling) /* toScaling */,
+                    currentModeConfig.getFps() /* fromFps */,
+                    fpsStr == null ? currentModeConfig.getFps()
+                            : Integer.parseInt(fpsStr)) /* toFps */;
+        } else {
+            FrameworkStatsLog.write(FrameworkStatsLog.GAME_MODE_CONFIGURATION_CHANGED, gameUid,
+                    Binder.getCallingUid(), gameModeToStatsdGameMode(gameMode),
+                    GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING /* fromScaling*/,
+                    scaling == null ? GamePackageConfiguration.GameModeConfiguration.DEFAULT_SCALING
+                            : Float.parseFloat(scaling) /* toScaling */,
+                    0 /* fromFps */,
+                    fpsStr == null ? 0 : Integer.parseInt(fpsStr) /* toFps */);
+        }
+
         // Adding game mode config override of the given package name
         GamePackageConfiguration configOverride;
         synchronized (mLock) {
@@ -1618,11 +1702,6 @@
     public void resetGameModeConfigOverride(String packageName, @UserIdInt int userId,
             @GameMode int gameModeToReset) throws SecurityException {
         checkPermission(Manifest.permission.MANAGE_GAME_MODE);
-        final GamePackageConfiguration deviceConfig;
-        synchronized (mDeviceConfigLock) {
-            deviceConfig = mConfigs.get(packageName);
-        }
-
         // resets GamePackageConfiguration of a given packageName.
         // If a gameMode is specified, only reset the GameModeConfiguration of the gameMode.
         synchronized (mLock) {
@@ -1938,13 +2017,99 @@
         LocalServices.addService(GameManagerInternal.class, new LocalService());
     }
 
-    private String dumpDeviceConfigs() {
-        StringBuilder out = new StringBuilder();
-        for (String key : mConfigs.keySet()) {
-            out.append("[\nName: ").append(key)
-                    .append("\nConfig: ").append(mConfigs.get(key).toString()).append("\n]");
+    private void registerStatsCallbacks() {
+        final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_INFO,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_CONFIGURATION,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+        statsManager.setPullAtomCallback(
+                FrameworkStatsLog.GAME_MODE_LISTENER,
+                null, // use default PullAtomMetadata values
+                BackgroundThread.getExecutor(),
+                this::onPullAtom);
+    }
+
+    private int onPullAtom(int atomTag, @NonNull List<StatsEvent> data) {
+        if (atomTag == FrameworkStatsLog.GAME_MODE_INFO
+                || atomTag == FrameworkStatsLog.GAME_MODE_CONFIGURATION) {
+            int userId = ActivityManager.getCurrentUser();
+            Set<String> packages;
+            synchronized (mDeviceConfigLock) {
+                packages = mConfigs.keySet();
+            }
+            for (String p : packages) {
+                GamePackageConfiguration config = getConfig(p, userId);
+                if (config == null) {
+                    continue;
+                }
+                int uid = -1;
+                try {
+                    uid = mPackageManager.getPackageUidAsUser(p, userId);
+                } catch (NameNotFoundException ex) {
+                    Slog.d(TAG,
+                            "Cannot find UID for package " + p + " under user handle id " + userId);
+                }
+                if (atomTag == FrameworkStatsLog.GAME_MODE_INFO) {
+                    data.add(
+                            FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.GAME_MODE_INFO, uid,
+                                    gameModesToStatsdGameModes(config.getOptedInGameModes()),
+                                    gameModesToStatsdGameModes(config.getAvailableGameModes())));
+                } else if (atomTag == FrameworkStatsLog.GAME_MODE_CONFIGURATION) {
+                    for (int gameMode : config.getAvailableGameModes()) {
+                        GamePackageConfiguration.GameModeConfiguration modeConfig =
+                                config.getGameModeConfiguration(gameMode);
+                        if (modeConfig != null) {
+                            data.add(FrameworkStatsLog.buildStatsEvent(
+                                    FrameworkStatsLog.GAME_MODE_CONFIGURATION, uid,
+                                    gameModeToStatsdGameMode(gameMode), modeConfig.getFps(),
+                                    modeConfig.getScaling()));
+                        }
+                    }
+                }
+            }
+        } else if (atomTag == FrameworkStatsLog.GAME_MODE_LISTENER) {
+            synchronized (mGameModeListenerLock) {
+                data.add(FrameworkStatsLog.buildStatsEvent(FrameworkStatsLog.GAME_MODE_LISTENER,
+                        mGameModeListeners.size()));
+            }
         }
-        return out.toString();
+        return android.app.StatsManager.PULL_SUCCESS;
+    }
+
+    private static int[] gameModesToStatsdGameModes(int[] modes) {
+        if (modes == null) {
+            return null;
+        }
+        int[] statsdModes = new int[modes.length];
+        int i = 0;
+        for (int mode : modes) {
+            statsdModes[i++] = gameModeToStatsdGameMode(mode);
+        }
+        return statsdModes;
+    }
+
+    private static int gameModeToStatsdGameMode(int mode) {
+        switch (mode) {
+            case GameManager.GAME_MODE_BATTERY:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_BATTERY;
+            case GameManager.GAME_MODE_PERFORMANCE:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_PERFORMANCE;
+            case GameManager.GAME_MODE_CUSTOM:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_CUSTOM;
+            case GameManager.GAME_MODE_STANDARD:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_STANDARD;
+            case GameManager.GAME_MODE_UNSUPPORTED:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_UNSUPPORTED;
+            default:
+                return FrameworkStatsLog.GAME_MODE_CONFIGURATION__GAME_MODE__GAME_MODE_UNSPECIFIED;
+        }
     }
 
     private static int gameStateModeToStatsdGameState(int mode) {
diff --git a/services/core/java/com/android/server/app/GameManagerSettings.java b/services/core/java/com/android/server/app/GameManagerSettings.java
index 638bc4e..5189017 100644
--- a/services/core/java/com/android/server/app/GameManagerSettings.java
+++ b/services/core/java/com/android/server/app/GameManagerSettings.java
@@ -19,6 +19,7 @@
 import android.app.GameManager;
 import android.os.FileUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.Slog;
 import android.util.Xml;
@@ -37,7 +38,6 @@
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.util.Map;
 
 /**
  * Persists all GameService related settings.
@@ -49,7 +49,11 @@
     // The XML file follows the below format:
     // <?xml>
     // <packages>
-    //     <package></package>
+    //     <package name="" gameMode="">
+    //       <gameModeConfig gameMode="" fps="" scaling="" useAngle="" loadingBoost="">
+    //       </gameModeConfig>
+    //       ...
+    //     </package>
     //     ...
     // </packages>
     private static final String GAME_SERVICE_FILE_NAME = "game-manager-service.xml";
@@ -155,11 +159,14 @@
             serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
 
             serializer.startTag(null, TAG_PACKAGES);
-            for (Map.Entry<String, Integer> entry : mGameModes.entrySet()) {
-                String packageName = entry.getKey();
+            final ArraySet<String> packageNames = new ArraySet<>(mGameModes.keySet());
+            packageNames.addAll(mConfigOverrides.keySet());
+            for (String packageName : packageNames) {
                 serializer.startTag(null, TAG_PACKAGE);
                 serializer.attribute(null, ATTR_NAME, packageName);
-                serializer.attributeInt(null, ATTR_GAME_MODE, entry.getValue());
+                if (mGameModes.containsKey(packageName)) {
+                    serializer.attributeInt(null, ATTR_GAME_MODE, mGameModes.get(packageName));
+                }
                 writeGameModeConfigTags(serializer, mConfigOverrides.get(packageName));
                 serializer.endTag(null, TAG_PACKAGE);
             }
@@ -224,7 +231,7 @@
                 // Do nothing
             }
             if (type != XmlPullParser.START_TAG) {
-                Slog.wtf(TAG, "No start tag found in package manager settings");
+                Slog.wtf(TAG, "No start tag found in game manager settings");
                 return false;
             }
 
@@ -245,7 +252,7 @@
                 }
             }
         } catch (XmlPullParserException | java.io.IOException e) {
-            Slog.wtf(TAG, "Error reading package manager settings", e);
+            Slog.wtf(TAG, "Error reading game manager settings", e);
             return false;
         }
         return true;
@@ -260,15 +267,12 @@
             XmlUtils.skipCurrentTag(parser);
             return;
         }
-        int gameMode;
         try {
-            gameMode = parser.getAttributeInt(null, ATTR_GAME_MODE);
+            final int gameMode = parser.getAttributeInt(null, ATTR_GAME_MODE);
+            mGameModes.put(name, gameMode);
         } catch (XmlPullParserException e) {
-            Slog.wtf(TAG, "Invalid game mode in package tag: "
-                    + parser.getAttributeValue(null, ATTR_GAME_MODE), e);
-            return;
+            Slog.v(TAG, "No game mode selected by user for package" + name);
         }
-        mGameModes.put(name, gameMode);
         final int packageTagDepth = parser.getDepth();
         int type;
         final GamePackageConfiguration config = new GamePackageConfiguration(name);
diff --git a/services/core/java/com/android/server/app/GameManagerShellCommand.java b/services/core/java/com/android/server/app/GameManagerShellCommand.java
index cdbffbe..abab0e7 100644
--- a/services/core/java/com/android/server/app/GameManagerShellCommand.java
+++ b/services/core/java/com/android/server/app/GameManagerShellCommand.java
@@ -27,6 +27,7 @@
 
 import java.io.PrintWriter;
 import java.util.Locale;
+import java.util.StringJoiner;
 
 /**
  * ShellCommands for GameManagerService.
@@ -34,8 +35,20 @@
  * Use with {@code adb shell cmd game ...}.
  */
 public class GameManagerShellCommand extends ShellCommand {
+    private static final String STANDARD_MODE_STR = "standard";
+    private static final String STANDARD_MODE_NUM = "1";
+    private static final String PERFORMANCE_MODE_STR = "performance";
+    private static final String PERFORMANCE_MODE_NUM = "2";
+    private static final String BATTERY_MODE_STR = "battery";
+    private static final String BATTERY_MODE_NUM = "3";
+    private static final String CUSTOM_MODE_STR = "custom";
+    private static final String CUSTOM_MODE_NUM = "4";
+    private static final String UNSUPPORTED_MODE_STR = "unsupported";
+    private static final String UNSUPPORTED_MODE_NUM = String.valueOf(
+            GameManager.GAME_MODE_UNSUPPORTED);
 
-    public GameManagerShellCommand() {}
+    public GameManagerShellCommand() {
+    }
 
     @Override
     public int onCommand(String cmd) {
@@ -46,10 +59,10 @@
         try {
             switch (cmd) {
                 case "set": {
-                    return runSetGameMode(pw);
+                    return runSetGameModeConfig(pw);
                 }
                 case "reset": {
-                    return runResetGameMode(pw);
+                    return runResetGameModeConfig(pw);
                 }
                 case "mode": {
                     /** The "mode" command allows setting a package's current game mode outside of
@@ -61,10 +74,13 @@
                      *          <PACKAGE_NAME> <CONFIG_STRING>`
                      * see: {@link GameManagerServiceTests#mockDeviceConfigAll()}
                      */
-                    return runGameMode(pw);
+                    return runSetGameMode(pw);
                 }
-                case "list": {
-                    return runGameList(pw);
+                case "list-modes": {
+                    return runListGameModes(pw);
+                }
+                case "list-configs": {
+                    return runListGameModeConfigs(pw);
                 }
                 default:
                     return handleDefaultCommands(cmd);
@@ -75,7 +91,21 @@
         return -1;
     }
 
-    private int runGameList(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
+    private int runListGameModes(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
+        final String packageName = getNextArgRequired();
+        final GameManagerService gameManagerService = (GameManagerService)
+                ServiceManager.getService(Context.GAME_SERVICE);
+        final StringJoiner sj = new StringJoiner(",");
+        for (int mode : gameManagerService.getAvailableGameModes(packageName,
+                ActivityManager.getCurrentUser())) {
+            sj.add(gameModeIntToString(mode));
+        }
+        pw.println(packageName + " has available game modes: [" + sj + "]");
+        return 0;
+    }
+
+    private int runListGameModeConfigs(PrintWriter pw)
+            throws ServiceNotFoundException, RemoteException {
         final String packageName = getNextArgRequired();
 
         final GameManagerService gameManagerService = (GameManagerService)
@@ -92,7 +122,7 @@
         return 0;
     }
 
-    private int runGameMode(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
+    private int runSetGameMode(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
         final String option = getNextOption();
         String userIdStr = null;
         if (option != null && option.equals("--user")) {
@@ -105,7 +135,9 @@
                 ServiceManager.getServiceOrThrow(Context.GAME_SERVICE));
         boolean batteryModeSupported = false;
         boolean perfModeSupported = false;
-        int[] modes = service.getAvailableGameModes(packageName);
+        int userId = userIdStr != null ? Integer.parseInt(userIdStr)
+                : ActivityManager.getCurrentUser();
+        int[] modes = service.getAvailableGameModes(packageName, userId);
         for (int mode : modes) {
             if (mode == GameManager.GAME_MODE_PERFORMANCE) {
                 perfModeSupported = true;
@@ -113,37 +145,47 @@
                 batteryModeSupported = true;
             }
         }
-        int userId = userIdStr != null ? Integer.parseInt(userIdStr)
-                : ActivityManager.getCurrentUser();
         switch (gameMode.toLowerCase()) {
-            case "1":
-            case "standard":
+            case STANDARD_MODE_NUM:
+            case STANDARD_MODE_STR:
                 // Standard mode can be used to specify loading ANGLE as the default OpenGL ES
                 // driver, so it should always be available.
                 service.setGameMode(packageName, GameManager.GAME_MODE_STANDARD, userId);
+                pw.println("Set game mode to `STANDARD` for user `" + userId + "` in game `"
+                        + packageName + "`");
                 break;
-            case "2":
-            case "performance":
+            case PERFORMANCE_MODE_NUM:
+            case PERFORMANCE_MODE_STR:
                 if (perfModeSupported) {
                     service.setGameMode(packageName, GameManager.GAME_MODE_PERFORMANCE,
                             userId);
+                    pw.println("Set game mode to `PERFORMANCE` for user `" + userId + "` in game `"
+                            + packageName + "`");
                 } else {
                     pw.println("Game mode: " + gameMode + " not supported by "
                             + packageName);
                     return -1;
                 }
                 break;
-            case "3":
-            case "battery":
+            case BATTERY_MODE_NUM:
+            case BATTERY_MODE_STR:
                 if (batteryModeSupported) {
                     service.setGameMode(packageName, GameManager.GAME_MODE_BATTERY,
                             userId);
+                    pw.println("Set game mode to `BATTERY` for user `" + userId + "` in game `"
+                            + packageName + "`");
                 } else {
                     pw.println("Game mode: " + gameMode + " not supported by "
                             + packageName);
                     return -1;
                 }
                 break;
+            case CUSTOM_MODE_NUM:
+            case CUSTOM_MODE_STR:
+                service.setGameMode(packageName, GameManager.GAME_MODE_CUSTOM, userId);
+                pw.println("Set game mode to `CUSTOM` for user `" + userId + "` in game `"
+                        + packageName + "`");
+                break;
             default:
                 pw.println("Invalid game mode: " + gameMode);
                 return -1;
@@ -151,15 +193,9 @@
         return 0;
     }
 
-    private int runSetGameMode(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
-        String option = getNextArgRequired();
-        if (!option.equals("--mode")) {
-            pw.println("Invalid option '" + option + "'");
-            return -1;
-        }
-
-        final String gameMode = getNextArgRequired();
-
+    private int runSetGameModeConfig(PrintWriter pw)
+            throws ServiceNotFoundException, RemoteException {
+        String option;
         /**
          * handling optional input
          * "--user", "--downscale" and "--fps" can come in any order
@@ -167,8 +203,12 @@
         String userIdStr = null;
         String fpsStr = null;
         String downscaleRatio = null;
+        int gameMode = GameManager.GAME_MODE_CUSTOM;
         while ((option = getNextOption()) != null) {
             switch (option) {
+                case "--mode":
+                    gameMode = Integer.parseInt(getNextArgRequired());
+                    break;
                 case "--user":
                     if (userIdStr == null) {
                         userIdStr = getNextArgRequired();
@@ -220,50 +260,21 @@
 
         final GameManagerService gameManagerService = (GameManagerService)
                 ServiceManager.getService(Context.GAME_SERVICE);
-
-        boolean batteryModeSupported = false;
-        boolean perfModeSupported = false;
-        int [] modes = gameManagerService.getAvailableGameModes(packageName);
-
-        for (int mode : modes) {
-            if (mode == GameManager.GAME_MODE_PERFORMANCE) {
-                perfModeSupported = true;
-            } else if (mode == GameManager.GAME_MODE_BATTERY) {
-                batteryModeSupported = true;
-            }
+        if (gameManagerService == null) {
+            pw.println("Failed to find GameManagerService on device");
+            return -1;
         }
-
-        switch (gameMode.toLowerCase(Locale.getDefault())) {
-            case "2":
-            case "performance":
-                if (perfModeSupported) {
-                    gameManagerService.setGameModeConfigOverride(packageName, userId,
-                            GameManager.GAME_MODE_PERFORMANCE, fpsStr, downscaleRatio);
-                } else {
-                    pw.println("Game mode: " + gameMode + " not supported by "
-                            + packageName);
-                    return -1;
-                }
-                break;
-            case "3":
-            case "battery":
-                if (batteryModeSupported) {
-                    gameManagerService.setGameModeConfigOverride(packageName, userId,
-                            GameManager.GAME_MODE_BATTERY, fpsStr, downscaleRatio);
-                } else {
-                    pw.println("Game mode: " + gameMode + " not supported by "
-                            + packageName);
-                    return -1;
-                }
-                break;
-            default:
-                pw.println("Invalid game mode: " + gameMode);
-                return -1;
-        }
+        gameManagerService.setGameModeConfigOverride(packageName, userId, gameMode,
+                fpsStr, downscaleRatio);
+        pw.println("Set custom mode intervention config for user `" + userId + "` in game `"
+                + packageName + "` as: `"
+                + "downscaling-ratio: " + downscaleRatio + ";"
+                + "fps-override: " + fpsStr + "`");
         return 0;
     }
 
-    private int runResetGameMode(PrintWriter pw) throws ServiceNotFoundException, RemoteException {
+    private int runResetGameModeConfig(PrintWriter pw)
+            throws ServiceNotFoundException, RemoteException {
         String option = null;
         String gameMode = null;
         String userIdStr = null;
@@ -305,13 +316,13 @@
         }
 
         switch (gameMode.toLowerCase(Locale.getDefault())) {
-            case "2":
-            case "performance":
+            case PERFORMANCE_MODE_NUM:
+            case PERFORMANCE_MODE_STR:
                 gameManagerService.resetGameModeConfigOverride(packageName, userId,
                         GameManager.GAME_MODE_PERFORMANCE);
                 break;
-            case "3":
-            case "battery":
+            case BATTERY_MODE_NUM:
+            case BATTERY_MODE_STR:
                 gameManagerService.resetGameModeConfigOverride(packageName, userId,
                         GameManager.GAME_MODE_BATTERY);
                 break;
@@ -322,6 +333,22 @@
         return 0;
     }
 
+    private static String gameModeIntToString(@GameManager.GameMode int gameMode) {
+        switch (gameMode) {
+            case GameManager.GAME_MODE_BATTERY:
+                return BATTERY_MODE_STR;
+            case GameManager.GAME_MODE_PERFORMANCE:
+                return PERFORMANCE_MODE_STR;
+            case GameManager.GAME_MODE_CUSTOM:
+                return CUSTOM_MODE_STR;
+            case GameManager.GAME_MODE_STANDARD:
+                return STANDARD_MODE_STR;
+            case GameManager.GAME_MODE_UNSUPPORTED:
+                return UNSUPPORTED_MODE_STR;
+        }
+        return "";
+    }
+
     @Override
     public void onHelp() {
         PrintWriter pw = getOutPrintWriter();
@@ -329,21 +356,28 @@
         pw.println("  help");
         pw.println("      Print this help text.");
         pw.println("  downscale");
-        pw.println("      Deprecated. Please use `set` command.");
-        pw.println("  mode [--user <USER_ID>] [1|2|3|standard|performance|battery] <PACKAGE_NAME>");
+        pw.println("      Deprecated. Please use `custom` command.");
+        pw.println("  list-configs <PACKAGE_NAME>");
+        pw.println("      Lists the current intervention configs of an app.");
+        pw.println("  list-modes <PACKAGE_NAME>");
+        pw.println("      Lists the current available game modes of an app.");
+        pw.println("  mode [--user <USER_ID>] [1|2|3|4|standard|performance|battery|custom] "
+                + "<PACKAGE_NAME>");
         pw.println("      Set app to run in the specified game mode, if supported.");
         pw.println("      --user <USER_ID>: apply for the given user,");
         pw.println("                        the current user is used when unspecified.");
-        pw.println("  set --mode [2|3|performance|battery] [intervention configs] <PACKAGE_NAME>");
-        pw.println("      Set app to run at given game mode with configs, if supported.");
+        pw.println("  set [intervention configs] <PACKAGE_NAME>");
+        pw.println("      Set app to run at custom mode using provided intervention configs");
         pw.println("      Intervention configs consists of:");
         pw.println("      --downscale [0.3|0.35|0.4|0.45|0.5|0.55|0.6|0.65");
-        pw.println("                  |0.7|0.75|0.8|0.85|0.9|disable]");
-        pw.println("      Set app to run at the specified scaling ratio.");
-        pw.println("      --fps [30|45|60|90|120|disable]");
-        pw.println("      Set app to run at the specified fps, if supported.");
+        pw.println("                  |0.7|0.75|0.8|0.85|0.9|disable]: Set app to run at the");
+        pw.println("                                                   specified scaling ratio.");
+        pw.println("      --fps [30|45|60|90|120|disable]: Set app to run at the specified fps,");
+        pw.println("                                       if supported.");
         pw.println("  reset [--mode [2|3|performance|battery] --user <USER_ID>] <PACKAGE_NAME>");
         pw.println("      Resets the game mode of the app to device configuration.");
+        pw.println("      This should only be used to reset any override to non custom game mode");
+        pw.println("      applied using the deprecated `set` command");
         pw.println("      --mode [2|3|performance|battery]: apply for the given mode,");
         pw.println("                                        resets all modes when unspecified.");
         pw.println("      --user <USER_ID>: apply for the given user,");
diff --git a/services/core/java/com/android/server/app/TEST_MAPPING b/services/core/java/com/android/server/app/TEST_MAPPING
index 0ba4d8c..82840ee 100644
--- a/services/core/java/com/android/server/app/TEST_MAPPING
+++ b/services/core/java/com/android/server/app/TEST_MAPPING
@@ -9,6 +9,23 @@
       ]
     },
     {
+      "name": "CtsStatsdAtomHostTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.cts.statsdatom.gamemanager"
+        }
+      ],
+      "file_patterns": [
+        "(/|^)GameManagerService.java"
+      ]
+    },
+    {
       "name": "FrameworksMockingServicesTests",
       "options": [
         {
@@ -18,6 +35,23 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "FrameworksCoreGameManagerTests",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        },
+        {
+          "include-filter": "android.app"
+        }
+      ],
+      "file_patterns": [
+        "(/|^)GameManagerService.java", "(/|^)GameManagerSettings.java"
+      ]
     }
   ]
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java
new file mode 100644
index 0000000..8d1da71
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceImpl.java
@@ -0,0 +1,601 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.appop;
+
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
+import static android.app.AppOpsManager.opRestrictsRead;
+
+import static com.android.server.appop.AppOpsServiceImpl.ModeCallback.ALL_OPS;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.AppOpsManager.Mode;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.function.pooled.PooledLambda;
+
+import libcore.util.EmptyArray;
+
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.Objects;
+
+
+/**
+ * Legacy implementation for App-ops service's app-op mode (uid and package) storage and access.
+ * In the future this class will also include mode callbacks and op restrictions.
+ */
+public class AppOpsCheckingServiceImpl implements AppOpsCheckingServiceInterface {
+
+    static final String TAG = "LegacyAppOpsServiceInterfaceImpl";
+
+    // Must be the same object that the AppOpsService is using for locking.
+    final Object mLock;
+    final Handler mHandler;
+    final Context mContext;
+    final SparseArray<int[]> mSwitchedOps;
+
+    @GuardedBy("mLock")
+    @VisibleForTesting
+    final SparseArray<SparseIntArray> mUidModes = new SparseArray<>();
+
+    @GuardedBy("mLock")
+    final SparseArray<ArrayMap<String, SparseIntArray>> mUserPackageModes = new SparseArray<>();
+
+    final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>();
+    final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers =
+            new ArrayMap<>();
+
+    final PersistenceScheduler mPersistenceScheduler;
+
+
+    // Constant meaning that any UID should be matched when dispatching callbacks
+    private static final int UID_ANY = -2;
+
+
+    AppOpsCheckingServiceImpl(PersistenceScheduler persistenceScheduler,
+                              @NonNull Object lock, Handler handler, Context context,
+                              SparseArray<int[]> switchedOps) {
+        this.mPersistenceScheduler = persistenceScheduler;
+        this.mLock = lock;
+        this.mHandler = handler;
+        this.mContext = context;
+        this.mSwitchedOps = switchedOps;
+    }
+
+    @Override
+    public SparseIntArray getNonDefaultUidModes(int uid) {
+        synchronized (mLock) {
+            SparseIntArray opModes = mUidModes.get(uid, null);
+            if (opModes == null) {
+                return new SparseIntArray();
+            }
+            return opModes.clone();
+        }
+    }
+
+    @Override
+    public int getUidMode(int uid, int op) {
+        synchronized (mLock) {
+            SparseIntArray opModes = mUidModes.get(uid, null);
+            if (opModes == null) {
+                return AppOpsManager.opToDefaultMode(op);
+            }
+            return opModes.get(op, AppOpsManager.opToDefaultMode(op));
+        }
+    }
+
+    @Override
+    public boolean setUidMode(int uid, int op, int mode) {
+        final int defaultMode = AppOpsManager.opToDefaultMode(op);
+        synchronized (mLock) {
+            SparseIntArray opModes = mUidModes.get(uid, null);
+            if (opModes == null) {
+                if (mode != defaultMode) {
+                    opModes = new SparseIntArray();
+                    mUidModes.put(uid, opModes);
+                    opModes.put(op, mode);
+                    mPersistenceScheduler.scheduleWriteLocked();
+                }
+            } else {
+                if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) {
+                    return false;
+                }
+                if (mode == defaultMode) {
+                    opModes.delete(op);
+                    if (opModes.size() <= 0) {
+                        opModes = null;
+                        mUidModes.delete(uid);
+                    }
+                } else {
+                    opModes.put(op, mode);
+                }
+                mPersistenceScheduler.scheduleWriteLocked();
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int getPackageMode(String packageName, int op, @UserIdInt int userId) {
+        synchronized (mLock) {
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return AppOpsManager.opToDefaultMode(op);
+            }
+            SparseIntArray opModes = packageModes.getOrDefault(packageName, null);
+            if (opModes == null) {
+                return AppOpsManager.opToDefaultMode(op);
+            }
+            return opModes.get(op, AppOpsManager.opToDefaultMode(op));
+        }
+    }
+
+    @Override
+    public void setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId) {
+        final int defaultMode = AppOpsManager.opToDefaultMode(op);
+        synchronized (mLock) {
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                packageModes = new ArrayMap<>();
+                mUserPackageModes.put(userId, packageModes);
+            }
+            SparseIntArray opModes = packageModes.get(packageName);
+            if (opModes == null) {
+                if (mode != defaultMode) {
+                    opModes = new SparseIntArray();
+                    packageModes.put(packageName, opModes);
+                    opModes.put(op, mode);
+                    mPersistenceScheduler.scheduleWriteLocked();
+                }
+            } else {
+                if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) {
+                    return;
+                }
+                if (mode == defaultMode) {
+                    opModes.delete(op);
+                    if (opModes.size() <= 0) {
+                        opModes = null;
+                        packageModes.remove(packageName);
+                    }
+                } else {
+                    opModes.put(op, mode);
+                }
+                mPersistenceScheduler.scheduleWriteLocked();
+            }
+        }
+    }
+
+    @Override
+    public void removeUid(int uid) {
+        synchronized (mLock) {
+            SparseIntArray opModes = mUidModes.get(uid);
+            if (opModes == null) {
+                return;
+            }
+            mUidModes.remove(uid);
+            mPersistenceScheduler.scheduleFastWriteLocked();
+        }
+    }
+
+    @Override
+    public boolean areUidModesDefault(int uid) {
+        synchronized (mLock) {
+            SparseIntArray opModes = mUidModes.get(uid);
+            return (opModes == null || opModes.size() <= 0);
+        }
+    }
+
+    @Override
+    public boolean arePackageModesDefault(String packageMode, @UserIdInt int userId) {
+        synchronized (mLock) {
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return true;
+            }
+            SparseIntArray opModes = packageModes.get(packageMode);
+            return (opModes == null || opModes.size() <= 0);
+        }
+    }
+
+    @Override
+    public boolean removePackage(String packageName, @UserIdInt int userId) {
+        synchronized (mLock) {
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            if (packageModes == null) {
+                return false;
+            }
+            SparseIntArray ops = packageModes.remove(packageName);
+            if (ops != null) {
+                mPersistenceScheduler.scheduleFastWriteLocked();
+                return true;
+            }
+            return false;
+        }
+    }
+
+    @Override
+    public void clearAllModes() {
+        synchronized (mLock) {
+            mUidModes.clear();
+            mUserPackageModes.clear();
+        }
+    }
+
+    @Override
+    public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener,
+            int op) {
+        Objects.requireNonNull(changedListener);
+        synchronized (mLock) {
+            ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op);
+            if (modeWatcherSet == null) {
+                modeWatcherSet = new ArraySet<>();
+                mOpModeWatchers.put(op, modeWatcherSet);
+            }
+            modeWatcherSet.add(changedListener);
+        }
+    }
+
+    @Override
+    public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
+            @NonNull String packageName) {
+        Objects.requireNonNull(changedListener);
+        Objects.requireNonNull(packageName);
+        synchronized (mLock) {
+            ArraySet<OnOpModeChangedListener> modeWatcherSet =
+                    mPackageModeWatchers.get(packageName);
+            if (modeWatcherSet == null) {
+                modeWatcherSet = new ArraySet<>();
+                mPackageModeWatchers.put(packageName, modeWatcherSet);
+            }
+            modeWatcherSet.add(changedListener);
+        }
+    }
+
+    @Override
+    public void removeListener(@NonNull OnOpModeChangedListener changedListener) {
+        Objects.requireNonNull(changedListener);
+
+        synchronized (mLock) {
+            for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) {
+                ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i);
+                cbs.remove(changedListener);
+                if (cbs.size() <= 0) {
+                    mOpModeWatchers.removeAt(i);
+                }
+            }
+
+            for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) {
+                ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i);
+                cbs.remove(changedListener);
+                if (cbs.size() <= 0) {
+                    mPackageModeWatchers.removeAt(i);
+                }
+            }
+        }
+    }
+
+    @Override
+    public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) {
+        synchronized (mLock) {
+            ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op);
+            if (modeChangedListenersSet == null) {
+                return new ArraySet<>();
+            }
+            return new ArraySet<>(modeChangedListenersSet);
+        }
+    }
+
+    @Override
+    public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(
+            @NonNull String packageName) {
+        Objects.requireNonNull(packageName);
+
+        synchronized (mLock) {
+            ArraySet<OnOpModeChangedListener> modeChangedListenersSet =
+                    mPackageModeWatchers.get(packageName);
+            if (modeChangedListenersSet == null) {
+                return new ArraySet<>();
+            }
+            return new ArraySet<>(modeChangedListenersSet);
+        }
+    }
+
+    @Override
+    public void notifyWatchersOfChange(int code, int uid) {
+        ArraySet<OnOpModeChangedListener> listenerSet = getOpModeChangedListeners(code);
+        if (listenerSet == null) {
+            return;
+        }
+        for (int i = 0; i < listenerSet.size(); i++) {
+            final OnOpModeChangedListener listener = listenerSet.valueAt(i);
+            notifyOpChanged(listener, code, uid, null);
+        }
+    }
+
+    @Override
+    public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code,
+            int uid, @Nullable String packageName) {
+        Objects.requireNonNull(onModeChangedListener);
+
+        if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0
+                && onModeChangedListener.getWatchingUid() != uid) {
+            return;
+        }
+
+        // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
+        int[] switchedCodes;
+        if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) {
+            switchedCodes = mSwitchedOps.get(code);
+        } else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) {
+            switchedCodes = new int[]{code};
+        } else {
+            switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()};
+        }
+
+        for (int switchedCode : switchedCodes) {
+            // There are features watching for mode changes such as window manager
+            // and location manager which are in our process. The callbacks in these
+            // features may require permissions our remote caller does not have.
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(),
+                        onModeChangedListener.getCallingUid())) {
+                    continue;
+                }
+                onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName);
+            } catch (RemoteException e) {
+                /* ignore */
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
+        // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
+        // as watcher should not use this to signal if the value is changed.
+        return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
+                watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
+    }
+
+    @Override
+    public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
+            @Nullable OnOpModeChangedListener callbackToIgnore) {
+        String[] uidPackageNames = getPackagesForUid(uid);
+        ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null;
+
+        synchronized (mLock) {
+            ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code);
+            if (callbacks != null) {
+                final int callbackCount = callbacks.size();
+                for (int i = 0; i < callbackCount; i++) {
+                    OnOpModeChangedListener callback = callbacks.valueAt(i);
+
+                    if (onlyForeground && (callback.getFlags()
+                            & WATCH_FOREGROUND_CHANGES) == 0) {
+                        continue;
+                    }
+
+                    ArraySet<String> changedPackages = new ArraySet<>();
+                    Collections.addAll(changedPackages, uidPackageNames);
+                    if (callbackSpecs == null) {
+                        callbackSpecs = new ArrayMap<>();
+                    }
+                    callbackSpecs.put(callback, changedPackages);
+                }
+            }
+
+            for (String uidPackageName : uidPackageNames) {
+                callbacks = mPackageModeWatchers.get(uidPackageName);
+                if (callbacks != null) {
+                    if (callbackSpecs == null) {
+                        callbackSpecs = new ArrayMap<>();
+                    }
+                    final int callbackCount = callbacks.size();
+                    for (int i = 0; i < callbackCount; i++) {
+                        OnOpModeChangedListener callback = callbacks.valueAt(i);
+
+                        if (onlyForeground && (callback.getFlags()
+                                & WATCH_FOREGROUND_CHANGES) == 0) {
+                            continue;
+                        }
+
+                        ArraySet<String> changedPackages = callbackSpecs.get(callback);
+                        if (changedPackages == null) {
+                            changedPackages = new ArraySet<>();
+                            callbackSpecs.put(callback, changedPackages);
+                        }
+                        changedPackages.add(uidPackageName);
+                    }
+                }
+            }
+
+            if (callbackSpecs != null && callbackToIgnore != null) {
+                callbackSpecs.remove(callbackToIgnore);
+            }
+        }
+
+        if (callbackSpecs == null) {
+            return;
+        }
+
+        for (int i = 0; i < callbackSpecs.size(); i++) {
+            final OnOpModeChangedListener callback = callbackSpecs.keyAt(i);
+            final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
+            if (reportedPackageNames == null) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsCheckingServiceImpl::notifyOpChanged,
+                        this, callback, code, uid, (String) null));
+
+            } else {
+                final int reportedPackageCount = reportedPackageNames.size();
+                for (int j = 0; j < reportedPackageCount; j++) {
+                    final String reportedPackageName = reportedPackageNames.valueAt(j);
+                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                            AppOpsCheckingServiceImpl::notifyOpChanged,
+                            this, callback, code, uid, reportedPackageName));
+                }
+            }
+        }
+    }
+
+    private static String[] getPackagesForUid(int uid) {
+        String[] packageNames = null;
+
+        // Very early during boot the package manager is not yet or not yet fully started. At this
+        // time there are no packages yet.
+        if (AppGlobals.getPackageManager() != null) {
+            try {
+                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        }
+        if (packageNames == null) {
+            return EmptyArray.STRING;
+        }
+        return packageNames;
+    }
+
+    @Override
+    public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) {
+        synchronized (mLock) {
+            return evalForegroundOps(mUidModes.get(uid), foregroundOps);
+        }
+    }
+
+    @Override
+    public SparseBooleanArray evalForegroundPackageOps(String packageName,
+            SparseBooleanArray foregroundOps, @UserIdInt int userId) {
+        synchronized (mLock) {
+            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
+            return evalForegroundOps(packageModes == null ? null : packageModes.get(packageName),
+                    foregroundOps);
+        }
+    }
+
+    private SparseBooleanArray evalForegroundOps(SparseIntArray opModes,
+            SparseBooleanArray foregroundOps) {
+        SparseBooleanArray tempForegroundOps = foregroundOps;
+        if (opModes != null) {
+            for (int i = opModes.size() - 1; i >= 0; i--) {
+                if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
+                    if (tempForegroundOps == null) {
+                        tempForegroundOps = new SparseBooleanArray();
+                    }
+                    evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps);
+                }
+            }
+        }
+        return tempForegroundOps;
+    }
+
+    private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) {
+        boolean curValue = foregroundOps.get(op, false);
+        ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op);
+        if (listenerSet != null) {
+            for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) {
+                if ((listenerSet.valueAt(cbi).getFlags()
+                        & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
+                    curValue = true;
+                }
+            }
+        }
+        foregroundOps.put(op, curValue);
+    }
+
+    @Override
+    public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage,
+            PrintWriter printWriter) {
+        boolean needSep = false;
+        if (mOpModeWatchers.size() > 0) {
+            boolean printedHeader = false;
+            for (int i = 0; i < mOpModeWatchers.size(); i++) {
+                if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
+                    continue;
+                }
+                boolean printedOpHeader = false;
+                ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
+                        mOpModeWatchers.valueAt(i);
+                for (int j = 0; j < modeChangedListenerSet.size(); j++) {
+                    final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j);
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(listener.getWatchingUid())) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        printWriter.println("  Op mode watchers:");
+                        printedHeader = true;
+                    }
+                    if (!printedOpHeader) {
+                        printWriter.print("    Op ");
+                        printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
+                        printWriter.println(":");
+                        printedOpHeader = true;
+                    }
+                    printWriter.print("      #"); printWriter.print(j); printWriter.print(": ");
+                    printWriter.println(listener.toString());
+                }
+            }
+        }
+
+        if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
+            boolean printedHeader = false;
+            for (int i = 0; i < mPackageModeWatchers.size(); i++) {
+                if (dumpPackage != null
+                        && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
+                    continue;
+                }
+                needSep = true;
+                if (!printedHeader) {
+                    printWriter.println("  Package mode watchers:");
+                    printedHeader = true;
+                }
+                printWriter.print("    Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i));
+                printWriter.println(":");
+                ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
+                        mPackageModeWatchers.valueAt(i);
+
+                for (int j = 0; j < modeChangedListenerSet.size(); j++) {
+                    printWriter.print("      #"); printWriter.print(j); printWriter.print(": ");
+                    printWriter.println(modeChangedListenerSet.valueAt(j).toString());
+                }
+            }
+        }
+        return needSep;
+    }
+
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java
new file mode 100644
index 0000000..d8d0d48
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsCheckingServiceInterface.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.appop;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppOpsManager.Mode;
+import android.util.ArraySet;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+
+import java.io.PrintWriter;
+
+/**
+ * Interface for accessing and modifying modes for app-ops i.e. package and uid modes.
+ * This interface also includes functions for added and removing op mode watchers.
+ * In the future this interface will also include op restrictions.
+ */
+public interface AppOpsCheckingServiceInterface {
+    /**
+     * Returns a copy of non-default app-ops with op as keys and their modes as values for a uid.
+     * Returns an empty SparseIntArray if nothing is set.
+     * @param uid for which we need the app-ops and their modes.
+     */
+    SparseIntArray getNonDefaultUidModes(int uid);
+
+    /**
+     * Returns the app-op mode for a particular app-op of a uid.
+     * Returns default op mode if the op mode for particular uid and op is not set.
+     * @param uid user id for which we need the mode.
+     * @param op app-op for which we need the mode.
+     * @return mode of the app-op.
+     */
+    int getUidMode(int uid, int op);
+
+    /**
+     * Set the app-op mode for a particular uid and op.
+     * The mode is not set if the mode is the same as the default mode for the op.
+     * @param uid user id for which we want to set the mode.
+     * @param op app-op for which we want to set the mode.
+     * @param mode mode for the app-op.
+     * @return true if op mode is changed.
+     */
+    boolean setUidMode(int uid, int op, @Mode int mode);
+
+    /**
+     * Gets the app-op mode for a particular package.
+     * Returns default op mode if the op mode for the particular package is not set.
+     * @param packageName package name for which we need the op mode.
+     * @param op app-op for which we need the mode.
+     * @param userId user id associated with the package.
+     * @return the mode of the app-op.
+     */
+    int getPackageMode(@NonNull String packageName, int op, @UserIdInt int userId);
+
+    /**
+     * Sets the app-op mode for a particular package.
+     * @param packageName package name for which we need to set the op mode.
+     * @param op app-op for which we need to set the mode.
+     * @param mode the mode of the app-op.
+     * @param userId user id associated with the package.
+     *
+     */
+    void setPackageMode(@NonNull String packageName, int op, @Mode int mode, @UserIdInt int userId);
+
+    /**
+     * Stop tracking any app-op modes for a package.
+     * @param packageName Name of the package for which we want to remove all mode tracking.
+     * @param userId user id associated with the package.
+     */
+    boolean removePackage(@NonNull String packageName,  @UserIdInt int userId);
+
+    /**
+     * Stop tracking any app-op modes for this uid.
+     * @param uid user id for which we want to remove all tracking.
+     */
+    void removeUid(int uid);
+
+    /**
+     * Returns true if all uid modes for this uid are
+     * in default state.
+     * @param uid user id
+     */
+    boolean areUidModesDefault(int uid);
+
+    /**
+     * Returns true if all package modes for this package name are
+     * in default state.
+     * @param packageName package name.
+     * @param userId user id associated with the package.
+     */
+    boolean arePackageModesDefault(String packageName, @UserIdInt int userId);
+
+    /**
+     * Stop tracking app-op modes for all uid and packages.
+     */
+    void clearAllModes();
+
+    /**
+     * Registers changedListener to listen to op's mode change.
+     * @param changedListener the listener that must be trigger on the op's mode change.
+     * @param op op representing the app-op whose mode change needs to be listened to.
+     */
+    void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op);
+
+    /**
+     * Registers changedListener to listen to package's app-op's mode change.
+     * @param changedListener the listener that must be trigger on the mode change.
+     * @param packageName of the package whose app-op's mode change needs to be listened to.
+     */
+    void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
+            @NonNull String packageName);
+
+    /**
+     * Stop the changedListener from triggering on any mode change.
+     * @param changedListener the listener that needs to be removed.
+     */
+    void removeListener(@NonNull OnOpModeChangedListener changedListener);
+
+    /**
+     * Temporary API which will be removed once we can safely untangle the methods that use this.
+     * Returns a set of OnOpModeChangedListener that are listening for op's mode changes.
+     * @param op app-op whose mode change is being listened to.
+     */
+    ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op);
+
+    /**
+     * Temporary API which will be removed once we can safely untangle the methods that use this.
+     * Returns a set of OnOpModeChangedListener that are listening for package's op's mode changes.
+     * @param packageName of package whose app-op's mode change is being listened to.
+     */
+    ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(@NonNull String packageName);
+
+    /**
+     * Temporary API which will be removed once we can safely untangle the methods that use this.
+     * Notify that the app-op's mode is changed by triggering the change listener.
+     * @param op App-op whose mode has changed
+     * @param uid user id associated with the app-op (or, if UID_ANY, notifies all users)
+     */
+    void notifyWatchersOfChange(int op, int uid);
+
+    /**
+     * Temporary API which will be removed once we can safely untangle the methods that use this.
+     * Notify that the app-op's mode is changed by triggering the change listener.
+     * @param changedListener the change listener.
+     * @param op App-op whose mode has changed
+     * @param uid user id associated with the app-op
+     * @param packageName package name that is associated with the app-op
+     */
+    void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid,
+            @Nullable String packageName);
+
+    /**
+     * Temporary API which will be removed once we can safely untangle the methods that use this.
+     * Notify that the app-op's mode is changed to all packages associated with the uid by
+     * triggering the appropriate change listener.
+     * @param op App-op whose mode has changed
+     * @param uid user id associated with the app-op
+     * @param onlyForeground true if only watchers that
+     * @param callbackToIgnore callback that should be ignored.
+     */
+    void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground,
+            @Nullable OnOpModeChangedListener callbackToIgnore);
+
+    /**
+     * TODO: Move hasForegroundWatchers and foregroundOps into this.
+     * Go over the list of app-ops for the uid and mark app-ops with MODE_FOREGROUND in
+     * foregroundOps.
+     * @param uid for which the app-op's mode needs to be marked.
+     * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
+     * @return  foregroundOps.
+     */
+    SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps);
+
+    /**
+     * Go over the list of app-ops for the package name and mark app-ops with MODE_FOREGROUND in
+     * foregroundOps.
+     * @param packageName for which the app-op's mode needs to be marked.
+     * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
+     * @param userId user id associated with the package.
+     * @return foregroundOps.
+     */
+    SparseBooleanArray evalForegroundPackageOps(String packageName,
+            SparseBooleanArray foregroundOps, @UserIdInt int userId);
+
+    /**
+     * Dump op mode and package mode listeners and their details.
+     * @param dumpOp if -1 then op mode listeners for all app-ops are dumped. If it's set to an
+     *               app-op, only the watchers for that app-op are dumped.
+     * @param dumpUid uid for which we want to dump op mode watchers.
+     * @param dumpPackage if not null and if dumpOp is -1, dumps watchers for the package name.
+     * @param printWriter writer to dump to.
+     */
+    boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter);
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java b/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java
index adfd2af..af5b07e 100644
--- a/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsRestrictionsImpl.java
@@ -42,7 +42,7 @@
 
     private Context mContext;
     private Handler mHandler;
-    private AppOpsServiceInterface mAppOpsServiceInterface;
+    private AppOpsCheckingServiceInterface mAppOpsServiceInterface;
 
     // Map from (Object token) to (int code) to (boolean restricted)
     private final ArrayMap<Object, SparseBooleanArray> mGlobalRestrictions = new ArrayMap<>();
@@ -56,7 +56,7 @@
             mUserRestrictionExcludedPackageTags = new ArrayMap<>();
 
     public AppOpsRestrictionsImpl(Context context, Handler handler,
-            AppOpsServiceInterface appOpsServiceInterface) {
+            AppOpsCheckingServiceInterface appOpsServiceInterface) {
         mContext = context;
         mHandler = handler;
         mAppOpsServiceInterface = appOpsServiceInterface;
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 7e00c32..39338c6 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -18,55 +18,22 @@
 
 import static android.app.AppOpsManager.ATTRIBUTION_CHAIN_ID_NONE;
 import static android.app.AppOpsManager.ATTRIBUTION_FLAG_TRUSTED;
-import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
-import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
-import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
-import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
-import static android.app.AppOpsManager.FILTER_BY_UID;
-import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
-import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
-import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
-import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
-import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.MODE_DEFAULT;
-import static android.app.AppOpsManager.MODE_ERRORED;
-import static android.app.AppOpsManager.MODE_FOREGROUND;
-import static android.app.AppOpsManager.MODE_IGNORED;
-import static android.app.AppOpsManager.OP_CAMERA;
 import static android.app.AppOpsManager.OP_FLAGS_ALL;
 import static android.app.AppOpsManager.OP_FLAG_SELF;
 import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.AppOpsManager.OP_PLAY_AUDIO;
-import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
-import static android.app.AppOpsManager.OP_RECORD_AUDIO;
-import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
-import static android.app.AppOpsManager.OP_VIBRATE;
-import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
-import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
-import static android.app.AppOpsManager.OpEventProxyInfo;
-import static android.app.AppOpsManager.RestrictionBypass;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_BOOT_TIME_SAMPLING;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_RARELY_USED;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM;
 import static android.app.AppOpsManager.SAMPLING_STRATEGY_UNIFORM_OPS;
-import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
 import static android.app.AppOpsManager._NUM_OP;
-import static android.app.AppOpsManager.extractFlagsFromKey;
-import static android.app.AppOpsManager.extractUidStateFromKey;
-import static android.app.AppOpsManager.modeToName;
-import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
 import static android.app.AppOpsManager.opRestrictsRead;
-import static android.app.AppOpsManager.opToName;
 import static android.app.AppOpsManager.opToPublicName;
-import static android.content.Intent.ACTION_PACKAGE_REMOVED;
-import static android.content.Intent.EXTRA_REPLACING;
 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS;
 import static android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP;
 
-import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
-
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -75,21 +42,16 @@
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
-import android.app.AppOpsManager.AttributedOpEntry;
 import android.app.AppOpsManager.AttributionFlags;
 import android.app.AppOpsManager.HistoricalOps;
-import android.app.AppOpsManager.Mode;
-import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.OpFlags;
 import android.app.AppOpsManagerInternal;
 import android.app.AppOpsManagerInternal.CheckOpsDelegate;
 import android.app.AsyncNotedAppOp;
 import android.app.RuntimeAppOpAccessMessage;
 import android.app.SyncNotedAppOp;
-import android.app.admin.DevicePolicyManagerInternal;
 import android.content.AttributionSource;
 import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -97,15 +59,11 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.PermissionInfo;
-import android.database.ContentObserver;
 import android.hardware.camera2.CameraDevice.CAMERA_AUDIO_RESTRICTION;
-import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.HandlerExecutor;
 import android.os.IBinder;
 import android.os.PackageTagsList;
 import android.os.Process;
@@ -116,22 +74,14 @@
 import android.os.ServiceManager;
 import android.os.ShellCallback;
 import android.os.ShellCommand;
-import android.os.SystemClock;
 import android.os.UserHandle;
-import android.os.storage.StorageManagerInternal;
-import android.permission.PermissionManager;
-import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.AtomicFile;
-import android.util.KeyValueListParser;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 import android.util.TimeUtils;
-import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.Immutable;
@@ -143,59 +93,37 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IAppOpsStartedCallback;
 import com.android.internal.app.MessageSamplingConfig;
-import com.android.internal.compat.IPlatformCompat;
-import com.android.internal.os.Clock;
-import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.modules.utils.TypedXmlPullParser;
-import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.LocalServices;
-import com.android.server.LockGuard;
-import com.android.server.SystemServerInitThreadPool;
 import com.android.server.SystemServiceManager;
 import com.android.server.pm.PackageList;
-import com.android.server.pm.pkg.AndroidPackage;
-import com.android.server.pm.pkg.component.ParsedAttribution;
 import com.android.server.policy.AppOpsPolicy;
 
-import dalvik.annotation.optimization.NeverCompile;
-
-import libcore.util.EmptyArray;
-
 import org.json.JSONException;
 import org.json.JSONObject;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Scanner;
-import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.function.Consumer;
 
-public class AppOpsService extends IAppOpsService.Stub implements PersistenceScheduler {
+/**
+ * The system service component to {@link AppOpsManager}.
+ */
+public class AppOpsService extends IAppOpsService.Stub {
+
+    private final AppOpsServiceInterface mAppOpsService;
+
     static final String TAG = "AppOps";
     static final boolean DEBUG = false;
 
@@ -204,57 +132,19 @@
      */
     private final ArraySet<NoteOpTrace> mNoteOpCallerStacktraces = new ArraySet<>();
 
-    private static final int NO_VERSION = -1;
-    /** Increment by one every time and add the corresponding upgrade logic in
-     *  {@link #upgradeLocked(int)} below. The first version was 1 */
-    private static final int CURRENT_VERSION = 1;
-
-    // Write at most every 30 minutes.
-    static final long WRITE_DELAY = DEBUG ? 1000 : 30*60*1000;
-
     // Constant meaning that any UID should be matched when dispatching callbacks
     private static final int UID_ANY = -2;
 
-    private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
-            OP_PLAY_AUDIO,
-            OP_RECORD_AUDIO,
-            OP_CAMERA,
-            OP_VIBRATE,
-    };
-
     private static final int MAX_UNFORWARDED_OPS = 10;
-    private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
+
     private static final int RARELY_USED_PACKAGES_INITIALIZATION_DELAY_MILLIS = 300000;
 
     final Context mContext;
-    final AtomicFile mFile;
     private final @Nullable File mNoteOpCallerStacktracesFile;
     final Handler mHandler;
 
-    /**
-     * Pool for {@link AttributedOp.OpEventProxyInfoPool} to avoid to constantly reallocate new
-     * objects
-     */
-    @GuardedBy("this")
-    final AttributedOp.OpEventProxyInfoPool mOpEventProxyInfoPool =
-            new AttributedOp.OpEventProxyInfoPool(MAX_UNUSED_POOLED_OBJECTS);
-
-    /**
-     * Pool for {@link AttributedOp.InProgressStartOpEventPool} to avoid to constantly reallocate
-     * new objects
-     */
-    @GuardedBy("this")
-    final AttributedOp.InProgressStartOpEventPool mInProgressStartOpEventPool =
-            new AttributedOp.InProgressStartOpEventPool(mOpEventProxyInfoPool,
-                    MAX_UNUSED_POOLED_OBJECTS);
-
     private final AppOpsManagerInternalImpl mAppOpsManagerInternal
             = new AppOpsManagerInternalImpl();
-    @Nullable private final DevicePolicyManagerInternal dpmi =
-            LocalServices.getService(DevicePolicyManagerInternal.class);
-
-    private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
-            ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
 
     /**
      * Registered callbacks, called from {@link #collectAsyncNotedOp}.
@@ -281,54 +171,9 @@
 
     boolean mWriteNoteOpsScheduled;
 
-    boolean mWriteScheduled;
-    boolean mFastWriteScheduled;
-    final Runnable mWriteRunner = new Runnable() {
-        public void run() {
-            synchronized (AppOpsService.this) {
-                mWriteScheduled = false;
-                mFastWriteScheduled = false;
-                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
-                    @Override protected Void doInBackground(Void... params) {
-                        writeState();
-                        return null;
-                    }
-                };
-                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null);
-            }
-        }
-    };
-
-    @GuardedBy("this")
-    @VisibleForTesting
-    final SparseArray<UidState> mUidStates = new SparseArray<>();
-
-    volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
-
-    /*
-     * These are app op restrictions imposed per user from various parties.
-     */
-    private final ArrayMap<IBinder, ClientUserRestrictionState> mOpUserRestrictions =
-            new ArrayMap<>();
-
-    /*
-     * These are app op restrictions imposed globally from various parties within the system.
-     */
-    private final ArrayMap<IBinder, ClientGlobalRestrictionState> mOpGlobalRestrictions =
-            new ArrayMap<>();
-
-    SparseIntArray mProfileOwners;
-
     private volatile CheckOpsDelegateDispatcher mCheckOpsDelegateDispatcher =
             new CheckOpsDelegateDispatcher(/*policy*/ null, /*delegate*/ null);
 
-    /**
-      * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
-      * changed
-      */
-    private final SparseArray<int[]> mSwitchedOps = new SparseArray<>();
-
-    private ActivityManagerInternal mActivityManagerInternal;
 
     /** Package sampled for message collection in the current session */
     @GuardedBy("this")
@@ -362,545 +207,8 @@
     /** Package Manager internal. Access via {@link #getPackageManagerInternal()} */
     private @Nullable PackageManagerInternal mPackageManagerInternal;
 
-    /** Interface for app-op modes.*/
-    @VisibleForTesting AppOpsServiceInterface mAppOpsServiceInterface;
-
-    /** Interface for app-op restrictions.*/
-    @VisibleForTesting AppOpsRestrictions mAppOpsRestrictions;
-
-    private AppOpsUidStateTracker mUidStateTracker;
-
-    /** Hands the definition of foreground and uid states */
-    @GuardedBy("this")
-    public AppOpsUidStateTracker getUidStateTracker() {
-        if (mUidStateTracker == null) {
-            mUidStateTracker = new AppOpsUidStateTrackerImpl(
-                    LocalServices.getService(ActivityManagerInternal.class),
-                    mHandler,
-                    r -> {
-                        synchronized (AppOpsService.this) {
-                            r.run();
-                        }
-                    },
-                    Clock.SYSTEM_CLOCK, mConstants);
-
-            mUidStateTracker.addUidStateChangedCallback(new HandlerExecutor(mHandler),
-                    this::onUidStateChanged);
-        }
-        return mUidStateTracker;
-    }
-
-    /**
-     * All times are in milliseconds. These constants are kept synchronized with the system
-     * global Settings. Any access to this class or its fields should be done while
-     * holding the AppOpsService lock.
-     */
-    final class Constants extends ContentObserver {
-
-        /**
-         * How long we want for a drop in uid state from top to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME
-         */
-        public long TOP_STATE_SETTLE_TIME;
-
-        /**
-         * How long we want for a drop in uid state from foreground to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME
-         */
-        public long FG_SERVICE_STATE_SETTLE_TIME;
-
-        /**
-         * How long we want for a drop in uid state from background to settle before applying it.
-         * @see Settings.Global#APP_OPS_CONSTANTS
-         * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME
-         */
-        public long BG_STATE_SETTLE_TIME;
-
-        private final KeyValueListParser mParser = new KeyValueListParser(',');
-        private ContentResolver mResolver;
-
-        public Constants(Handler handler) {
-            super(handler);
-            updateConstants();
-        }
-
-        public void startMonitoring(ContentResolver resolver) {
-            mResolver = resolver;
-            mResolver.registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
-                    false, this);
-            updateConstants();
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            updateConstants();
-        }
-
-        private void updateConstants() {
-            String value = mResolver != null ? Settings.Global.getString(mResolver,
-                    Settings.Global.APP_OPS_CONSTANTS) : "";
-
-            synchronized (AppOpsService.this) {
-                try {
-                    mParser.setString(value);
-                } catch (IllegalArgumentException e) {
-                    // Failed to parse the settings string, log this and move on
-                    // with defaults.
-                    Slog.e(TAG, "Bad app ops settings", e);
-                }
-                TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L);
-                FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L);
-                BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
-                        KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
-            }
-        }
-
-        void dump(PrintWriter pw) {
-            pw.println("  Settings:");
-
-            pw.print("    "); pw.print(KEY_TOP_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
-            pw.println();
-            pw.print("    "); pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
-            pw.println();
-            pw.print("    "); pw.print(KEY_BG_STATE_SETTLE_TIME); pw.print("=");
-            TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
-            pw.println();
-        }
-    }
-
-    @VisibleForTesting
-    final Constants mConstants;
-
-    @VisibleForTesting
-    final class UidState {
-        public final int uid;
-
-        public ArrayMap<String, Ops> pkgOps;
-
-        // true indicates there is an interested observer, false there isn't but it has such an op
-        //TODO: Move foregroundOps and hasForegroundWatchers into the AppOpsServiceInterface.
-        public SparseBooleanArray foregroundOps;
-        public boolean hasForegroundWatchers;
-
-        public UidState(int uid) {
-            this.uid = uid;
-        }
-
-        public void clear() {
-            mAppOpsServiceInterface.removeUid(uid);
-            if (pkgOps != null) {
-                for (String packageName : pkgOps.keySet()) {
-                    mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
-                }
-            }
-            pkgOps = null;
-        }
-
-        public boolean isDefault() {
-            boolean areAllPackageModesDefault = true;
-            if (pkgOps != null) {
-                for (String packageName : pkgOps.keySet()) {
-                    if (!mAppOpsServiceInterface.arePackageModesDefault(packageName,
-                            UserHandle.getUserId(uid))) {
-                        areAllPackageModesDefault = false;
-                        break;
-                    }
-                }
-            }
-            return (pkgOps == null || pkgOps.isEmpty())
-                    && mAppOpsServiceInterface.areUidModesDefault(uid)
-                    && areAllPackageModesDefault;
-        }
-
-        // Functions for uid mode access and manipulation.
-        public SparseIntArray getNonDefaultUidModes() {
-            return mAppOpsServiceInterface.getNonDefaultUidModes(uid);
-        }
-
-        public int getUidMode(int op) {
-            return mAppOpsServiceInterface.getUidMode(uid, op);
-        }
-
-        public boolean setUidMode(int op, int mode) {
-            return mAppOpsServiceInterface.setUidMode(uid, op, mode);
-        }
-
-        @SuppressWarnings("GuardedBy")
-        int evalMode(int op, int mode) {
-            return getUidStateTracker().evalMode(uid, op, mode);
-        }
-
-        public void evalForegroundOps() {
-            foregroundOps = null;
-            foregroundOps = mAppOpsServiceInterface.evalForegroundUidOps(uid, foregroundOps);
-            if (pkgOps != null) {
-                for (int i = pkgOps.size() - 1; i >= 0; i--) {
-                    foregroundOps = mAppOpsServiceInterface
-                            .evalForegroundPackageOps(pkgOps.valueAt(i).packageName, foregroundOps,
-                                    UserHandle.getUserId(uid));
-                }
-            }
-            hasForegroundWatchers = false;
-            if (foregroundOps != null) {
-                for (int i = 0;  i < foregroundOps.size(); i++) {
-                    if (foregroundOps.valueAt(i)) {
-                        hasForegroundWatchers = true;
-                        break;
-                    }
-                }
-            }
-        }
-
-        @SuppressWarnings("GuardedBy")
-        public int getState() {
-            return getUidStateTracker().getUidState(uid);
-        }
-
-        @SuppressWarnings("GuardedBy")
-        public void dump(PrintWriter pw, long nowElapsed) {
-            getUidStateTracker().dumpUidState(pw, uid, nowElapsed);
-        }
-    }
-
-    final static class Ops extends SparseArray<Op> {
-        final String packageName;
-        final UidState uidState;
-
-        /**
-         * The restriction properties of the package. If {@code null} it could not have been read
-         * yet and has to be refreshed.
-         */
-        @Nullable RestrictionBypass bypass;
-
-        /** Lazily populated cache of attributionTags of this package */
-        final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
-
-        /**
-         * Lazily populated cache of <b>valid</b> attributionTags of this package, a set smaller
-         * than or equal to {@link #knownAttributionTags}.
-         */
-        final @NonNull ArraySet<String> validAttributionTags = new ArraySet<>();
-
-        Ops(String _packageName, UidState _uidState) {
-            packageName = _packageName;
-            uidState = _uidState;
-        }
-    }
-
-    /** Returned from {@link #verifyAndGetBypass(int, String, String, String)}. */
-    private static final class PackageVerificationResult {
-
-        final RestrictionBypass bypass;
-        final boolean isAttributionTagValid;
-
-        PackageVerificationResult(RestrictionBypass bypass, boolean isAttributionTagValid) {
-            this.bypass = bypass;
-            this.isAttributionTagValid = isAttributionTagValid;
-        }
-    }
-
-    final class Op {
-        int op;
-        int uid;
-        final UidState uidState;
-        final @NonNull String packageName;
-
-        /** attributionTag -> AttributedOp */
-        final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
-
-        Op(UidState uidState, String packageName, int op, int uid) {
-            this.op = op;
-            this.uid = uid;
-            this.uidState = uidState;
-            this.packageName = packageName;
-        }
-
-        @Mode int getMode() {
-            return mAppOpsServiceInterface.getPackageMode(packageName, this.op,
-                    UserHandle.getUserId(this.uid));
-        }
-        void setMode(@Mode int mode) {
-            mAppOpsServiceInterface.setPackageMode(packageName, this.op, mode,
-                    UserHandle.getUserId(this.uid));
-        }
-
-        void removeAttributionsWithNoTime() {
-            for (int i = mAttributions.size() - 1; i >= 0; i--) {
-                if (!mAttributions.valueAt(i).hasAnyTime()) {
-                    mAttributions.removeAt(i);
-                }
-            }
-        }
-
-        private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
-                @Nullable String attributionTag) {
-            AttributedOp attributedOp;
-
-            attributedOp = mAttributions.get(attributionTag);
-            if (attributedOp == null) {
-                attributedOp = new AttributedOp(AppOpsService.this, attributionTag, parent);
-                mAttributions.put(attributionTag, attributedOp);
-            }
-
-            return attributedOp;
-        }
-
-        @NonNull OpEntry createEntryLocked() {
-            final int numAttributions = mAttributions.size();
-
-            final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
-                    new ArrayMap<>(numAttributions);
-            for (int i = 0; i < numAttributions; i++) {
-                attributionEntries.put(mAttributions.keyAt(i),
-                        mAttributions.valueAt(i).createAttributedOpEntryLocked());
-            }
-
-            return new OpEntry(op, getMode(), attributionEntries);
-        }
-
-        @NonNull OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
-            final int numAttributions = mAttributions.size();
-
-            final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
-            for (int i = 0; i < numAttributions; i++) {
-                if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
-                    attributionEntries.put(mAttributions.keyAt(i),
-                            mAttributions.valueAt(i).createAttributedOpEntryLocked());
-                    break;
-                }
-            }
-
-            return new OpEntry(op, getMode(), attributionEntries);
-        }
-
-        boolean isRunning() {
-            final int numAttributions = mAttributions.size();
-            for (int i = 0; i < numAttributions; i++) {
-                if (mAttributions.valueAt(i).isRunning()) {
-                    return true;
-                }
-            }
-
-            return false;
-        }
-    }
-
-    final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
-    final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
     final AudioRestrictionManager mAudioRestrictionManager = new AudioRestrictionManager();
 
-    final class ModeCallback extends OnOpModeChangedListener implements DeathRecipient  {
-        /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
-        public static final int ALL_OPS = -2;
-
-        // Need to keep this only because stopWatchingMode needs an IAppOpsCallback.
-        // Otherwise we can just use the IBinder object.
-        private final IAppOpsCallback mCallback;
-
-        ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOpCode,
-                int callingUid, int callingPid) {
-            super(watchingUid, flags, watchedOpCode, callingUid, callingPid);
-            this.mCallback = callback;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("ModeCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, getWatchingUid());
-            sb.append(" flags=0x");
-            sb.append(Integer.toHexString(getFlags()));
-            switch (getWatchedOpCode()) {
-                case OP_NONE:
-                    break;
-                case ALL_OPS:
-                    sb.append(" op=(all)");
-                    break;
-                default:
-                    sb.append(" op=");
-                    sb.append(opToName(getWatchedOpCode()));
-                    break;
-            }
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, getCallingUid());
-            sb.append(" pid=");
-            sb.append(getCallingPid());
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void unlinkToDeath() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingMode(mCallback);
-        }
-
-        @Override
-        public void onOpModeChanged(int op, int uid, String packageName) throws RemoteException {
-            mCallback.opChanged(op, uid, packageName);
-        }
-    }
-
-    final class ActiveCallback implements DeathRecipient {
-        final IAppOpsActiveCallback mCallback;
-        final int mWatchingUid;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("ActiveCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void destroy() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingActive(mCallback);
-        }
-    }
-
-    final class StartedCallback implements DeathRecipient {
-        final IAppOpsStartedCallback mCallback;
-        final int mWatchingUid;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("StartedCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void destroy() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingStarted(mCallback);
-        }
-    }
-
-    final class NotedCallback implements DeathRecipient {
-        final IAppOpsNotedCallback mCallback;
-        final int mWatchingUid;
-        final int mCallingUid;
-        final int mCallingPid;
-
-        NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
-                int callingPid) {
-            mCallback = callback;
-            mWatchingUid = watchingUid;
-            mCallingUid = callingUid;
-            mCallingPid = callingPid;
-            try {
-                mCallback.asBinder().linkToDeath(this, 0);
-            } catch (RemoteException e) {
-                /*ignored*/
-            }
-        }
-
-        @Override
-        public String toString() {
-            StringBuilder sb = new StringBuilder(128);
-            sb.append("NotedCallback{");
-            sb.append(Integer.toHexString(System.identityHashCode(this)));
-            sb.append(" watchinguid=");
-            UserHandle.formatUid(sb, mWatchingUid);
-            sb.append(" from uid=");
-            UserHandle.formatUid(sb, mCallingUid);
-            sb.append(" pid=");
-            sb.append(mCallingPid);
-            sb.append('}');
-            return sb.toString();
-        }
-
-        void destroy() {
-            mCallback.asBinder().unlinkToDeath(this, 0);
-        }
-
-        @Override
-        public void binderDied() {
-            stopWatchingNoted(mCallback);
-        }
-    }
-
-    /**
-     * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
-     */
-    static void onClientDeath(@NonNull AttributedOp attributedOp,
-            @NonNull IBinder clientId) {
-        attributedOp.onClientDeath(clientId);
-    }
-
-
     /**
      * Loads the OpsValidation file results into a hashmap {@link #mNoteOpCallerStacktraces}
      * so that we do not log the same operation twice between instances
@@ -925,20 +233,12 @@
     }
 
     public AppOpsService(File storagePath, Handler handler, Context context) {
-        mContext = context;
+        this(handler, context, new AppOpsServiceImpl(storagePath, handler, context));
+    }
 
-        for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
-            int switchCode = AppOpsManager.opToSwitch(switchedCode);
-            mSwitchedOps.put(switchCode,
-                    ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
-        }
-        mAppOpsServiceInterface =
-                new LegacyAppOpsServiceInterfaceImpl(this, this, handler, context, mSwitchedOps);
-        mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler,
-                mAppOpsServiceInterface);
-
-        LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
-        mFile = new AtomicFile(storagePath, "appops");
+    @VisibleForTesting
+    public AppOpsService(Handler handler, Context context,
+            AppOpsServiceInterface appOpsServiceInterface) {
         if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED) {
             mNoteOpCallerStacktracesFile = new File(SystemServiceManager.ensureSystemDir(),
                     "noteOpStackTraces.json");
@@ -946,185 +246,25 @@
         } else {
             mNoteOpCallerStacktracesFile = null;
         }
+
+        mAppOpsService = appOpsServiceInterface;
+        mContext = context;
         mHandler = handler;
-        mConstants = new Constants(mHandler);
-        readState();
     }
 
+    /**
+     * Publishes binder and local service.
+     */
     public void publish() {
         ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
         LocalServices.addService(AppOpsManagerInternal.class, mAppOpsManagerInternal);
     }
 
-    /** Handler for work when packages are removed or updated */
-    private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            String pkgName = intent.getData().getEncodedSchemeSpecificPart();
-            int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
-
-            if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
-                synchronized (AppOpsService.this) {
-                    UidState uidState = mUidStates.get(uid);
-                    if (uidState == null || uidState.pkgOps == null) {
-                        return;
-                    }
-                    mAppOpsServiceInterface.removePackage(pkgName, UserHandle.getUserId(uid));
-                    Ops removedOps = uidState.pkgOps.remove(pkgName);
-                    if (removedOps != null) {
-                        scheduleFastWriteLocked();
-                    }
-                }
-            } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
-                AndroidPackage pkg = getPackageManagerInternal().getPackage(pkgName);
-                if (pkg == null) {
-                    return;
-                }
-
-                ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
-                ArraySet<String> attributionTags = new ArraySet<>();
-                attributionTags.add(null);
-                if (pkg.getAttributions() != null) {
-                    int numAttributions = pkg.getAttributions().size();
-                    for (int attributionNum = 0; attributionNum < numAttributions;
-                            attributionNum++) {
-                        ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
-                        attributionTags.add(attribution.getTag());
-
-                        int numInheritFrom = attribution.getInheritFrom().size();
-                        for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
-                                inheritFromNum++) {
-                            dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
-                                    attribution.getTag());
-                        }
-                    }
-                }
-
-                synchronized (AppOpsService.this) {
-                    UidState uidState = mUidStates.get(uid);
-                    if (uidState == null || uidState.pkgOps == null) {
-                        return;
-                    }
-
-                    Ops ops = uidState.pkgOps.get(pkgName);
-                    if (ops == null) {
-                        return;
-                    }
-
-                    // Reset cached package properties to re-initialize when needed
-                    ops.bypass = null;
-                    ops.knownAttributionTags.clear();
-
-                    // Merge data collected for removed attributions into their successor
-                    // attributions
-                    int numOps = ops.size();
-                    for (int opNum = 0; opNum < numOps; opNum++) {
-                        Op op = ops.valueAt(opNum);
-
-                        int numAttributions = op.mAttributions.size();
-                        for (int attributionNum = numAttributions - 1; attributionNum >= 0;
-                                attributionNum--) {
-                            String attributionTag = op.mAttributions.keyAt(attributionNum);
-
-                            if (attributionTags.contains(attributionTag)) {
-                                // attribution still exist after upgrade
-                                continue;
-                            }
-
-                            String newAttributionTag = dstAttributionTags.get(attributionTag);
-
-                            AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
-                                    newAttributionTag);
-                            newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
-                            op.mAttributions.removeAt(attributionNum);
-
-                            scheduleFastWriteLocked();
-                        }
-                    }
-                }
-            }
-        }
-    };
-
+    /**
+     * Finishes boot sequence.
+     */
     public void systemReady() {
-        mConstants.startMonitoring(mContext.getContentResolver());
-        mHistoricalRegistry.systemReady(mContext.getContentResolver());
-
-        IntentFilter packageUpdateFilter = new IntentFilter();
-        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        packageUpdateFilter.addDataScheme("package");
-
-        mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
-                packageUpdateFilter, null, null);
-
-        synchronized (this) {
-            for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
-                int uid = mUidStates.keyAt(uidNum);
-                UidState uidState = mUidStates.valueAt(uidNum);
-
-                String[] pkgsInUid = getPackagesForUid(uidState.uid);
-                if (ArrayUtils.isEmpty(pkgsInUid)) {
-                    uidState.clear();
-                    mUidStates.removeAt(uidNum);
-                    scheduleFastWriteLocked();
-                    continue;
-                }
-
-                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
-                if (pkgs == null) {
-                    continue;
-                }
-
-                int numPkgs = pkgs.size();
-                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
-                    String pkg = pkgs.keyAt(pkgNum);
-
-                    String action;
-                    if (!ArrayUtils.contains(pkgsInUid, pkg)) {
-                        action = Intent.ACTION_PACKAGE_REMOVED;
-                    } else {
-                        action = Intent.ACTION_PACKAGE_REPLACED;
-                    }
-
-                    SystemServerInitThreadPool.submit(
-                            () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
-                                    .setData(Uri.fromParts("package", pkg, null))
-                                    .putExtra(Intent.EXTRA_UID, uid)),
-                            "Update app-ops uidState in case package " + pkg + " changed");
-                }
-            }
-        }
-
-        final IntentFilter packageSuspendFilter = new IntentFilter();
-        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
-        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
-                final String[] changedPkgs = intent.getStringArrayExtra(
-                        Intent.EXTRA_CHANGED_PACKAGE_LIST);
-                for (int code : OPS_RESTRICTED_ON_SUSPEND) {
-                    ArraySet<OnOpModeChangedListener> onModeChangedListeners;
-                    synchronized (AppOpsService.this) {
-                        onModeChangedListeners =
-                                mAppOpsServiceInterface.getOpModeChangedListeners(code);
-                        if (onModeChangedListeners == null) {
-                            continue;
-                        }
-                    }
-                    for (int i = 0; i < changedUids.length; i++) {
-                        final int changedUid = changedUids[i];
-                        final String changedPkg = changedPkgs[i];
-                        // We trust packagemanager to insert matching uid and packageNames in the
-                        // extras
-                        notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg);
-                    }
-                }
-            }
-        }, UserHandle.ALL, packageSuspendFilter, null, null);
+        mAppOpsService.systemReady();
 
         final IntentFilter packageAddedFilter = new IntentFilter();
         packageAddedFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
@@ -1132,9 +272,8 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                final Uri data = intent.getData();
 
-                final String packageName = data.getSchemeSpecificPart();
+                final String packageName = intent.getData().getSchemeSpecificPart();
                 PackageInfo pi = getPackageManagerInternal().getPackageInfo(packageName,
                         PackageManager.GET_PERMISSIONS, Process.myUid(), mContext.getUserId());
                 if (isSamplingTarget(pi)) {
@@ -1169,8 +308,6 @@
                         }
                     }
                 });
-
-        mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
     }
 
     /**
@@ -1185,132 +322,18 @@
         mCheckOpsDelegateDispatcher = new CheckOpsDelegateDispatcher(policy, delegate);
     }
 
+    /**
+     * Notify when a package is removed
+     */
     public void packageRemoved(int uid, String packageName) {
-        synchronized (this) {
-            UidState uidState = mUidStates.get(uid);
-            if (uidState == null) {
-                return;
-            }
-
-            Ops removedOps = null;
-
-            // Remove any package state if such.
-            if (uidState.pkgOps != null) {
-                removedOps = uidState.pkgOps.remove(packageName);
-                mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
-            }
-
-            // If we just nuked the last package state check if the UID is valid.
-            if (removedOps != null && uidState.pkgOps.isEmpty()
-                    && getPackagesForUid(uid).length <= 0) {
-                uidState.clear();
-                mUidStates.remove(uid);
-            }
-
-            if (removedOps != null) {
-                scheduleFastWriteLocked();
-
-                final int numOps = removedOps.size();
-                for (int opNum = 0; opNum < numOps; opNum++) {
-                    final Op op = removedOps.valueAt(opNum);
-
-                    final int numAttributions = op.mAttributions.size();
-                    for (int attributionNum = 0; attributionNum < numAttributions;
-                            attributionNum++) {
-                        AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
-
-                        while (attributedOp.isRunning()) {
-                            attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
-                        }
-                        while (attributedOp.isPaused()) {
-                            attributedOp.finished(attributedOp.mPausedInProgressEvents.keyAt(0));
-                        }
-                    }
-                }
-            }
-        }
-
-        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory,
-                    mHistoricalRegistry, uid, packageName));
+        mAppOpsService.packageRemoved(uid, packageName);
     }
 
+    /**
+     * Notify when a uid is removed.
+     */
     public void uidRemoved(int uid) {
-        synchronized (this) {
-            if (mUidStates.indexOfKey(uid) >= 0) {
-                mUidStates.get(uid).clear();
-                mUidStates.remove(uid);
-                scheduleFastWriteLocked();
-            }
-        }
-    }
-
-    // The callback method from ForegroundPolicyInterface
-    private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) {
-        synchronized (this) {
-            UidState uidState = getUidStateLocked(uid, true);
-
-            if (uidState != null && foregroundModeMayChange && uidState.hasForegroundWatchers) {
-                for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
-                    if (!uidState.foregroundOps.valueAt(fgi)) {
-                        continue;
-                    }
-                    final int code = uidState.foregroundOps.keyAt(fgi);
-
-                    if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)
-                            && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) {
-                        mHandler.sendMessage(PooledLambda.obtainMessage(
-                                AppOpsService::notifyOpChangedForAllPkgsInUid,
-                                this, code, uidState.uid, true, null));
-                    } else if (uidState.pkgOps != null) {
-                        final ArraySet<OnOpModeChangedListener> listenerSet =
-                                mAppOpsServiceInterface.getOpModeChangedListeners(code);
-                        if (listenerSet != null) {
-                            for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
-                                final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
-                                if ((listener.getFlags()
-                                        & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
-                                        || !listener.isWatchingUid(uidState.uid)) {
-                                    continue;
-                                }
-                                for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
-                                    final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
-                                    if (op == null) {
-                                        continue;
-                                    }
-                                    if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
-                                        mHandler.sendMessage(PooledLambda.obtainMessage(
-                                                AppOpsService::notifyOpChanged,
-                                                this, listenerSet.valueAt(cbi), code, uidState.uid,
-                                                uidState.pkgOps.keyAt(pkgi)));
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            if (uidState != null && uidState.pkgOps != null) {
-                int numPkgs = uidState.pkgOps.size();
-                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
-                    Ops ops = uidState.pkgOps.valueAt(pkgNum);
-
-                    int numOps = ops.size();
-                    for (int opNum = 0; opNum < numOps; opNum++) {
-                        Op op = ops.valueAt(opNum);
-
-                        int numAttributions = op.mAttributions.size();
-                        for (int attributionNum = 0; attributionNum < numAttributions;
-                                attributionNum++) {
-                            AttributedOp attributedOp = op.mAttributions.valueAt(
-                                    attributionNum);
-
-                            attributedOp.onUidStateChanged(state);
-                        }
-                    }
-                }
-            }
-        }
+        mAppOpsService.uidRemoved(uid);
     }
 
     /**
@@ -1318,542 +341,60 @@
      */
     public void updateUidProcState(int uid, int procState,
             @ActivityManager.ProcessCapability int capability) {
-        synchronized (this) {
-            getUidStateTracker().updateUidProcState(uid, procState, capability);
-            if (!mUidStates.contains(uid)) {
-                UidState uidState = new UidState(uid);
-                mUidStates.put(uid, uidState);
-                onUidStateChanged(uid,
-                        AppOpsUidStateTracker.processStateToUidState(procState), false);
-            }
-        }
+        mAppOpsService.updateUidProcState(uid, procState, capability);
     }
 
+    /**
+     * Initiates shutdown.
+     */
     public void shutdown() {
-        Slog.w(TAG, "Writing app ops before shutdown...");
-        boolean doWrite = false;
-        synchronized (this) {
-            if (mWriteScheduled) {
-                mWriteScheduled = false;
-                mFastWriteScheduled = false;
-                mHandler.removeCallbacks(mWriteRunner);
-                doWrite = true;
-            }
-        }
-        if (doWrite) {
-            writeState();
-        }
+        mAppOpsService.shutdown();
+
         if (AppOpsManager.NOTE_OP_COLLECTION_ENABLED && mWriteNoteOpsScheduled) {
             writeNoteOps();
         }
-
-        mHistoricalRegistry.shutdown();
-    }
-
-    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
-        ArrayList<AppOpsManager.OpEntry> resOps = null;
-        if (ops == null) {
-            resOps = new ArrayList<>();
-            for (int j=0; j<pkgOps.size(); j++) {
-                Op curOp = pkgOps.valueAt(j);
-                resOps.add(getOpEntryForResult(curOp));
-            }
-        } else {
-            for (int j=0; j<ops.length; j++) {
-                Op curOp = pkgOps.get(ops[j]);
-                if (curOp != null) {
-                    if (resOps == null) {
-                        resOps = new ArrayList<>();
-                    }
-                    resOps.add(getOpEntryForResult(curOp));
-                }
-            }
-        }
-        return resOps;
-    }
-
-    @Nullable
-    private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
-            @Nullable int[] ops) {
-        final SparseIntArray opModes = uidState.getNonDefaultUidModes();
-        if (opModes == null) {
-            return null;
-        }
-
-        int opModeCount = opModes.size();
-        if (opModeCount == 0) {
-            return null;
-        }
-        ArrayList<AppOpsManager.OpEntry> resOps = null;
-        if (ops == null) {
-            resOps = new ArrayList<>();
-            for (int i = 0; i < opModeCount; i++) {
-                int code = opModes.keyAt(i);
-                resOps.add(new OpEntry(code, opModes.get(code), Collections.emptyMap()));
-            }
-        } else {
-            for (int j=0; j<ops.length; j++) {
-                int code = ops[j];
-                if (opModes.indexOfKey(code) >= 0) {
-                    if (resOps == null) {
-                        resOps = new ArrayList<>();
-                    }
-                    resOps.add(new OpEntry(code, opModes.get(code), Collections.emptyMap()));
-                }
-            }
-        }
-        return resOps;
-    }
-
-    private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op) {
-        return op.createEntryLocked();
     }
 
     @Override
     public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
-        final int callingUid = Binder.getCallingUid();
-        final boolean hasAllPackageAccess = mContext.checkPermission(
-                Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(),
-                Binder.getCallingUid(), null) == PackageManager.PERMISSION_GRANTED;
-        ArrayList<AppOpsManager.PackageOps> res = null;
-        synchronized (this) {
-            final int uidStateCount = mUidStates.size();
-            for (int i = 0; i < uidStateCount; i++) {
-                UidState uidState = mUidStates.valueAt(i);
-                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
-                    continue;
-                }
-                ArrayMap<String, Ops> packages = uidState.pkgOps;
-                final int packageCount = packages.size();
-                for (int j = 0; j < packageCount; j++) {
-                    Ops pkgOps = packages.valueAt(j);
-                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
-                    if (resOps != null) {
-                        if (res == null) {
-                            res = new ArrayList<>();
-                        }
-                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                                pkgOps.packageName, pkgOps.uidState.uid, resOps);
-                        // Caller can always see their packages and with a permission all.
-                        if (hasAllPackageAccess || callingUid == pkgOps.uidState.uid) {
-                            res.add(resPackage);
-                        }
-                    }
-                }
-            }
-        }
-        return res;
+        return mAppOpsService.getPackagesForOps(ops);
     }
 
     @Override
     public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
             int[] ops) {
-        enforceGetAppOpsStatsPermissionIfNeeded(uid,packageName);
-        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return Collections.emptyList();
-        }
-        synchronized (this) {
-            Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null,
-                    /* edit */ false);
-            if (pkgOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
-            if (resOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
-            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                    pkgOps.packageName, pkgOps.uidState.uid, resOps);
-            res.add(resPackage);
-            return res;
-        }
-    }
-
-    private void enforceGetAppOpsStatsPermissionIfNeeded(int uid, String packageName) {
-        final int callingUid = Binder.getCallingUid();
-        // We get to access everything
-        if (callingUid == Process.myPid()) {
-            return;
-        }
-        // Apps can access their own data
-        if (uid == callingUid && packageName != null
-                && checkPackage(uid, packageName) == MODE_ALLOWED) {
-            return;
-        }
-        // Otherwise, you need a permission...
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), callingUid, null);
-    }
-
-    /**
-     * Verify that historical appop request arguments are valid.
-     */
-    private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
-            String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
-            long endTimeMillis, int flags) {
-        if ((filter & FILTER_BY_UID) != 0) {
-            Preconditions.checkArgument(uid != Process.INVALID_UID);
-        } else {
-            Preconditions.checkArgument(uid == Process.INVALID_UID);
-        }
-
-        if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
-            Objects.requireNonNull(packageName);
-        } else {
-            Preconditions.checkArgument(packageName == null);
-        }
-
-        if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
-            Preconditions.checkArgument(attributionTag == null);
-        }
-
-        if ((filter & FILTER_BY_OP_NAMES) != 0) {
-            Objects.requireNonNull(opNames);
-        } else {
-            Preconditions.checkArgument(opNames == null);
-        }
-
-        Preconditions.checkFlagsArgument(filter,
-                FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
-                        | FILTER_BY_OP_NAMES);
-        Preconditions.checkArgumentNonnegative(beginTimeMillis);
-        Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
-        Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
+        return mAppOpsService.getOpsForPackage(uid, packageName, ops);
     }
 
     @Override
     public void getHistoricalOps(int uid, String packageName, String attributionTag,
             List<String> opNames, int dataType, int filter, long beginTimeMillis,
             long endTimeMillis, int flags, RemoteCallback callback) {
-        PackageManager pm = mContext.getPackageManager();
-
-        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
-                beginTimeMillis, endTimeMillis, flags);
-        Objects.requireNonNull(callback, "callback cannot be null");
-        ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
-        boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid();
-        if (!isSelfRequest) {
-            boolean isCallerInstrumented =
-                    ami.getInstrumentationSourceUid(Binder.getCallingUid()) != Process.INVALID_UID;
-            boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
-            boolean isCallerPermissionController;
-            try {
-                isCallerPermissionController = pm.getPackageUidAsUser(
-                        mContext.getPackageManager().getPermissionControllerPackageName(), 0,
-                        UserHandle.getUserId(Binder.getCallingUid()))
-                        == Binder.getCallingUid();
-            } catch (PackageManager.NameNotFoundException doesNotHappen) {
-                return;
-            }
-
-            boolean doesCallerHavePermission = mContext.checkPermission(
-                    android.Manifest.permission.GET_HISTORICAL_APP_OPS_STATS,
-                    Binder.getCallingPid(), Binder.getCallingUid())
-                    == PackageManager.PERMISSION_GRANTED;
-
-            if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController
-                    && !doesCallerHavePermission) {
-                mHandler.post(() -> callback.sendResult(new Bundle()));
-                return;
-            }
-
-            mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                    Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
-        }
-
-        final String[] opNamesArray = (opNames != null)
-                ? opNames.toArray(new String[opNames.size()]) : null;
-
-        Set<String> attributionChainExemptPackages = null;
-        if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
-            attributionChainExemptPackages =
-                    PermissionManager.getIndicatorExemptedPackages(mContext);
-        }
-
-        final String[] chainExemptPkgArray = attributionChainExemptPackages != null
-                ? attributionChainExemptPackages.toArray(
-                        new String[attributionChainExemptPackages.size()]) : null;
-
-        // Must not hold the appops lock
-        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
-                filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
-                callback).recycleOnUse());
+        mAppOpsService.getHistoricalOps(uid, packageName, attributionTag, opNames,
+                dataType, filter, beginTimeMillis, endTimeMillis, flags, callback);
     }
 
     @Override
     public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
             List<String> opNames, int dataType, int filter, long beginTimeMillis,
             long endTimeMillis, int flags, RemoteCallback callback) {
-        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
-                beginTimeMillis, endTimeMillis, flags);
-        Objects.requireNonNull(callback, "callback cannot be null");
-
-        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
-
-        final String[] opNamesArray = (opNames != null)
-                ? opNames.toArray(new String[opNames.size()]) : null;
-
-        Set<String> attributionChainExemptPackages = null;
-        if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
-            attributionChainExemptPackages =
-                    PermissionManager.getIndicatorExemptedPackages(mContext);
-        }
-
-        final String[] chainExemptPkgArray = attributionChainExemptPackages != null
-                ? attributionChainExemptPackages.toArray(
-                new String[attributionChainExemptPackages.size()]) : null;
-
-        // Must not hold the appops lock
-        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
-                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
-                filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
-                callback).recycleOnUse());
+        mAppOpsService.getHistoricalOpsFromDiskRaw(uid, packageName, attributionTag,
+                opNames, dataType, filter, beginTimeMillis, endTimeMillis, flags, callback);
     }
 
     @Override
     public void reloadNonHistoricalState() {
-        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
-                Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
-        writeState();
-        readState();
+        mAppOpsService.reloadNonHistoricalState();
     }
 
     @Override
     public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
-        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
-        synchronized (this) {
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
-            if (resOps == null) {
-                return null;
-            }
-            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
-            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
-                    null, uidState.uid, resOps);
-            res.add(resPackage);
-            return res;
-        }
-    }
-
-    private void pruneOpLocked(Op op, int uid, String packageName) {
-        op.removeAttributionsWithNoTime();
-
-        if (op.mAttributions.isEmpty()) {
-            Ops ops = getOpsLocked(uid, packageName, null, false, null, /* edit */ false);
-            if (ops != null) {
-                ops.remove(op.op);
-                op.setMode(AppOpsManager.opToDefaultMode(op.op));
-                if (ops.size() <= 0) {
-                    UidState uidState = ops.uidState;
-                    ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
-                    if (pkgOps != null) {
-                        pkgOps.remove(ops.packageName);
-                        mAppOpsServiceInterface.removePackage(ops.packageName,
-                                UserHandle.getUserId(uidState.uid));
-                        if (pkgOps.isEmpty()) {
-                            uidState.pkgOps = null;
-                        }
-                        if (uidState.isDefault()) {
-                            uidState.clear();
-                            mUidStates.remove(uid);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    private void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
-        if (callingPid == Process.myPid()) {
-            return;
-        }
-        final int callingUser = UserHandle.getUserId(callingUid);
-        synchronized (this) {
-            if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
-                if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
-                    // Profile owners are allowed to change modes but only for apps
-                    // within their user.
-                    return;
-                }
-            }
-        }
-        mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
-                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        return mAppOpsService.getUidOps(uid, ops);
     }
 
     @Override
     public void setUidMode(int code, int uid, int mode) {
-        setUidMode(code, uid, mode, null);
-    }
-
-    private void setUidMode(int code, int uid, int mode,
-            @Nullable IAppOpsCallback permissionPolicyCallback) {
-        if (DEBUG) {
-            Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
-                    + " by uid " + Binder.getCallingUid());
-        }
-
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-        verifyIncomingOp(code);
-        code = AppOpsManager.opToSwitch(code);
-
-        if (permissionPolicyCallback == null) {
-            updatePermissionRevokedCompat(uid, code, mode);
-        }
-
-        int previousMode;
-        synchronized (this) {
-            final int defaultMode = AppOpsManager.opToDefaultMode(code);
-
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState == null) {
-                if (mode == defaultMode) {
-                    return;
-                }
-                uidState = new UidState(uid);
-                mUidStates.put(uid, uidState);
-            }
-            if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) {
-                previousMode = uidState.getUidMode(code);
-            } else {
-                // doesn't look right but is legacy behavior.
-                previousMode = MODE_DEFAULT;
-            }
-
-            if (!uidState.setUidMode(code, mode)) {
-                return;
-            }
-            uidState.evalForegroundOps();
-            if (mode != MODE_ERRORED && mode != previousMode) {
-                updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
-            }
-        }
-
-        notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
-        notifyOpChangedSync(code, uid, null, mode, previousMode);
-    }
-
-    /**
-     * Notify that an op changed for all packages in an uid.
-     *
-     * @param code The op that changed
-     * @param uid The uid the op was changed for
-     * @param onlyForeground Only notify watchers that watch for foreground changes
-     */
-    private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
-            @Nullable IAppOpsCallback callbackToIgnore) {
-        ModeCallback listenerToIgnore = callbackToIgnore != null
-                ? mModeWatchers.get(callbackToIgnore.asBinder()) : null;
-        mAppOpsServiceInterface.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground,
-                listenerToIgnore);
-    }
-
-    private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
-        PackageManager packageManager = mContext.getPackageManager();
-        if (packageManager == null) {
-            // This can only happen during early boot. At this time the permission state and appop
-            // state are in sync
-            return;
-        }
-
-        String[] packageNames = packageManager.getPackagesForUid(uid);
-        if (ArrayUtils.isEmpty(packageNames)) {
-            return;
-        }
-        String packageName = packageNames[0];
-
-        int[] ops = mSwitchedOps.get(switchCode);
-        for (int code : ops) {
-            String permissionName = AppOpsManager.opToPermission(code);
-            if (permissionName == null) {
-                continue;
-            }
-
-            if (packageManager.checkPermission(permissionName, packageName)
-                    != PackageManager.PERMISSION_GRANTED) {
-                continue;
-            }
-
-            PermissionInfo permissionInfo;
-            try {
-                permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
-            } catch (PackageManager.NameNotFoundException e) {
-                e.printStackTrace();
-                continue;
-            }
-
-            if (!permissionInfo.isRuntime()) {
-                continue;
-            }
-
-            boolean supportsRuntimePermissions = getPackageManagerInternal()
-                    .getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M;
-
-            UserHandle user = UserHandle.getUserHandleForUid(uid);
-            boolean isRevokedCompat;
-            if (permissionInfo.backgroundPermission != null) {
-                if (packageManager.checkPermission(permissionInfo.backgroundPermission, packageName)
-                        == PackageManager.PERMISSION_GRANTED) {
-                    boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
-
-                    if (isBackgroundRevokedCompat && supportsRuntimePermissions) {
-                        Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
-                                + " permission state, this is discouraged and you should revoke the"
-                                + " runtime permission instead: uid=" + uid + ", switchCode="
-                                + switchCode + ", mode=" + mode + ", permission="
-                                + permissionInfo.backgroundPermission);
-                    }
-
-                    final long identity = Binder.clearCallingIdentity();
-                    try {
-                        packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
-                                packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
-                                isBackgroundRevokedCompat
-                                        ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
-
-                isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
-                        && mode != AppOpsManager.MODE_FOREGROUND;
-            } else {
-                isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
-            }
-
-            if (isRevokedCompat && supportsRuntimePermissions) {
-                Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
-                        + " permission state, this is discouraged and you should revoke the"
-                        + " runtime permission instead: uid=" + uid + ", switchCode="
-                        + switchCode + ", mode=" + mode + ", permission=" + permissionName);
-            }
-
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                packageManager.updatePermissionFlags(permissionName, packageName,
-                        PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
-                                ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode,
-            int previousMode) {
-        final StorageManagerInternal storageManagerInternal =
-                LocalServices.getService(StorageManagerInternal.class);
-        if (storageManagerInternal != null) {
-            storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode, previousMode);
-        }
+        mAppOpsService.setUidMode(code, uid, mode, null);
     }
 
     /**
@@ -1866,309 +407,12 @@
      */
     @Override
     public void setMode(int code, int uid, @NonNull String packageName, int mode) {
-        setMode(code, uid, packageName, mode, null);
-    }
-
-    private void setMode(int code, int uid, @NonNull String packageName, int mode,
-            @Nullable IAppOpsCallback permissionPolicyCallback) {
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
-        verifyIncomingOp(code);
-        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
-            return;
-        }
-
-        ArraySet<OnOpModeChangedListener> repCbs = null;
-        code = AppOpsManager.opToSwitch(code);
-
-        PackageVerificationResult pvr;
-        try {
-            pvr = verifyAndGetBypass(uid, packageName, null);
-        } catch (SecurityException e) {
-            Slog.e(TAG, "Cannot setMode", e);
-            return;
-        }
-
-        int previousMode = MODE_DEFAULT;
-        synchronized (this) {
-            UidState uidState = getUidStateLocked(uid, false);
-            Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true);
-            if (op != null) {
-                if (op.getMode() != mode) {
-                    previousMode = op.getMode();
-                    op.setMode(mode);
-
-                    if (uidState != null) {
-                        uidState.evalForegroundOps();
-                    }
-                    ArraySet<OnOpModeChangedListener> cbs =
-                            mAppOpsServiceInterface.getOpModeChangedListeners(code);
-                    if (cbs != null) {
-                        if (repCbs == null) {
-                            repCbs = new ArraySet<>();
-                        }
-                        repCbs.addAll(cbs);
-                    }
-                    cbs = mAppOpsServiceInterface.getPackageModeChangedListeners(packageName);
-                    if (cbs != null) {
-                        if (repCbs == null) {
-                            repCbs = new ArraySet<>();
-                        }
-                        repCbs.addAll(cbs);
-                    }
-                    if (repCbs != null && permissionPolicyCallback != null) {
-                        repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder()));
-                    }
-                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
-                        // If going into the default mode, prune this op
-                        // if there is nothing else interesting in it.
-                        pruneOpLocked(op, uid, packageName);
-                    }
-                    scheduleFastWriteLocked();
-                    if (mode != MODE_ERRORED) {
-                        updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
-                    }
-                }
-            }
-        }
-        if (repCbs != null) {
-            mHandler.sendMessage(PooledLambda.obtainMessage(
-                    AppOpsService::notifyOpChanged,
-                    this, repCbs, code, uid, packageName));
-        }
-
-        notifyOpChangedSync(code, uid, packageName, mode, previousMode);
-    }
-
-    private void notifyOpChanged(ArraySet<OnOpModeChangedListener> callbacks, int code,
-            int uid, String packageName) {
-        for (int i = 0; i < callbacks.size(); i++) {
-            final OnOpModeChangedListener callback = callbacks.valueAt(i);
-            notifyOpChanged(callback, code, uid, packageName);
-        }
-    }
-
-    private void notifyOpChanged(OnOpModeChangedListener callback, int code,
-            int uid, String packageName) {
-        mAppOpsServiceInterface.notifyOpChanged(callback, code, uid, packageName);
-    }
-
-    private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
-            int op, int uid, String packageName, int previousMode) {
-        boolean duplicate = false;
-        if (reports == null) {
-            reports = new ArrayList<>();
-        } else {
-            final int reportCount = reports.size();
-            for (int j = 0; j < reportCount; j++) {
-                ChangeRec report = reports.get(j);
-                if (report.op == op && report.pkg.equals(packageName)) {
-                    duplicate = true;
-                    break;
-                }
-            }
-        }
-        if (!duplicate) {
-            reports.add(new ChangeRec(op, uid, packageName, previousMode));
-        }
-
-        return reports;
-    }
-
-    private static HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> addCallbacks(
-            HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks,
-            int op, int uid, String packageName, int previousMode,
-            ArraySet<OnOpModeChangedListener> cbs) {
-        if (cbs == null) {
-            return callbacks;
-        }
-        if (callbacks == null) {
-            callbacks = new HashMap<>();
-        }
-        final int N = cbs.size();
-        for (int i=0; i<N; i++) {
-            OnOpModeChangedListener cb = cbs.valueAt(i);
-            ArrayList<ChangeRec> reports = callbacks.get(cb);
-            ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
-            if (changed != reports) {
-                callbacks.put(cb, changed);
-            }
-        }
-        return callbacks;
-    }
-
-    static final class ChangeRec {
-        final int op;
-        final int uid;
-        final String pkg;
-        final int previous_mode;
-
-        ChangeRec(int _op, int _uid, String _pkg, int _previous_mode) {
-            op = _op;
-            uid = _uid;
-            pkg = _pkg;
-            previous_mode = _previous_mode;
-        }
+        mAppOpsService.setMode(code, uid, packageName, mode, null);
     }
 
     @Override
     public void resetAllModes(int reqUserId, String reqPackageName) {
-        final int callingPid = Binder.getCallingPid();
-        final int callingUid = Binder.getCallingUid();
-        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
-                true, true, "resetAllModes", null);
-
-        int reqUid = -1;
-        if (reqPackageName != null) {
-            try {
-                reqUid = AppGlobals.getPackageManager().getPackageUid(
-                        reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
-            } catch (RemoteException e) {
-                /* ignore - local call */
-            }
-        }
-
-        enforceManageAppOpsModes(callingPid, callingUid, reqUid);
-
-        HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks = null;
-        ArrayList<ChangeRec> allChanges = new ArrayList<>();
-        synchronized (this) {
-            boolean changed = false;
-            for (int i = mUidStates.size() - 1; i >= 0; i--) {
-                UidState uidState = mUidStates.valueAt(i);
-
-                SparseIntArray opModes = uidState.getNonDefaultUidModes();
-                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
-                    final int uidOpCount = opModes.size();
-                    for (int j = uidOpCount - 1; j >= 0; j--) {
-                        final int code = opModes.keyAt(j);
-                        if (AppOpsManager.opAllowsReset(code)) {
-                            int previousMode = opModes.valueAt(j);
-                            uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code));
-                            for (String packageName : getPackagesForUid(uidState.uid)) {
-                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        previousMode,
-                                        mAppOpsServiceInterface.getOpModeChangedListeners(code));
-                                callbacks = addCallbacks(callbacks, code, uidState.uid, packageName,
-                                        previousMode, mAppOpsServiceInterface
-                                                .getPackageModeChangedListeners(packageName));
-
-                                allChanges = addChange(allChanges, code, uidState.uid,
-                                        packageName, previousMode);
-                            }
-                        }
-                    }
-                }
-
-                if (uidState.pkgOps == null) {
-                    continue;
-                }
-
-                if (reqUserId != UserHandle.USER_ALL
-                        && reqUserId != UserHandle.getUserId(uidState.uid)) {
-                    // Skip any ops for a different user
-                    continue;
-                }
-
-                Map<String, Ops> packages = uidState.pkgOps;
-                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
-                boolean uidChanged = false;
-                while (it.hasNext()) {
-                    Map.Entry<String, Ops> ent = it.next();
-                    String packageName = ent.getKey();
-                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
-                        // Skip any ops for a different package
-                        continue;
-                    }
-                    Ops pkgOps = ent.getValue();
-                    for (int j=pkgOps.size()-1; j>=0; j--) {
-                        Op curOp = pkgOps.valueAt(j);
-                        if (shouldDeferResetOpToDpm(curOp.op)) {
-                            deferResetOpToDpm(curOp.op, reqPackageName, reqUserId);
-                            continue;
-                        }
-                        if (AppOpsManager.opAllowsReset(curOp.op)
-                                && curOp.getMode() != AppOpsManager.opToDefaultMode(curOp.op)) {
-                            int previousMode = curOp.getMode();
-                            curOp.setMode(AppOpsManager.opToDefaultMode(curOp.op));
-                            changed = true;
-                            uidChanged = true;
-                            final int uid = curOp.uidState.uid;
-                            callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
-                                    previousMode,
-                                    mAppOpsServiceInterface.getOpModeChangedListeners(curOp.op));
-                            callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
-                                    previousMode, mAppOpsServiceInterface
-                                            .getPackageModeChangedListeners(packageName));
-
-                            allChanges = addChange(allChanges, curOp.op, uid, packageName,
-                                    previousMode);
-                            curOp.removeAttributionsWithNoTime();
-                            if (curOp.mAttributions.isEmpty()) {
-                                pkgOps.removeAt(j);
-                            }
-                        }
-                    }
-                    if (pkgOps.size() == 0) {
-                        it.remove();
-                        mAppOpsServiceInterface.removePackage(packageName,
-                                UserHandle.getUserId(uidState.uid));
-                    }
-                }
-                if (uidState.isDefault()) {
-                    uidState.clear();
-                    mUidStates.remove(uidState.uid);
-                }
-                if (uidChanged) {
-                    uidState.evalForegroundOps();
-                }
-            }
-
-            if (changed) {
-                scheduleFastWriteLocked();
-            }
-        }
-        if (callbacks != null) {
-            for (Map.Entry<OnOpModeChangedListener, ArrayList<ChangeRec>> ent
-                    : callbacks.entrySet()) {
-                OnOpModeChangedListener cb = ent.getKey();
-                ArrayList<ChangeRec> reports = ent.getValue();
-                for (int i=0; i<reports.size(); i++) {
-                    ChangeRec rep = reports.get(i);
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::notifyOpChanged,
-                            this, cb, rep.op, rep.uid, rep.pkg));
-                }
-            }
-        }
-
-        int numChanges = allChanges.size();
-        for (int i = 0; i < numChanges; i++) {
-            ChangeRec change = allChanges.get(i);
-            notifyOpChangedSync(change.op, change.uid, change.pkg,
-                    AppOpsManager.opToDefaultMode(change.op), change.previous_mode);
-        }
-    }
-
-    private boolean shouldDeferResetOpToDpm(int op) {
-        // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
-        //  pre-grants to a role-based mechanism or another general-purpose mechanism.
-        return dpmi != null && dpmi.supportsResetOp(op);
-    }
-
-    /** Assumes {@link #shouldDeferResetOpToDpm(int)} is true. */
-    private void deferResetOpToDpm(int op, String packageName, @UserIdInt int userId) {
-        // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
-        //  pre-grants to a role-based mechanism or another general-purpose mechanism.
-        dpmi.resetOp(op, packageName, userId);
-    }
-
-    private void evalAllForegroundOpsLocked() {
-        for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
-            final UidState uidState = mUidStates.valueAt(uidi);
-            if (uidState.foregroundOps != null) {
-                uidState.evalForegroundOps();
-            }
-        }
+        mAppOpsService.resetAllModes(reqUserId, reqPackageName);
     }
 
     @Override
@@ -2179,66 +423,17 @@
     @Override
     public void startWatchingModeWithFlags(int op, String packageName, int flags,
             IAppOpsCallback callback) {
-        int watchedUid = -1;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        // TODO: should have a privileged permission to protect this.
-        // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
-        // the USAGE_STATS permission since this can provide information about when an
-        // app is in the foreground?
-        Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
-                AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
-        if (callback == null) {
-            return;
-        }
-        final boolean mayWatchPackageName = packageName != null
-                && !filterAppAccessUnlocked(packageName, UserHandle.getUserId(callingUid));
-        synchronized (this) {
-            int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
-
-            int notifiedOps;
-            if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
-                if (op == OP_NONE) {
-                    notifiedOps = ALL_OPS;
-                } else {
-                    notifiedOps = op;
-                }
-            } else {
-                notifiedOps = switchOp;
-            }
-
-            ModeCallback cb = mModeWatchers.get(callback.asBinder());
-            if (cb == null) {
-                cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid,
-                        callingPid);
-                mModeWatchers.put(callback.asBinder(), cb);
-            }
-            if (switchOp != AppOpsManager.OP_NONE) {
-                mAppOpsServiceInterface.startWatchingOpModeChanged(cb, switchOp);
-            }
-            if (mayWatchPackageName) {
-                mAppOpsServiceInterface.startWatchingPackageModeChanged(cb, packageName);
-            }
-            evalAllForegroundOpsLocked();
-        }
+        mAppOpsService.startWatchingModeWithFlags(op, packageName, flags, callback);
     }
 
     @Override
     public void stopWatchingMode(IAppOpsCallback callback) {
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            ModeCallback cb = mModeWatchers.remove(callback.asBinder());
-            if (cb != null) {
-                cb.unlinkToDeath();
-                mAppOpsServiceInterface.removeListener(cb);
-            }
-
-            evalAllForegroundOpsLocked();
-        }
+        mAppOpsService.stopWatchingMode(callback);
     }
 
+    /**
+     * @return the current {@link CheckOpsDelegate}.
+     */
     public CheckOpsDelegate getAppOpsServiceDelegate() {
         synchronized (AppOpsService.this) {
             final CheckOpsDelegateDispatcher dispatcher = mCheckOpsDelegateDispatcher;
@@ -2246,6 +441,9 @@
         }
     }
 
+    /**
+     * Sets the appops {@link CheckOpsDelegate}
+     */
     public void setAppOpsServiceDelegate(CheckOpsDelegate delegate) {
         synchronized (AppOpsService.this) {
             final CheckOpsDelegateDispatcher oldDispatcher = mCheckOpsDelegateDispatcher;
@@ -2269,58 +467,7 @@
 
     private int checkOperationImpl(int code, int uid, String packageName,
             @Nullable String attributionTag, boolean raw) {
-        verifyIncomingOp(code);
-        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
-            return AppOpsManager.opToDefaultMode(code);
-        }
-
-        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag, raw);
-    }
-
-    /**
-     * Get the mode of an app-op.
-     *
-     * @param code The code of the op
-     * @param uid The uid of the package the op belongs to
-     * @param packageName The package the op belongs to
-     * @param raw If the raw state of eval-ed state should be checked.
-     *
-     * @return The mode of the op
-     */
-    private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
-            @Nullable String attributionTag, boolean raw) {
-        PackageVerificationResult pvr;
-        try {
-            pvr = verifyAndGetBypass(uid, packageName, null);
-        } catch (SecurityException e) {
-            Slog.e(TAG, "checkOperation", e);
-            return AppOpsManager.opToDefaultMode(code);
-        }
-
-        if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
-            return AppOpsManager.MODE_IGNORED;
-        }
-        synchronized (this) {
-            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, true)) {
-                return AppOpsManager.MODE_IGNORED;
-            }
-            code = AppOpsManager.opToSwitch(code);
-            UidState uidState = getUidStateLocked(uid, false);
-            if (uidState != null
-                    && uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) {
-                final int rawMode = uidState.getUidMode(code);
-                return raw ? rawMode : uidState.evalMode(code, rawMode);
-            }
-            Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false);
-            if (op == null) {
-                return AppOpsManager.opToDefaultMode(code);
-            }
-            return raw ? op.getMode() : op.uidState.evalMode(op.op, op.getMode());
-        }
+        return mAppOpsService.checkOperation(code, uid, packageName, attributionTag, raw);
     }
 
     @Override
@@ -2340,7 +487,8 @@
     @Override
     public void setAudioRestriction(int code, int usage, int uid, int mode,
             String[] exceptionPackages) {
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        mAppOpsService.enforceManageAppOpsModes(Binder.getCallingPid(),
+                Binder.getCallingUid(), uid);
         verifyIncomingUid(uid);
         verifyIncomingOp(code);
 
@@ -2348,58 +496,35 @@
                 code, usage, uid, mode, exceptionPackages);
 
         mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
+                AppOpsServiceInterface::notifyWatchersOfChange, mAppOpsService, code,
+                UID_ANY));
     }
 
 
     @Override
     public void setCameraAudioRestriction(@CAMERA_AUDIO_RESTRICTION int mode) {
-        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), -1);
+        mAppOpsService.enforceManageAppOpsModes(Binder.getCallingPid(),
+                Binder.getCallingUid(), -1);
 
         mAudioRestrictionManager.setCameraAudioRestriction(mode);
 
         mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyWatchersOfChange, this,
+                AppOpsServiceInterface::notifyWatchersOfChange, mAppOpsService,
                 AppOpsManager.OP_PLAY_AUDIO, UID_ANY));
         mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyWatchersOfChange, this,
+                AppOpsServiceInterface::notifyWatchersOfChange, mAppOpsService,
                 AppOpsManager.OP_VIBRATE, UID_ANY));
     }
 
     @Override
     public int checkPackage(int uid, String packageName) {
-        Objects.requireNonNull(packageName);
-        try {
-            verifyAndGetBypass(uid, packageName, null);
-            // When the caller is the system, it's possible that the packageName is the special
-            // one (e.g., "root") which isn't actually existed.
-            if (resolveUid(packageName) == uid
-                    || (isPackageExisted(packageName)
-                            && !filterAppAccessUnlocked(packageName, UserHandle.getUserId(uid)))) {
-                return AppOpsManager.MODE_ALLOWED;
-            }
-            return AppOpsManager.MODE_ERRORED;
-        } catch (SecurityException ignored) {
-            return AppOpsManager.MODE_ERRORED;
-        }
+        return mAppOpsService.checkPackage(uid, packageName);
     }
 
     private boolean isPackageExisted(String packageName) {
         return getPackageManagerInternal().getPackageStateInternal(packageName) != null;
     }
 
-    /**
-     * This method will check with PackageManager to determine if the package provided should
-     * be visible to the {@link Binder#getCallingUid()}.
-     *
-     * NOTE: This must not be called while synchronized on {@code this} to avoid dead locks
-     */
-    private boolean filterAppAccessUnlocked(String packageName, int userId) {
-        final int callingUid = Binder.getCallingUid();
-        return LocalServices.getService(PackageManagerInternal.class)
-                .filterAppAccess(packageName, callingUid, userId);
-    }
-
     @Override
     public SyncNotedAppOp noteProxyOperation(int code, AttributionSource attributionSource,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
@@ -2445,13 +570,20 @@
             final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
                     : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
 
-            final SyncNotedAppOp proxyReturn = noteOperationUnchecked(code, proxyUid,
+            final int proxyReturn = mAppOpsService.noteOperationUnchecked(code, proxyUid,
                     resolveProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
-                    proxyFlags, !isProxyTrusted, "proxy " + message, shouldCollectMessage);
-            if (proxyReturn.getOpMode() != AppOpsManager.MODE_ALLOWED) {
-                return new SyncNotedAppOp(proxyReturn.getOpMode(), code, proxiedAttributionTag,
+                    proxyFlags);
+            if (proxyReturn != AppOpsManager.MODE_ALLOWED) {
+                return new SyncNotedAppOp(proxyReturn, code, proxiedAttributionTag,
                         proxiedPackageName);
             }
+            if (shouldCollectAsyncNotedOp) {
+                boolean isProxyAttributionTagValid = mAppOpsService.isAttributionTagValid(proxyUid,
+                        resolveProxyPackageName, proxyAttributionTag, null);
+                collectAsyncNotedOp(proxyUid, resolveProxyPackageName, code,
+                        isProxyAttributionTagValid ? proxyAttributionTag : null, proxyFlags,
+                        message, shouldCollectMessage);
+            }
         }
 
         String resolveProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
@@ -2463,9 +595,32 @@
 
         final int proxiedFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXIED
                 : AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED;
-        return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
-                proxiedAttributionTag, proxyUid, resolveProxyPackageName, proxyAttributionTag,
-                proxiedFlags, shouldCollectAsyncNotedOp, message, shouldCollectMessage);
+        final int result = mAppOpsService.noteOperationUnchecked(code, proxiedUid,
+                resolveProxiedPackageName, proxiedAttributionTag, proxyUid, resolveProxyPackageName,
+                proxyAttributionTag, proxiedFlags);
+
+        boolean isProxiedAttributionTagValid = mAppOpsService.isAttributionTagValid(proxiedUid,
+                resolveProxiedPackageName, proxiedAttributionTag, resolveProxyPackageName);
+        if (shouldCollectAsyncNotedOp && result == AppOpsManager.MODE_ALLOWED) {
+            collectAsyncNotedOp(proxiedUid, resolveProxiedPackageName, code,
+                    isProxiedAttributionTagValid ? proxiedAttributionTag : null, proxiedFlags,
+                    message, shouldCollectMessage);
+        }
+
+
+        return new SyncNotedAppOp(result, code,
+                isProxiedAttributionTagValid ? proxiedAttributionTag : null,
+                resolveProxiedPackageName);
+    }
+
+    private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
+        if (attributionSource.getUid() != Binder.getCallingUid()
+                && attributionSource.isTrusted(mContext)) {
+            return true;
+        }
+        return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null)
+                == PackageManager.PERMISSION_GRANTED;
     }
 
     @Override
@@ -2479,258 +634,58 @@
     private SyncNotedAppOp noteOperationImpl(int code, int uid, @Nullable String packageName,
             @Nullable String attributionTag, boolean shouldCollectAsyncNotedOp,
             @Nullable String message, boolean shouldCollectMessage) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
         if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
                     packageName);
         }
 
+        int result = mAppOpsService.noteOperation(code, uid, packageName,
+                attributionTag, message);
+
         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
-                    packageName);
-        }
-        return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
-                Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF,
-                shouldCollectAsyncNotedOp, message, shouldCollectMessage);
-    }
 
-    private SyncNotedAppOp noteOperationUnchecked(int code, int uid, @NonNull String packageName,
-            @Nullable String attributionTag, int proxyUid, String proxyPackageName,
-            @Nullable String proxyAttributionTag, @OpFlags int flags,
-            boolean shouldCollectAsyncNotedOp, @Nullable String message,
-            boolean shouldCollectMessage) {
-        PackageVerificationResult pvr;
-        try {
-            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
-            boolean wasNull = attributionTag == null;
-            if (!pvr.isAttributionTagValid) {
-                attributionTag = null;
-            }
-        } catch (SecurityException e) {
-            Slog.e(TAG, "noteOperation", e);
-            return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                    packageName);
+        boolean isAttributionTagValid = mAppOpsService.isAttributionTagValid(uid,
+                    resolvedPackageName, attributionTag, null);
+
+        if (shouldCollectAsyncNotedOp && result == MODE_ALLOWED) {
+            collectAsyncNotedOp(uid, resolvedPackageName, code,
+                    isAttributionTagValid ? attributionTag : null, AppOpsManager.OP_FLAG_SELF,
+                    message, shouldCollectMessage);
         }
 
-        synchronized (this) {
-            final Ops ops = getOpsLocked(uid, packageName, attributionTag,
-                    pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
-            if (ops == null) {
-                scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        AppOpsManager.MODE_IGNORED);
-                if (DEBUG) Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
-                        + " package " + packageName + "flags: " +
-                        AppOpsManager.flagsToString(flags));
-                return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                        packageName);
-            }
-            final Op op = getOpLocked(ops, code, uid, true);
-            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
-            if (attributedOp.isRunning()) {
-                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
-                        + code + " startTime of in progress event="
-                        + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
-            }
-
-            final int switchCode = AppOpsManager.opToSwitch(code);
-            final UidState uidState = ops.uidState;
-            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
-                attributedOp.rejected(uidState.getState(), flags);
-                scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        AppOpsManager.MODE_IGNORED);
-                return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
-                        packageName);
-            }
-            // If there is a non-default per UID policy (we set UID op mode only if
-            // non-default) it takes over, otherwise use the per package policy.
-            if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
-                final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
-                if (uidMode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG) Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    attributedOp.rejected(uidState.getState(), flags);
-                    scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                            uidMode);
-                    return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
-                }
-            } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
-                        : op;
-                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
-                if (mode != AppOpsManager.MODE_ALLOWED) {
-                    if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    attributedOp.rejected(uidState.getState(), flags);
-                    scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                            mode);
-                    return new SyncNotedAppOp(mode, code, attributionTag, packageName);
-                }
-            }
-            if (DEBUG) {
-                Slog.d(TAG,
-                        "noteOperation: allowing code " + code + " uid " + uid + " package "
-                                + packageName + (attributionTag == null ? ""
-                                : "." + attributionTag) + " flags: "
-                                + AppOpsManager.flagsToString(flags));
-            }
-            scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                    AppOpsManager.MODE_ALLOWED);
-            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
-                    uidState.getState(),
-                    flags);
-
-            if (shouldCollectAsyncNotedOp) {
-                collectAsyncNotedOp(uid, packageName, code, attributionTag, flags, message,
-                        shouldCollectMessage);
-            }
-
-            return new SyncNotedAppOp(AppOpsManager.MODE_ALLOWED, code, attributionTag,
-                    packageName);
-        }
+        return new SyncNotedAppOp(result, code, isAttributionTagValid ? attributionTag : null,
+                resolvedPackageName);
     }
 
     // TODO moltmann: Allow watching for attribution ops
     @Override
     public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
-        int watchedUid = Process.INVALID_UID;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
-        if (ops != null) {
-            Preconditions.checkArrayElementsInRange(ops, 0,
-                    AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
-        }
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
-            if (callbacks == null) {
-                callbacks = new SparseArray<>();
-                mActiveWatchers.put(callback.asBinder(), callbacks);
-            }
-            final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
-                    callingUid, callingPid);
-            for (int op : ops) {
-                callbacks.put(op, activeCallback);
-            }
-        }
+        mAppOpsService.startWatchingActive(ops, callback);
     }
 
     @Override
     public void stopWatchingActive(IAppOpsActiveCallback callback) {
-        if (callback == null) {
-            return;
-        }
-        synchronized (this) {
-            final SparseArray<ActiveCallback> activeCallbacks =
-                    mActiveWatchers.remove(callback.asBinder());
-            if (activeCallbacks == null) {
-                return;
-            }
-            final int callbackCount = activeCallbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                activeCallbacks.valueAt(i).destroy();
-            }
-        }
+        mAppOpsService.stopWatchingActive(callback);
     }
 
     @Override
     public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
-        int watchedUid = Process.INVALID_UID;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
-
-        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
-        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
-                "Invalid op code in: " + Arrays.toString(ops));
-        Objects.requireNonNull(callback, "Callback cannot be null");
-
-        synchronized (this) {
-            SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
-            if (callbacks == null) {
-                callbacks = new SparseArray<>();
-                mStartedWatchers.put(callback.asBinder(), callbacks);
-            }
-
-            final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
-                    callingUid, callingPid);
-            for (int op : ops) {
-                callbacks.put(op, startedCallback);
-            }
-        }
+        mAppOpsService.startWatchingStarted(ops, callback);
     }
 
     @Override
     public void stopWatchingStarted(IAppOpsStartedCallback callback) {
-        Objects.requireNonNull(callback, "Callback cannot be null");
-
-        synchronized (this) {
-            final SparseArray<StartedCallback> startedCallbacks =
-                    mStartedWatchers.remove(callback.asBinder());
-            if (startedCallbacks == null) {
-                return;
-            }
-
-            final int callbackCount = startedCallbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                startedCallbacks.valueAt(i).destroy();
-            }
-        }
+        mAppOpsService.stopWatchingStarted(callback);
     }
 
     @Override
     public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
-        int watchedUid = Process.INVALID_UID;
-        final int callingUid = Binder.getCallingUid();
-        final int callingPid = Binder.getCallingPid();
-        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                != PackageManager.PERMISSION_GRANTED) {
-            watchedUid = callingUid;
-        }
-        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
-        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
-                "Invalid op code in: " + Arrays.toString(ops));
-        Objects.requireNonNull(callback, "Callback cannot be null");
-        synchronized (this) {
-            SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
-            if (callbacks == null) {
-                callbacks = new SparseArray<>();
-                mNotedWatchers.put(callback.asBinder(), callbacks);
-            }
-            final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
-                    callingUid, callingPid);
-            for (int op : ops) {
-                callbacks.put(op, notedCallback);
-            }
-        }
+        mAppOpsService.startWatchingNoted(ops, callback);
     }
 
     @Override
     public void stopWatchingNoted(IAppOpsNotedCallback callback) {
-        Objects.requireNonNull(callback, "Callback cannot be null");
-        synchronized (this) {
-            final SparseArray<NotedCallback> notedCallbacks =
-                    mNotedWatchers.remove(callback.asBinder());
-            if (notedCallbacks == null) {
-                return;
-            }
-            final int callbackCount = notedCallbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                notedCallbacks.valueAt(i).destroy();
-            }
-        }
+        mAppOpsService.stopWatchingNoted(callback);
     }
 
     /**
@@ -2817,7 +772,7 @@
         int uid = Binder.getCallingUid();
         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
 
-        verifyAndGetBypass(uid, packageName, null);
+        mAppOpsService.verifyPackage(uid, packageName);
 
         synchronized (this) {
             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2847,7 +802,7 @@
         int uid = Binder.getCallingUid();
         Pair<String, Integer> key = getAsyncNotedOpsKey(packageName, uid);
 
-        verifyAndGetBypass(uid, packageName, null);
+        mAppOpsService.verifyPackage(uid, packageName);
 
         synchronized (this) {
             RemoteCallbackList<IAppOpsAsyncNotedCallback> callbacks = mAsyncOpWatchers.get(key);
@@ -2866,7 +821,7 @@
 
         int uid = Binder.getCallingUid();
 
-        verifyAndGetBypass(uid, packageName, null);
+        mAppOpsService.verifyPackage(uid, packageName);
 
         synchronized (this) {
             return mUnforwardedAsyncNotedOps.remove(getAsyncNotedOpsKey(packageName, uid));
@@ -2889,54 +844,49 @@
             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @NonNull String message,
             boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
             int attributionChainId) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
         if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
             return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
                     packageName);
         }
 
+        int result = mAppOpsService.startOperation(clientId, code, uid, packageName,
+                attributionTag, startIfModeDefault, message,
+                attributionFlags, attributionChainId);
+
         String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return new SyncNotedAppOp(AppOpsManager.MODE_IGNORED, code, attributionTag,
-                    packageName);
+
+        boolean isAttributionTagValid = mAppOpsService.isAttributionTagValid(uid,
+                resolvedPackageName, attributionTag, null);
+
+        if (shouldCollectAsyncNotedOp && result == MODE_ALLOWED) {
+            collectAsyncNotedOp(uid, resolvedPackageName, code,
+                    isAttributionTagValid ? attributionTag : null, AppOpsManager.OP_FLAG_SELF,
+                    message, shouldCollectMessage);
         }
 
-        // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
-        // purposes and not as a check, also make sure that the caller is allowed to access
-        // the data gated by OP_RECORD_AUDIO.
-        //
-        // TODO: Revert this change before Android 12.
-        if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
-            int result = checkOperation(OP_RECORD_AUDIO, uid, packageName);
-            if (result != AppOpsManager.MODE_ALLOWED) {
-                return new SyncNotedAppOp(result, code, attributionTag, packageName);
-            }
-        }
-        return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
-                Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
-                shouldCollectAsyncNotedOp, message, shouldCollectMessage, attributionFlags,
-                attributionChainId, /*dryRun*/ false);
+        return new SyncNotedAppOp(result, code, isAttributionTagValid ? attributionTag : null,
+                resolvedPackageName);
     }
 
     @Override
-    public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
+    public SyncNotedAppOp startProxyOperation(IBinder clientId, int code,
             @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
             boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
             boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
             @AttributionFlags int proxiedAttributionFlags, int attributionChainId) {
-        return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code, attributionSource,
-                startIfModeDefault, shouldCollectAsyncNotedOp, message, shouldCollectMessage,
-                skipProxyOperation, proxyAttributionFlags, proxiedAttributionFlags,
-                attributionChainId);
+        return mCheckOpsDelegateDispatcher.startProxyOperation(clientId, code,
+                attributionSource, startIfModeDefault, shouldCollectAsyncNotedOp, message,
+                shouldCollectMessage, skipProxyOperation, proxyAttributionFlags,
+                proxiedAttributionFlags, attributionChainId);
     }
 
-    private SyncNotedAppOp startProxyOperationImpl(@NonNull IBinder clientId, int code,
+    private SyncNotedAppOp startProxyOperationImpl(IBinder clientId, int code,
             @NonNull AttributionSource attributionSource,
             boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, String message,
             boolean shouldCollectMessage, boolean skipProxyOperation, @AttributionFlags
             int proxyAttributionFlags, @AttributionFlags int proxiedAttributionFlags,
             int attributionChainId) {
+
         final int proxyUid = attributionSource.getUid();
         final String proxyPackageName = attributionSource.getPackageName();
         final String proxyAttributionTag = attributionSource.getAttributionTag();
@@ -2984,147 +934,68 @@
 
         if (!skipProxyOperation) {
             // Test if the proxied operation will succeed before starting the proxy operation
-            final SyncNotedAppOp testProxiedOp = startOperationUnchecked(clientId, code,
+            final int testProxiedOp = mAppOpsService.startOperationUnchecked(clientId, code,
                     proxiedUid, resolvedProxiedPackageName, proxiedAttributionTag, proxyUid,
                     resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault,
-                    shouldCollectAsyncNotedOp, message, shouldCollectMessage,
                     proxiedAttributionFlags, attributionChainId, /*dryRun*/ true);
-            if (!shouldStartForMode(testProxiedOp.getOpMode(), startIfModeDefault)) {
-                return testProxiedOp;
+
+            boolean isTestProxiedAttributionTagValid =
+                    mAppOpsService.isAttributionTagValid(proxiedUid, resolvedProxiedPackageName,
+                            proxiedAttributionTag, resolvedProxyPackageName);
+
+            if (!shouldStartForMode(testProxiedOp, startIfModeDefault)) {
+                return new SyncNotedAppOp(testProxiedOp, code,
+                        isTestProxiedAttributionTagValid ? proxiedAttributionTag : null,
+                        resolvedProxiedPackageName);
             }
 
             final int proxyFlags = isProxyTrusted ? AppOpsManager.OP_FLAG_TRUSTED_PROXY
                     : AppOpsManager.OP_FLAG_UNTRUSTED_PROXY;
 
-            final SyncNotedAppOp proxyAppOp = startOperationUnchecked(clientId, code, proxyUid,
+            final int proxyAppOp = mAppOpsService.startOperationUnchecked(clientId, code, proxyUid,
                     resolvedProxyPackageName, proxyAttributionTag, Process.INVALID_UID, null, null,
-                    proxyFlags, startIfModeDefault, !isProxyTrusted, "proxy " + message,
-                    shouldCollectMessage, proxyAttributionFlags, attributionChainId,
+                    proxyFlags, startIfModeDefault, proxyAttributionFlags, attributionChainId,
                     /*dryRun*/ false);
-            if (!shouldStartForMode(proxyAppOp.getOpMode(), startIfModeDefault)) {
-                return proxyAppOp;
+
+            boolean isProxyAttributionTagValid = mAppOpsService.isAttributionTagValid(proxyUid,
+                    resolvedProxyPackageName, proxyAttributionTag, null);
+
+            if (!shouldStartForMode(proxyAppOp, startIfModeDefault)) {
+                return new SyncNotedAppOp(proxyAppOp, code,
+                        isProxyAttributionTagValid ? proxyAttributionTag : null,
+                        resolvedProxyPackageName);
+            }
+
+            if (shouldCollectAsyncNotedOp) {
+                collectAsyncNotedOp(proxyUid, resolvedProxyPackageName, code,
+                        isProxyAttributionTagValid ? proxyAttributionTag : null, proxyFlags,
+                        message, shouldCollectMessage);
             }
         }
 
-        return startOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
-                proxiedAttributionTag, proxyUid, resolvedProxyPackageName, proxyAttributionTag,
-                proxiedFlags, startIfModeDefault, shouldCollectAsyncNotedOp, message,
-                shouldCollectMessage, proxiedAttributionFlags, attributionChainId,
-                /*dryRun*/ false);
+        final int proxiedAppOp = mAppOpsService.startOperationUnchecked(clientId, code, proxiedUid,
+                resolvedProxiedPackageName, proxiedAttributionTag, proxyUid,
+                resolvedProxyPackageName, proxyAttributionTag, proxiedFlags, startIfModeDefault,
+                proxiedAttributionFlags, attributionChainId,/*dryRun*/ false);
+
+        boolean isProxiedAttributionTagValid = mAppOpsService.isAttributionTagValid(proxiedUid,
+                resolvedProxiedPackageName, proxiedAttributionTag, resolvedProxyPackageName);
+
+        if (shouldCollectAsyncNotedOp && proxiedAppOp == MODE_ALLOWED) {
+            collectAsyncNotedOp(proxyUid, resolvedProxiedPackageName, code,
+                    isProxiedAttributionTagValid ? proxiedAttributionTag : null,
+                    proxiedAttributionFlags, message, shouldCollectMessage);
+        }
+
+        return new SyncNotedAppOp(proxiedAppOp, code,
+                isProxiedAttributionTagValid ? proxiedAttributionTag : null,
+                resolvedProxiedPackageName);
     }
 
     private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
         return (mode == MODE_ALLOWED || (mode == MODE_DEFAULT && startIfModeDefault));
     }
 
-    private SyncNotedAppOp startOperationUnchecked(IBinder clientId, int code, int uid,
-            @NonNull String packageName, @Nullable String attributionTag, int proxyUid,
-            String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
-            boolean startIfModeDefault, boolean shouldCollectAsyncNotedOp, @Nullable String message,
-            boolean shouldCollectMessage, @AttributionFlags int attributionFlags,
-            int attributionChainId, boolean dryRun) {
-        PackageVerificationResult pvr;
-        try {
-            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
-            if (!pvr.isAttributionTagValid) {
-                attributionTag = null;
-            }
-        } catch (SecurityException e) {
-            Slog.e(TAG, "startOperation", e);
-            return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                    packageName);
-        }
-
-        boolean isRestricted = false;
-        int startType = START_TYPE_FAILED;
-        synchronized (this) {
-            final Ops ops = getOpsLocked(uid, packageName, attributionTag,
-                    pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
-            if (ops == null) {
-                if (!dryRun) {
-                    scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                            flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
-                            attributionChainId);
-                }
-                if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
-                        + " package " + packageName + " flags: "
-                        + AppOpsManager.flagsToString(flags));
-                return new SyncNotedAppOp(AppOpsManager.MODE_ERRORED, code, attributionTag,
-                        packageName);
-            }
-            final Op op = getOpLocked(ops, code, uid, true);
-            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
-            final UidState uidState = ops.uidState;
-            isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass,
-                    false);
-            final int switchCode = AppOpsManager.opToSwitch(code);
-            // If there is a non-default per UID policy (we set UID op mode only if
-            // non-default) it takes over, otherwise use the per package policy.
-            if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
-                final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
-                if (!shouldStartForMode(uidMode, startIfModeDefault)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code "
-                                + switchCode + " (" + code + ") uid " + uid + " package "
-                                + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    }
-                    if (!dryRun) {
-                        attributedOp.rejected(uidState.getState(), flags);
-                        scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, uidMode, startType, attributionFlags, attributionChainId);
-                    }
-                    return new SyncNotedAppOp(uidMode, code, attributionTag, packageName);
-                }
-            } else {
-                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
-                        : op;
-                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
-                if (mode != AppOpsManager.MODE_ALLOWED
-                        && (!startIfModeDefault || mode != MODE_DEFAULT)) {
-                    if (DEBUG) Slog.d(TAG, "startOperation: reject #" + mode + " for code "
-                            + switchCode + " (" + code + ") uid " + uid + " package "
-                            + packageName + " flags: " + AppOpsManager.flagsToString(flags));
-                    if (!dryRun) {
-                        attributedOp.rejected(uidState.getState(), flags);
-                        scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
-                                flags, mode, startType, attributionFlags, attributionChainId);
-                    }
-                    return new SyncNotedAppOp(mode, code, attributionTag, packageName);
-                }
-            }
-            if (DEBUG) Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
-                    + " package " + packageName + " restricted: " + isRestricted
-                    + " flags: " + AppOpsManager.flagsToString(flags));
-            if (!dryRun) {
-                try {
-                    if (isRestricted) {
-                        attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
-                                proxyAttributionTag, uidState.getState(), flags,
-                                attributionFlags, attributionChainId);
-                    } else {
-                        attributedOp.started(clientId, proxyUid, proxyPackageName,
-                                proxyAttributionTag, uidState.getState(), flags,
-                                attributionFlags, attributionChainId);
-                        startType = START_TYPE_STARTED;
-                    }
-                } catch (RemoteException e) {
-                    throw new RuntimeException(e);
-                }
-                scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
-                        isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
-                        attributionChainId);
-            }
-        }
-
-        if (shouldCollectAsyncNotedOp && !dryRun && !isRestricted) {
-            collectAsyncNotedOp(uid, packageName, code, attributionTag, AppOpsManager.OP_FLAG_SELF,
-                    message, shouldCollectMessage);
-        }
-
-        return new SyncNotedAppOp(isRestricted ? MODE_IGNORED : MODE_ALLOWED, code, attributionTag,
-                packageName);
-    }
-
     @Override
     public void finishOperation(IBinder clientId, int code, int uid, String packageName,
             String attributionTag) {
@@ -3134,22 +1005,11 @@
 
     private void finishOperationImpl(IBinder clientId, int code, int uid, String packageName,
             String attributionTag) {
-        verifyIncomingUid(uid);
-        verifyIncomingOp(code);
-        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
-            return;
-        }
-
-        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return;
-        }
-
-        finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
+        mAppOpsService.finishOperation(clientId, code, uid, packageName, attributionTag);
     }
 
     @Override
-    public void finishProxyOperation(@NonNull IBinder clientId, int code,
+    public void finishProxyOperation(IBinder clientId, int code,
             @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
         mCheckOpsDelegateDispatcher.finishProxyOperation(clientId, code, attributionSource,
                 skipProxyOperation);
@@ -3181,8 +1041,8 @@
         }
 
         if (!skipProxyOperation) {
-            finishOperationUnchecked(clientId, code, proxyUid, resolvedProxyPackageName,
-                    proxyAttributionTag);
+            mAppOpsService.finishOperationUnchecked(clientId, code, proxyUid,
+                    resolvedProxyPackageName, proxyAttributionTag);
         }
 
         String resolvedProxiedPackageName = AppOpsManager.resolvePackageName(proxiedUid,
@@ -3191,209 +1051,12 @@
             return null;
         }
 
-        finishOperationUnchecked(clientId, code, proxiedUid, resolvedProxiedPackageName,
-                proxiedAttributionTag);
+        mAppOpsService.finishOperationUnchecked(clientId, code, proxiedUid,
+                resolvedProxiedPackageName, proxiedAttributionTag);
 
         return null;
     }
 
-    private void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
-            String attributionTag) {
-        PackageVerificationResult pvr;
-        try {
-            pvr = verifyAndGetBypass(uid, packageName, attributionTag);
-            if (!pvr.isAttributionTagValid) {
-                attributionTag = null;
-            }
-        } catch (SecurityException e) {
-            Slog.e(TAG, "Cannot finishOperation", e);
-            return;
-        }
-
-        synchronized (this) {
-            Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
-                    pvr.bypass, /* edit */ true);
-            if (op == null) {
-                Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
-                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
-                return;
-            }
-            final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
-            if (attributedOp == null) {
-                Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
-                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
-                return;
-            }
-
-            if (attributedOp.isRunning() || attributedOp.isPaused()) {
-                attributedOp.finished(clientId);
-            } else {
-                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
-                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
-            }
-        }
-    }
-
-    void scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull
-            String packageName, @Nullable String attributionTag, boolean active, @AttributionFlags
-            int attributionFlags, int attributionChainId) {
-        ArraySet<ActiveCallback> dispatchedCallbacks = null;
-        final int callbackListCount = mActiveWatchers.size();
-        for (int i = 0; i < callbackListCount; i++) {
-            final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
-            ActiveCallback callback = callbacks.get(code);
-            if (callback != null) {
-                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-                    continue;
-                }
-                if (dispatchedCallbacks == null) {
-                    dispatchedCallbacks = new ArraySet<>();
-                }
-                dispatchedCallbacks.add(callback);
-            }
-        }
-        if (dispatchedCallbacks == null) {
-            return;
-        }
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyOpActiveChanged,
-                this, dispatchedCallbacks, code, uid, packageName, attributionTag, active,
-                attributionFlags, attributionChainId));
-    }
-
-    private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
-            int code, int uid, @NonNull String packageName, @Nullable String attributionTag,
-            boolean active, @AttributionFlags int attributionFlags, int attributionChainId) {
-        // There are features watching for mode changes such as window manager
-        // and location manager which are in our process. The callbacks in these
-        // features may require permissions our remote caller does not have.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int callbackCount = callbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                final ActiveCallback callback = callbacks.valueAt(i);
-                try {
-                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
-                        continue;
-                    }
-                    callback.mCallback.opActiveChanged(code, uid, packageName, attributionTag,
-                            active, attributionFlags, attributionChainId);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
-            String attributionTag, @OpFlags int flags, @Mode int result,
-            @AppOpsManager.OnOpStartedListener.StartedType int startedType,
-            @AttributionFlags int attributionFlags, int attributionChainId) {
-        ArraySet<StartedCallback> dispatchedCallbacks = null;
-        final int callbackListCount = mStartedWatchers.size();
-        for (int i = 0; i < callbackListCount; i++) {
-            final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
-
-            StartedCallback callback = callbacks.get(code);
-            if (callback != null) {
-                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-                    continue;
-                }
-
-                if (dispatchedCallbacks == null) {
-                    dispatchedCallbacks = new ArraySet<>();
-                }
-                dispatchedCallbacks.add(callback);
-            }
-        }
-
-        if (dispatchedCallbacks == null) {
-            return;
-        }
-
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyOpStarted,
-                this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
-                result, startedType, attributionFlags, attributionChainId));
-    }
-
-    private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
-            int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
-            @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
-            @AttributionFlags int attributionFlags, int attributionChainId) {
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int callbackCount = callbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                final StartedCallback callback = callbacks.valueAt(i);
-                try {
-                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
-                        continue;
-                    }
-                    callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
-                            result, startedType, attributionFlags, attributionChainId);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
-    private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
-            String attributionTag, @OpFlags int flags, @Mode int result) {
-        ArraySet<NotedCallback> dispatchedCallbacks = null;
-        final int callbackListCount = mNotedWatchers.size();
-        for (int i = 0; i < callbackListCount; i++) {
-            final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
-            final NotedCallback callback = callbacks.get(code);
-            if (callback != null) {
-                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
-                    continue;
-                }
-                if (dispatchedCallbacks == null) {
-                    dispatchedCallbacks = new ArraySet<>();
-                }
-                dispatchedCallbacks.add(callback);
-            }
-        }
-        if (dispatchedCallbacks == null) {
-            return;
-        }
-        mHandler.sendMessage(PooledLambda.obtainMessage(
-                AppOpsService::notifyOpChecked,
-                this, dispatchedCallbacks, code, uid, packageName, attributionTag, flags,
-                result));
-    }
-
-    private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
-            int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
-            @Mode int result) {
-        // There are features watching for checks in our process. The callbacks in
-        // these features may require permissions our remote caller does not have.
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final int callbackCount = callbacks.size();
-            for (int i = 0; i < callbackCount; i++) {
-                final NotedCallback callback = callbacks.valueAt(i);
-                try {
-                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
-                        continue;
-                    }
-                    callback.mCallback.opNoted(code, uid, packageName, attributionTag, flags,
-                            result);
-                } catch (RemoteException e) {
-                    /* do nothing */
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
-    }
-
     @Override
     public int permissionToOpCode(String permission) {
         if (permission == null) {
@@ -3451,13 +1114,6 @@
                 Binder.getCallingPid(), Binder.getCallingUid(), null);
     }
 
-    private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
-        // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
-        // as watcher should not use this to signal if the value is changed.
-        return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
-                watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
-    }
-
     private void verifyIncomingOp(int op) {
         if (op >= 0 && op < AppOpsManager._NUM_OP) {
             // Enforce manage appops permission if it's a restricted read op.
@@ -3498,35 +1154,6 @@
                 || resolveUid(resolvedPackage) != Process.INVALID_UID;
     }
 
-    private boolean isCallerAndAttributionTrusted(@NonNull AttributionSource attributionSource) {
-        if (attributionSource.getUid() != Binder.getCallingUid()
-                && attributionSource.isTrusted(mContext)) {
-            return true;
-        }
-        return mContext.checkPermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
-                Binder.getCallingPid(), Binder.getCallingUid(), null)
-                == PackageManager.PERMISSION_GRANTED;
-    }
-
-    private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
-        UidState uidState = mUidStates.get(uid);
-        if (uidState == null) {
-            if (!edit) {
-                return null;
-            }
-            uidState = new UidState(uid);
-            mUidStates.put(uid, uidState);
-        }
-
-        return uidState;
-    }
-
-    private void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
-        synchronized (this) {
-            getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible);
-        }
-    }
-
     /**
      * @return {@link PackageManagerInternal}
      */
@@ -3538,764 +1165,6 @@
         return mPackageManagerInternal;
     }
 
-    /**
-     * Create a restriction description matching the properties of the package.
-     *
-     * @param pkg The package to create the restriction description for
-     *
-     * @return The restriction matching the package
-     */
-    private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
-        return new RestrictionBypass(pkg.getUid() == Process.SYSTEM_UID, pkg.isPrivileged(),
-                mContext.checkPermission(android.Manifest.permission
-                        .EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
-                == PackageManager.PERMISSION_GRANTED);
-    }
-
-    /**
-     * @see #verifyAndGetBypass(int, String, String, String)
-     */
-    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
-            @Nullable String attributionTag) {
-        return verifyAndGetBypass(uid, packageName, attributionTag, null);
-    }
-
-    /**
-     * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
-     * description} for the package, along with a boolean indicating whether the attribution tag is
-     * valid.
-     *
-     * @param uid The uid the package belongs to
-     * @param packageName The package the might belong to the uid
-     * @param attributionTag attribution tag or {@code null} if no need to verify
-     * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
-     *
-     * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
-     *         attribution tag is valid
-     */
-    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
-            @Nullable String attributionTag, @Nullable String proxyPackageName) {
-        if (uid == Process.ROOT_UID) {
-            // For backwards compatibility, don't check package name for root UID.
-            return new PackageVerificationResult(null,
-                    /* isAttributionTagValid */ true);
-        }
-        if (Process.isSdkSandboxUid(uid)) {
-            // SDK sandbox processes run in their own UID range, but their associated
-            // UID for checks should always be the UID of the package implementing SDK sandbox
-            // service.
-            // TODO: We will need to modify the callers of this function instead, so
-            // modifications and checks against the app ops state are done with the
-            // correct UID.
-            try {
-                final PackageManager pm = mContext.getPackageManager();
-                final String supplementalPackageName = pm.getSdkSandboxPackageName();
-                if (Objects.equals(packageName, supplementalPackageName)) {
-                    uid = pm.getPackageUidAsUser(supplementalPackageName,
-                            PackageManager.PackageInfoFlags.of(0), UserHandle.getUserId(uid));
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                // Shouldn't happen for the supplemental package
-                e.printStackTrace();
-            }
-        }
-
-
-        // Do not check if uid/packageName/attributionTag is already known.
-        synchronized (this) {
-            UidState uidState = mUidStates.get(uid);
-            if (uidState != null && uidState.pkgOps != null) {
-                Ops ops = uidState.pkgOps.get(packageName);
-
-                if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
-                        attributionTag)) && ops.bypass != null) {
-                    return new PackageVerificationResult(ops.bypass,
-                            ops.validAttributionTags.contains(attributionTag));
-                }
-            }
-        }
-
-        int callingUid = Binder.getCallingUid();
-
-        // Allow any attribution tag for resolvable uids
-        int pkgUid;
-        if (Objects.equals(packageName, "com.android.shell")) {
-            // Special case for the shell which is a package but should be able
-            // to bypass app attribution tag restrictions.
-            pkgUid = Process.SHELL_UID;
-        } else {
-            pkgUid = resolveUid(packageName);
-        }
-        if (pkgUid != Process.INVALID_UID) {
-            if (pkgUid != UserHandle.getAppId(uid)) {
-                Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
-                        + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
-                String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
-                throw new SecurityException("Specified package \"" + packageName + "\" under uid "
-                        +  UserHandle.getAppId(uid) + otherUidMessage);
-            }
-            return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
-                    /* isAttributionTagValid */ true);
-        }
-
-        int userId = UserHandle.getUserId(uid);
-        RestrictionBypass bypass = null;
-        boolean isAttributionTagValid = false;
-
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
-            AndroidPackage pkg = pmInt.getPackage(packageName);
-            if (pkg != null) {
-                isAttributionTagValid = isAttributionInPackage(pkg, attributionTag);
-                pkgUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
-                bypass = getBypassforPackage(pkg);
-            }
-            if (!isAttributionTagValid) {
-                AndroidPackage proxyPkg = proxyPackageName != null
-                        ? pmInt.getPackage(proxyPackageName) : null;
-                // Re-check in proxy.
-                isAttributionTagValid = isAttributionInPackage(proxyPkg, attributionTag);
-                String msg;
-                if (pkg != null && isAttributionTagValid) {
-                    msg = "attributionTag " + attributionTag + " declared in manifest of the proxy"
-                            + " package " + proxyPackageName + ", this is not advised";
-                } else if (pkg != null) {
-                    msg = "attributionTag " + attributionTag + " not declared in manifest of "
-                            + packageName;
-                } else {
-                    msg = "package " + packageName + " not found, can't check for "
-                            + "attributionTag " + attributionTag;
-                }
-
-                try {
-                    if (!mPlatformCompat.isChangeEnabledByPackageName(
-                            SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName,
-                            userId) || !mPlatformCompat.isChangeEnabledByUid(
-                                    SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE,
-                            callingUid)) {
-                        // Do not override tags if overriding is not enabled for this package
-                        isAttributionTagValid = true;
-                    }
-                    Slog.e(TAG, msg);
-                } catch (RemoteException neverHappens) {
-                }
-            }
-        } finally {
-            Binder.restoreCallingIdentity(ident);
-        }
-
-        if (pkgUid != uid) {
-            Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
-                    + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
-            String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
-            throw new SecurityException("Specified package \"" + packageName + "\" under uid " + uid
-                    + otherUidMessage);
-        }
-
-        return new PackageVerificationResult(bypass, isAttributionTagValid);
-    }
-
-    private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
-            @Nullable String attributionTag) {
-        if (pkg == null) {
-            return false;
-        } else if (attributionTag == null) {
-            return true;
-        }
-        if (pkg.getAttributions() != null) {
-            int numAttributions = pkg.getAttributions().size();
-            for (int i = 0; i < numAttributions; i++) {
-                if (pkg.getAttributions().get(i).getTag().equals(attributionTag)) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    /**
-     * Get (and potentially create) ops.
-     *
-     * @param uid The uid the package belongs to
-     * @param packageName The name of the package
-     * @param attributionTag attribution tag
-     * @param isAttributionTagValid whether the given attribution tag is valid
-     * @param bypass When to bypass certain op restrictions (can be null if edit == false)
-     * @param edit If an ops does not exist, create the ops?
-
-     * @return The ops
-     */
-    private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
-            boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit) {
-        UidState uidState = getUidStateLocked(uid, edit);
-        if (uidState == null) {
-            return null;
-        }
-
-        if (uidState.pkgOps == null) {
-            if (!edit) {
-                return null;
-            }
-            uidState.pkgOps = new ArrayMap<>();
-        }
-
-        Ops ops = uidState.pkgOps.get(packageName);
-        if (ops == null) {
-            if (!edit) {
-                return null;
-            }
-            ops = new Ops(packageName, uidState);
-            uidState.pkgOps.put(packageName, ops);
-        }
-
-        if (edit) {
-            if (bypass != null) {
-                ops.bypass = bypass;
-            }
-
-            if (attributionTag != null) {
-                ops.knownAttributionTags.add(attributionTag);
-                if (isAttributionTagValid) {
-                    ops.validAttributionTags.add(attributionTag);
-                } else {
-                    ops.validAttributionTags.remove(attributionTag);
-                }
-            }
-        }
-
-        return ops;
-    }
-
-    @Override
-    public void scheduleWriteLocked() {
-        if (!mWriteScheduled) {
-            mWriteScheduled = true;
-            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
-        }
-    }
-
-    @Override
-    public void scheduleFastWriteLocked() {
-        if (!mFastWriteScheduled) {
-            mWriteScheduled = true;
-            mFastWriteScheduled = true;
-            mHandler.removeCallbacks(mWriteRunner);
-            mHandler.postDelayed(mWriteRunner, 10*1000);
-        }
-    }
-
-    /**
-     * Get the state of an op for a uid.
-     *
-     * @param code The code of the op
-     * @param uid The uid the of the package
-     * @param packageName The package name for which to get the state for
-     * @param attributionTag The attribution tag
-     * @param isAttributionTagValid Whether the given attribution tag is valid
-     * @param bypass When to bypass certain op restrictions (can be null if edit == false)
-     * @param edit Iff {@code true} create the {@link Op} object if not yet created
-     *
-     * @return The {@link Op state} of the op
-     */
-    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
-            @Nullable String attributionTag, boolean isAttributionTagValid,
-            @Nullable RestrictionBypass bypass, boolean edit) {
-        Ops ops = getOpsLocked(uid, packageName, attributionTag, isAttributionTagValid, bypass,
-                edit);
-        if (ops == null) {
-            return null;
-        }
-        return getOpLocked(ops, code, uid, edit);
-    }
-
-    private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
-        Op op = ops.get(code);
-        if (op == null) {
-            if (!edit) {
-                return null;
-            }
-            op = new Op(ops.uidState, ops.packageName, code, uid);
-            ops.put(code, op);
-        }
-        if (edit) {
-            scheduleWriteLocked();
-        }
-        return op;
-    }
-
-    private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
-        if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
-            return false;
-        }
-        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
-        return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
-    }
-
-    private boolean isOpRestrictedLocked(int uid, int code, String packageName,
-            String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp) {
-        int restrictionSetCount = mOpGlobalRestrictions.size();
-
-        for (int i = 0; i < restrictionSetCount; i++) {
-            ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
-            if (restrictionState.hasRestriction(code)) {
-                return true;
-            }
-        }
-
-        int userHandle = UserHandle.getUserId(uid);
-        restrictionSetCount = mOpUserRestrictions.size();
-
-        for (int i = 0; i < restrictionSetCount; i++) {
-            // For each client, check that the given op is not restricted, or that the given
-            // package is exempt from the restriction.
-            ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
-            if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle,
-                    isCheckOp)) {
-                RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
-                if (opBypass != null) {
-                    // If we are the system, bypass user restrictions for certain codes
-                    synchronized (this) {
-                        if (opBypass.isSystemUid && appBypass != null && appBypass.isSystemUid) {
-                            return false;
-                        }
-                        if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
-                            return false;
-                        }
-                        if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
-                                && appBypass.isRecordAudioRestrictionExcept) {
-                            return false;
-                        }
-                    }
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    void readState() {
-        int oldVersion = NO_VERSION;
-        synchronized (mFile) {
-            synchronized (this) {
-                FileInputStream stream;
-                try {
-                    stream = mFile.openRead();
-                } catch (FileNotFoundException e) {
-                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
-                    return;
-                }
-                boolean success = false;
-                mUidStates.clear();
-                mAppOpsServiceInterface.clearAllModes();
-                try {
-                    TypedXmlPullParser parser = Xml.resolvePullParser(stream);
-                    int type;
-                    while ((type = parser.next()) != XmlPullParser.START_TAG
-                            && type != XmlPullParser.END_DOCUMENT) {
-                        ;
-                    }
-
-                    if (type != XmlPullParser.START_TAG) {
-                        throw new IllegalStateException("no start tag found");
-                    }
-
-                    oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
-
-                    int outerDepth = parser.getDepth();
-                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                            continue;
-                        }
-
-                        String tagName = parser.getName();
-                        if (tagName.equals("pkg")) {
-                            readPackage(parser);
-                        } else if (tagName.equals("uid")) {
-                            readUidOps(parser);
-                        } else {
-                            Slog.w(TAG, "Unknown element under <app-ops>: "
-                                    + parser.getName());
-                            XmlUtils.skipCurrentTag(parser);
-                        }
-                    }
-                    success = true;
-                } catch (IllegalStateException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (NullPointerException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (NumberFormatException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (XmlPullParserException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (IOException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } catch (IndexOutOfBoundsException e) {
-                    Slog.w(TAG, "Failed parsing " + e);
-                } finally {
-                    if (!success) {
-                        mUidStates.clear();
-                        mAppOpsServiceInterface.clearAllModes();
-                    }
-                    try {
-                        stream.close();
-                    } catch (IOException e) {
-                    }
-                }
-            }
-        }
-        synchronized (this) {
-            upgradeLocked(oldVersion);
-        }
-    }
-
-    private void upgradeRunAnyInBackgroundLocked() {
-        for (int i = 0; i < mUidStates.size(); i++) {
-            final UidState uidState = mUidStates.valueAt(i);
-            if (uidState == null) {
-                continue;
-            }
-            SparseIntArray opModes = uidState.getNonDefaultUidModes();
-            if (opModes != null) {
-                final int idx = opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
-                if (idx >= 0) {
-                    uidState.setUidMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
-                            opModes.valueAt(idx));
-                }
-            }
-            if (uidState.pkgOps == null) {
-                continue;
-            }
-            boolean changed = false;
-            for (int j = 0; j < uidState.pkgOps.size(); j++) {
-                Ops ops = uidState.pkgOps.valueAt(j);
-                if (ops != null) {
-                    final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
-                    if (op != null && op.getMode() != AppOpsManager.opToDefaultMode(op.op)) {
-                        final Op copy = new Op(op.uidState, op.packageName,
-                                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
-                        copy.setMode(op.getMode());
-                        ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
-                        changed = true;
-                    }
-                }
-            }
-            if (changed) {
-                uidState.evalForegroundOps();
-            }
-        }
-    }
-
-    private void upgradeLocked(int oldVersion) {
-        if (oldVersion >= CURRENT_VERSION) {
-            return;
-        }
-        Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
-        switch (oldVersion) {
-            case NO_VERSION:
-                upgradeRunAnyInBackgroundLocked();
-                // fall through
-            case 1:
-                // for future upgrades
-        }
-        scheduleFastWriteLocked();
-    }
-
-    private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException,
-            XmlPullParserException, IOException {
-        final int uid = parser.getAttributeInt(null, "n");
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("op")) {
-                final int code = parser.getAttributeInt(null, "n");
-                final int mode = parser.getAttributeInt(null, "m");
-                setUidMode(code, uid, mode);
-            } else {
-                Slog.w(TAG, "Unknown element under <uid-ops>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-    }
-
-    private void readPackage(TypedXmlPullParser parser)
-            throws NumberFormatException, XmlPullParserException, IOException {
-        String pkgName = parser.getAttributeValue(null, "n");
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if (tagName.equals("uid")) {
-                readUid(parser, pkgName);
-            } else {
-                Slog.w(TAG, "Unknown element under <pkg>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-    }
-
-    private void readUid(TypedXmlPullParser parser, String pkgName)
-            throws NumberFormatException, XmlPullParserException, IOException {
-        int uid = parser.getAttributeInt(null, "n");
-        final UidState uidState = getUidStateLocked(uid, true);
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            String tagName = parser.getName();
-            if (tagName.equals("op")) {
-                readOp(parser, uidState, pkgName);
-            } else {
-                Slog.w(TAG, "Unknown element under <pkg>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-        uidState.evalForegroundOps();
-    }
-
-    private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
-            @Nullable String attribution)
-            throws NumberFormatException, IOException, XmlPullParserException {
-        final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
-
-        final long key = parser.getAttributeLong(null, "n");
-        final int uidState = extractUidStateFromKey(key);
-        final int opFlags = extractFlagsFromKey(key);
-
-        final long accessTime = parser.getAttributeLong(null, "t", 0);
-        final long rejectTime = parser.getAttributeLong(null, "r", 0);
-        final long accessDuration = parser.getAttributeLong(null, "d", -1);
-        final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
-        final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
-        final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
-
-        if (accessTime > 0) {
-            attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
-                    proxyAttributionTag, uidState, opFlags);
-        }
-        if (rejectTime > 0) {
-            attributedOp.rejected(rejectTime, uidState, opFlags);
-        }
-    }
-
-    private void readOp(TypedXmlPullParser parser,
-            @NonNull UidState uidState, @NonNull String pkgName)
-            throws NumberFormatException, XmlPullParserException, IOException {
-        int opCode = parser.getAttributeInt(null, "n");
-        Op op = new Op(uidState, pkgName, opCode, uidState.uid);
-
-        final int mode = parser.getAttributeInt(null, "m", AppOpsManager.opToDefaultMode(op.op));
-        op.setMode(mode);
-
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
-                continue;
-            }
-            String tagName = parser.getName();
-            if (tagName.equals("st")) {
-                readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
-            } else {
-                Slog.w(TAG, "Unknown element under <op>: "
-                        + parser.getName());
-                XmlUtils.skipCurrentTag(parser);
-            }
-        }
-
-        if (uidState.pkgOps == null) {
-            uidState.pkgOps = new ArrayMap<>();
-        }
-        Ops ops = uidState.pkgOps.get(pkgName);
-        if (ops == null) {
-            ops = new Ops(pkgName, uidState);
-            uidState.pkgOps.put(pkgName, ops);
-        }
-        ops.put(op.op, op);
-    }
-
-    void writeState() {
-        synchronized (mFile) {
-            FileOutputStream stream;
-            try {
-                stream = mFile.startWrite();
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to write state: " + e);
-                return;
-            }
-
-            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
-
-            try {
-                TypedXmlSerializer out = Xml.resolveSerializer(stream);
-                out.startDocument(null, true);
-                out.startTag(null, "app-ops");
-                out.attributeInt(null, "v", CURRENT_VERSION);
-
-                SparseArray<SparseIntArray> uidStatesClone;
-                synchronized (this) {
-                    uidStatesClone = new SparseArray<>(mUidStates.size());
-
-                    final int uidStateCount = mUidStates.size();
-                    for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
-                        UidState uidState = mUidStates.valueAt(uidStateNum);
-                        int uid = mUidStates.keyAt(uidStateNum);
-
-                        SparseIntArray opModes = uidState.getNonDefaultUidModes();
-                        if (opModes != null && opModes.size() > 0) {
-                            uidStatesClone.put(uid, opModes);
-                        }
-                    }
-                }
-
-                final int uidStateCount = uidStatesClone.size();
-                for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
-                    SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
-                    if (opModes != null && opModes.size() > 0) {
-                        out.startTag(null, "uid");
-                        out.attributeInt(null, "n", uidStatesClone.keyAt(uidStateNum));
-                        final int opCount = opModes.size();
-                        for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
-                            final int op = opModes.keyAt(opCountNum);
-                            final int mode = opModes.valueAt(opCountNum);
-                            out.startTag(null, "op");
-                            out.attributeInt(null, "n", op);
-                            out.attributeInt(null, "m", mode);
-                            out.endTag(null, "op");
-                        }
-                        out.endTag(null, "uid");
-                    }
-                }
-
-                if (allOps != null) {
-                    String lastPkg = null;
-                    for (int i=0; i<allOps.size(); i++) {
-                        AppOpsManager.PackageOps pkg = allOps.get(i);
-                        if (!Objects.equals(pkg.getPackageName(), lastPkg)) {
-                            if (lastPkg != null) {
-                                out.endTag(null, "pkg");
-                            }
-                            lastPkg = pkg.getPackageName();
-                            if (lastPkg != null) {
-                                out.startTag(null, "pkg");
-                                out.attribute(null, "n", lastPkg);
-                            }
-                        }
-                        out.startTag(null, "uid");
-                        out.attributeInt(null, "n", pkg.getUid());
-                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
-                        for (int j=0; j<ops.size(); j++) {
-                            AppOpsManager.OpEntry op = ops.get(j);
-                            out.startTag(null, "op");
-                            out.attributeInt(null, "n", op.getOp());
-                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
-                                out.attributeInt(null, "m", op.getMode());
-                            }
-
-                            for (String attributionTag : op.getAttributedOpEntries().keySet()) {
-                                final AttributedOpEntry attribution =
-                                        op.getAttributedOpEntries().get(attributionTag);
-
-                                final ArraySet<Long> keys = attribution.collectKeys();
-
-                                final int keyCount = keys.size();
-                                for (int k = 0; k < keyCount; k++) {
-                                    final long key = keys.valueAt(k);
-
-                                    final int uidState = AppOpsManager.extractUidStateFromKey(key);
-                                    final int flags = AppOpsManager.extractFlagsFromKey(key);
-
-                                    final long accessTime = attribution.getLastAccessTime(uidState,
-                                            uidState, flags);
-                                    final long rejectTime = attribution.getLastRejectTime(uidState,
-                                            uidState, flags);
-                                    final long accessDuration = attribution.getLastDuration(
-                                            uidState, uidState, flags);
-                                    // Proxy information for rejections is not backed up
-                                    final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
-                                            uidState, uidState, flags);
-
-                                    if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
-                                            && proxy == null) {
-                                        continue;
-                                    }
-
-                                    String proxyPkg = null;
-                                    String proxyAttributionTag = null;
-                                    int proxyUid = Process.INVALID_UID;
-                                    if (proxy != null) {
-                                        proxyPkg = proxy.getPackageName();
-                                        proxyAttributionTag = proxy.getAttributionTag();
-                                        proxyUid = proxy.getUid();
-                                    }
-
-                                    out.startTag(null, "st");
-                                    if (attributionTag != null) {
-                                        out.attribute(null, "id", attributionTag);
-                                    }
-                                    out.attributeLong(null, "n", key);
-                                    if (accessTime > 0) {
-                                        out.attributeLong(null, "t", accessTime);
-                                    }
-                                    if (rejectTime > 0) {
-                                        out.attributeLong(null, "r", rejectTime);
-                                    }
-                                    if (accessDuration > 0) {
-                                        out.attributeLong(null, "d", accessDuration);
-                                    }
-                                    if (proxyPkg != null) {
-                                        out.attribute(null, "pp", proxyPkg);
-                                    }
-                                    if (proxyAttributionTag != null) {
-                                        out.attribute(null, "pc", proxyAttributionTag);
-                                    }
-                                    if (proxyUid >= 0) {
-                                        out.attributeInt(null, "pu", proxyUid);
-                                    }
-                                    out.endTag(null, "st");
-                                }
-                            }
-
-                            out.endTag(null, "op");
-                        }
-                        out.endTag(null, "uid");
-                    }
-                    if (lastPkg != null) {
-                        out.endTag(null, "pkg");
-                    }
-                }
-
-                out.endTag(null, "app-ops");
-                out.endDocument();
-                mFile.finishWrite(stream);
-            } catch (IOException e) {
-                Slog.w(TAG, "Failed to write state, restoring backup.", e);
-                mFile.failWrite(stream);
-            }
-        }
-        mHistoricalRegistry.writeAndClearDiscreteHistory();
-    }
-
     static class Shell extends ShellCommand {
         final IAppOpsService mInterface;
         final AppOpsService mInternal;
@@ -4309,7 +1178,6 @@
         int mode;
         int packageUid;
         int nonpackageUid;
-        final static Binder sBinder = new Binder();
         IBinder mToken;
         boolean targetsUid;
 
@@ -4330,7 +1198,7 @@
             dumpCommandHelp(pw);
         }
 
-        static private int strOpToOp(String op, PrintWriter err) {
+        static int strOpToOp(String op, PrintWriter err) {
             try {
                 return AppOpsManager.strOpToOp(op);
             } catch (IllegalArgumentException e) {
@@ -4527,6 +1395,24 @@
         pw.println("              not specified, the current user is assumed.");
     }
 
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mAppOpsService.dump(fd, pw, args);
+
+        pw.println();
+        if (mCheckOpsDelegateDispatcher.mPolicy != null
+                && mCheckOpsDelegateDispatcher.mPolicy instanceof AppOpsPolicy) {
+            AppOpsPolicy policy = (AppOpsPolicy) mCheckOpsDelegateDispatcher.mPolicy;
+            policy.dumpTags(pw);
+        } else {
+            pw.println("  AppOps policy not set.");
+        }
+
+        if (mAudioRestrictionManager.hasActiveRestrictions()) {
+            pw.println();
+            mAudioRestrictionManager.dump(pw);
+        }
+    }
     static int onShellCommand(Shell shell, String cmd) {
         if (cmd == null) {
             return shell.handleDefaultCommands(cmd);
@@ -4730,14 +1616,12 @@
                     return 0;
                 }
                 case "write-settings": {
-                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
+                    shell.mInternal.mAppOpsService
+                            .enforceManageAppOpsModes(Binder.getCallingPid(),
                             Binder.getCallingUid(), -1);
                     final long token = Binder.clearCallingIdentity();
                     try {
-                        synchronized (shell.mInternal) {
-                            shell.mInternal.mHandler.removeCallbacks(shell.mInternal.mWriteRunner);
-                        }
-                        shell.mInternal.writeState();
+                        shell.mInternal.mAppOpsService.writeState();
                         pw.println("Current settings written.");
                     } finally {
                         Binder.restoreCallingIdentity(token);
@@ -4745,11 +1629,12 @@
                     return 0;
                 }
                 case "read-settings": {
-                    shell.mInternal.enforceManageAppOpsModes(Binder.getCallingPid(),
-                            Binder.getCallingUid(), -1);
+                    shell.mInternal.mAppOpsService
+                            .enforceManageAppOpsModes(Binder.getCallingPid(),
+                                    Binder.getCallingUid(), -1);
                     final long token = Binder.clearCallingIdentity();
                     try {
-                        shell.mInternal.readState();
+                        shell.mInternal.mAppOpsService.readState();
                         pw.println("Last settings read.");
                     } finally {
                         Binder.restoreCallingIdentity(token);
@@ -4795,877 +1680,70 @@
         return -1;
     }
 
-    private void dumpHelp(PrintWriter pw) {
-        pw.println("AppOps service (appops) dump options:");
-        pw.println("  -h");
-        pw.println("    Print this help text.");
-        pw.println("  --op [OP]");
-        pw.println("    Limit output to data associated with the given app op code.");
-        pw.println("  --mode [MODE]");
-        pw.println("    Limit output to data associated with the given app op mode.");
-        pw.println("  --package [PACKAGE]");
-        pw.println("    Limit output to data associated with the given package name.");
-        pw.println("  --attributionTag [attributionTag]");
-        pw.println("    Limit output to data associated with the given attribution tag.");
-        pw.println("  --include-discrete [n]");
-        pw.println("    Include discrete ops limited to n per dimension. Use zero for no limit.");
-        pw.println("  --watchers");
-        pw.println("    Only output the watcher sections.");
-        pw.println("  --history");
-        pw.println("    Only output history.");
-        pw.println("  --uid-state-changes");
-        pw.println("    Include logs about uid state changes.");
-    }
-
-    private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
-            @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
-            @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
-        final int numAttributions = op.mAttributions.size();
-        for (int i = 0; i < numAttributions; i++) {
-            if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
-                    op.mAttributions.keyAt(i), filterAttributionTag)) {
-                continue;
-            }
-
-            pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
-            dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
-                    prefix + "  ");
-            pw.print(prefix + "]\n");
-        }
-    }
-
-    private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
-            @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
-            @NonNull Date date, @NonNull String prefix) {
-
-        final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
-                attributionTag).getAttributedOpEntries().get(attributionTag);
-
-        final ArraySet<Long> keys = entry.collectKeys();
-
-        final int keyCount = keys.size();
-        for (int k = 0; k < keyCount; k++) {
-            final long key = keys.valueAt(k);
-
-            final int uidState = AppOpsManager.extractUidStateFromKey(key);
-            final int flags = AppOpsManager.extractFlagsFromKey(key);
-
-            final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
-            final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
-            final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
-            final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
-
-            String proxyPkg = null;
-            String proxyAttributionTag = null;
-            int proxyUid = Process.INVALID_UID;
-            if (proxy != null) {
-                proxyPkg = proxy.getPackageName();
-                proxyAttributionTag = proxy.getAttributionTag();
-                proxyUid = proxy.getUid();
-            }
-
-            if (accessTime > 0) {
-                pw.print(prefix);
-                pw.print("Access: ");
-                pw.print(AppOpsManager.keyToString(key));
-                pw.print(" ");
-                date.setTime(accessTime);
-                pw.print(sdf.format(date));
-                pw.print(" (");
-                TimeUtils.formatDuration(accessTime - now, pw);
-                pw.print(")");
-                if (accessDuration > 0) {
-                    pw.print(" duration=");
-                    TimeUtils.formatDuration(accessDuration, pw);
-                }
-                if (proxyUid >= 0) {
-                    pw.print(" proxy[");
-                    pw.print("uid=");
-                    pw.print(proxyUid);
-                    pw.print(", pkg=");
-                    pw.print(proxyPkg);
-                    pw.print(", attributionTag=");
-                    pw.print(proxyAttributionTag);
-                    pw.print("]");
-                }
-                pw.println();
-            }
-
-            if (rejectTime > 0) {
-                pw.print(prefix);
-                pw.print("Reject: ");
-                pw.print(AppOpsManager.keyToString(key));
-                date.setTime(rejectTime);
-                pw.print(sdf.format(date));
-                pw.print(" (");
-                TimeUtils.formatDuration(rejectTime - now, pw);
-                pw.print(")");
-                if (proxyUid >= 0) {
-                    pw.print(" proxy[");
-                    pw.print("uid=");
-                    pw.print(proxyUid);
-                    pw.print(", pkg=");
-                    pw.print(proxyPkg);
-                    pw.print(", attributionTag=");
-                    pw.print(proxyAttributionTag);
-                    pw.print("]");
-                }
-                pw.println();
-            }
-        }
-
-        final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
-        if (attributedOp.isRunning()) {
-            long earliestElapsedTime = Long.MAX_VALUE;
-            long maxNumStarts = 0;
-            int numInProgressEvents = attributedOp.mInProgressEvents.size();
-            for (int i = 0; i < numInProgressEvents; i++) {
-                AttributedOp.InProgressStartOpEvent event =
-                        attributedOp.mInProgressEvents.valueAt(i);
-
-                earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
-                maxNumStarts = Math.max(maxNumStarts, event.mNumUnfinishedStarts);
-            }
-
-            pw.print(prefix + "Running start at: ");
-            TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
-            pw.println();
-
-            if (maxNumStarts > 1) {
-                pw.print(prefix + "startNesting=");
-                pw.println(maxNumStarts);
-            }
-        }
-    }
-
-    @NeverCompile // Avoid size overhead of debugging code.
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
-
-        int dumpOp = OP_NONE;
-        String dumpPackage = null;
-        String dumpAttributionTag = null;
-        int dumpUid = Process.INVALID_UID;
-        int dumpMode = -1;
-        boolean dumpWatchers = false;
-        // TODO ntmyren: Remove the dumpHistory and dumpFilter
-        boolean dumpHistory = false;
-        boolean includeDiscreteOps = false;
-        boolean dumpUidStateChangeLogs = false;
-        int nDiscreteOps = 10;
-        @HistoricalOpsRequestFilter int dumpFilter = 0;
-        boolean dumpAll = false;
-
-        if (args != null) {
-            for (int i = 0; i < args.length; i++) {
-                String arg = args[i];
-                if ("-h".equals(arg)) {
-                    dumpHelp(pw);
-                    return;
-                } else if ("-a".equals(arg)) {
-                    // dump all data
-                    dumpAll = true;
-                } else if ("--op".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --op option");
-                        return;
-                    }
-                    dumpOp = Shell.strOpToOp(args[i], pw);
-                    dumpFilter |= FILTER_BY_OP_NAMES;
-                    if (dumpOp < 0) {
-                        return;
-                    }
-                } else if ("--package".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --package option");
-                        return;
-                    }
-                    dumpPackage = args[i];
-                    dumpFilter |= FILTER_BY_PACKAGE_NAME;
-                    try {
-                        dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
-                                PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
-                                0);
-                    } catch (RemoteException e) {
-                    }
-                    if (dumpUid < 0) {
-                        pw.println("Unknown package: " + dumpPackage);
-                        return;
-                    }
-                    dumpUid = UserHandle.getAppId(dumpUid);
-                    dumpFilter |= FILTER_BY_UID;
-                } else if ("--attributionTag".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --attributionTag option");
-                        return;
-                    }
-                    dumpAttributionTag = args[i];
-                    dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
-                } else if ("--mode".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --mode option");
-                        return;
-                    }
-                    dumpMode = Shell.strModeToMode(args[i], pw);
-                    if (dumpMode < 0) {
-                        return;
-                    }
-                } else if ("--watchers".equals(arg)) {
-                    dumpWatchers = true;
-                } else if ("--include-discrete".equals(arg)) {
-                    i++;
-                    if (i >= args.length) {
-                        pw.println("No argument for --include-discrete option");
-                        return;
-                    }
-                    try {
-                        nDiscreteOps = Integer.valueOf(args[i]);
-                    } catch (NumberFormatException e) {
-                        pw.println("Wrong parameter: " + args[i]);
-                        return;
-                    }
-                    includeDiscreteOps = true;
-                } else if ("--history".equals(arg)) {
-                    dumpHistory = true;
-                } else if (arg.length() > 0 && arg.charAt(0) == '-') {
-                    pw.println("Unknown option: " + arg);
-                    return;
-                } else if ("--uid-state-changes".equals(arg)) {
-                    dumpUidStateChangeLogs = true;
-                } else {
-                    pw.println("Unknown command: " + arg);
-                    return;
-                }
-            }
-        }
-
-        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
-        final Date date = new Date();
-        synchronized (this) {
-            pw.println("Current AppOps Service state:");
-            if (!dumpHistory && !dumpWatchers) {
-                mConstants.dump(pw);
-            }
-            pw.println();
-            final long now = System.currentTimeMillis();
-            final long nowElapsed = SystemClock.elapsedRealtime();
-            final long nowUptime = SystemClock.uptimeMillis();
-            boolean needSep = false;
-            if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
-                    && !dumpHistory) {
-                pw.println("  Profile owners:");
-                for (int poi = 0; poi < mProfileOwners.size(); poi++) {
-                    pw.print("    User #");
-                    pw.print(mProfileOwners.keyAt(poi));
-                    pw.print(": ");
-                    UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
-                    pw.println();
-                }
-                pw.println();
-            }
-
-            if (!dumpHistory) {
-                needSep |= mAppOpsServiceInterface.dumpListeners(dumpOp, dumpUid, dumpPackage, pw);
-            }
-
-            if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
-                boolean printedHeader = false;
-                for (int i = 0; i < mModeWatchers.size(); i++) {
-                    final ModeCallback cb = mModeWatchers.valueAt(i);
-                    if (dumpPackage != null
-                            && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) {
-                        continue;
-                    }
-                    needSep = true;
-                    if (!printedHeader) {
-                        pw.println("  All op mode watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
-                    pw.print(": "); pw.println(cb);
-                }
-            }
-            if (mActiveWatchers.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
-                    final SparseArray<ActiveCallback> activeWatchers =
-                            mActiveWatchers.valueAt(watcherNum);
-                    if (activeWatchers.size() <= 0) {
-                        continue;
-                    }
-                    final ActiveCallback cb = activeWatchers.valueAt(0);
-                    if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
-                        continue;
-                    }
-                    if (dumpPackage != null
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-                    if (!printedHeader) {
-                        pw.println("  All op active watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(
-                            mActiveWatchers.keyAt(watcherNum))));
-                    pw.println(" ->");
-                    pw.print("        [");
-                    final int opCount = activeWatchers.size();
-                    for (int opNum = 0; opNum < opCount; opNum++) {
-                        if (opNum > 0) {
-                            pw.print(' ');
-                        }
-                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
-                        if (opNum < opCount - 1) {
-                            pw.print(',');
-                        }
-                    }
-                    pw.println("]");
-                    pw.print("        ");
-                    pw.println(cb);
-                }
-            }
-            if (mStartedWatchers.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-
-                final int watchersSize = mStartedWatchers.size();
-                for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
-                    final SparseArray<StartedCallback> startedWatchers =
-                            mStartedWatchers.valueAt(watcherNum);
-                    if (startedWatchers.size() <= 0) {
-                        continue;
-                    }
-
-                    final StartedCallback cb = startedWatchers.valueAt(0);
-                    if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
-                        continue;
-                    }
-
-                    if (dumpPackage != null
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-
-                    if (!printedHeader) {
-                        pw.println("  All op started watchers:");
-                        printedHeader = true;
-                    }
-
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(
-                            mStartedWatchers.keyAt(watcherNum))));
-                    pw.println(" ->");
-
-                    pw.print("        [");
-                    final int opCount = startedWatchers.size();
-                    for (int opNum = 0; opNum < opCount; opNum++) {
-                        if (opNum > 0) {
-                            pw.print(' ');
-                        }
-
-                        pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
-                        if (opNum < opCount - 1) {
-                            pw.print(',');
-                        }
-                    }
-                    pw.println("]");
-
-                    pw.print("        ");
-                    pw.println(cb);
-                }
-            }
-            if (mNotedWatchers.size() > 0 && dumpMode < 0) {
-                needSep = true;
-                boolean printedHeader = false;
-                for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) {
-                    final SparseArray<NotedCallback> notedWatchers =
-                            mNotedWatchers.valueAt(watcherNum);
-                    if (notedWatchers.size() <= 0) {
-                        continue;
-                    }
-                    final NotedCallback cb = notedWatchers.valueAt(0);
-                    if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
-                        continue;
-                    }
-                    if (dumpPackage != null
-                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
-                        continue;
-                    }
-                    if (!printedHeader) {
-                        pw.println("  All op noted watchers:");
-                        printedHeader = true;
-                    }
-                    pw.print("    ");
-                    pw.print(Integer.toHexString(System.identityHashCode(
-                            mNotedWatchers.keyAt(watcherNum))));
-                    pw.println(" ->");
-                    pw.print("        [");
-                    final int opCount = notedWatchers.size();
-                    for (int opNum = 0; opNum < opCount; opNum++) {
-                        if (opNum > 0) {
-                            pw.print(' ');
-                        }
-                        pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum)));
-                        if (opNum < opCount - 1) {
-                            pw.print(',');
-                        }
-                    }
-                    pw.println("]");
-                    pw.print("        ");
-                    pw.println(cb);
-                }
-            }
-            if (mAudioRestrictionManager.hasActiveRestrictions() && dumpOp < 0
-                    && dumpPackage != null && dumpMode < 0 && !dumpWatchers) {
-                needSep = mAudioRestrictionManager.dump(pw) || needSep;
-            }
-            if (needSep) {
-                pw.println();
-            }
-            for (int i=0; i<mUidStates.size(); i++) {
-                UidState uidState = mUidStates.valueAt(i);
-                final SparseIntArray opModes = uidState.getNonDefaultUidModes();
-                final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
-
-                if (dumpWatchers || dumpHistory) {
-                    continue;
-                }
-                if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
-                    boolean hasOp = dumpOp < 0 || (opModes != null
-                            && opModes.indexOfKey(dumpOp) >= 0);
-                    boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
-                    boolean hasMode = dumpMode < 0;
-                    if (!hasMode && opModes != null) {
-                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
-                            if (opModes.valueAt(opi) == dumpMode) {
-                                hasMode = true;
-                            }
-                        }
-                    }
-                    if (pkgOps != null) {
-                        for (int pkgi = 0;
-                                 (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
-                                 pkgi++) {
-                            Ops ops = pkgOps.valueAt(pkgi);
-                            if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
-                                hasOp = true;
-                            }
-                            if (!hasMode) {
-                                for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
-                                    if (ops.valueAt(opi).getMode() == dumpMode) {
-                                        hasMode = true;
-                                    }
-                                }
-                            }
-                            if (!hasPackage && dumpPackage.equals(ops.packageName)) {
-                                hasPackage = true;
-                            }
-                        }
-                    }
-                    if (uidState.foregroundOps != null && !hasOp) {
-                        if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
-                            hasOp = true;
-                        }
-                    }
-                    if (!hasOp || !hasPackage || !hasMode) {
-                        continue;
-                    }
-                }
-
-                pw.print("  Uid "); UserHandle.formatUid(pw, uidState.uid); pw.println(":");
-                uidState.dump(pw, nowElapsed);
-                if (uidState.foregroundOps != null && (dumpMode < 0
-                        || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
-                    pw.println("    foregroundOps:");
-                    for (int j = 0; j < uidState.foregroundOps.size(); j++) {
-                        if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
-                            continue;
-                        }
-                        pw.print("      ");
-                        pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
-                        pw.print(": ");
-                        pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
-                    }
-                    pw.print("    hasForegroundWatchers=");
-                    pw.println(uidState.hasForegroundWatchers);
-                }
-                needSep = true;
-
-                if (opModes != null) {
-                    final int opModeCount = opModes.size();
-                    for (int j = 0; j < opModeCount; j++) {
-                        final int code = opModes.keyAt(j);
-                        final int mode = opModes.valueAt(j);
-                        if (dumpOp >= 0 && dumpOp != code) {
-                            continue;
-                        }
-                        if (dumpMode >= 0 && dumpMode != mode) {
-                            continue;
-                        }
-                        pw.print("      "); pw.print(AppOpsManager.opToName(code));
-                        pw.print(": mode="); pw.println(AppOpsManager.modeToName(mode));
-                    }
-                }
-
-                if (pkgOps == null) {
-                    continue;
-                }
-
-                for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
-                    final Ops ops = pkgOps.valueAt(pkgi);
-                    if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
-                        continue;
-                    }
-                    boolean printedPackage = false;
-                    for (int j=0; j<ops.size(); j++) {
-                        final Op op = ops.valueAt(j);
-                        final int opCode = op.op;
-                        if (dumpOp >= 0 && dumpOp != opCode) {
-                            continue;
-                        }
-                        if (dumpMode >= 0 && dumpMode != op.getMode()) {
-                            continue;
-                        }
-                        if (!printedPackage) {
-                            pw.print("    Package "); pw.print(ops.packageName); pw.println(":");
-                            printedPackage = true;
-                        }
-                        pw.print("      "); pw.print(AppOpsManager.opToName(opCode));
-                        pw.print(" ("); pw.print(AppOpsManager.modeToName(op.getMode()));
-                        final int switchOp = AppOpsManager.opToSwitch(opCode);
-                        if (switchOp != opCode) {
-                            pw.print(" / switch ");
-                            pw.print(AppOpsManager.opToName(switchOp));
-                            final Op switchObj = ops.get(switchOp);
-                            int mode = switchObj == null
-                                    ? AppOpsManager.opToDefaultMode(switchOp) : switchObj.getMode();
-                            pw.print("="); pw.print(AppOpsManager.modeToName(mode));
-                        }
-                        pw.println("): ");
-                        dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
-                                sdf, date, "        ");
-                    }
-                }
-            }
-            if (needSep) {
-                pw.println();
-            }
-
-            boolean showUserRestrictions = !(dumpMode < 0 && !dumpWatchers && !dumpHistory);
-            mAppOpsRestrictions.dumpRestrictions(pw, dumpOp, dumpPackage, showUserRestrictions);
-
-            if (!dumpHistory && !dumpWatchers) {
-                pw.println();
-                if (mCheckOpsDelegateDispatcher.mPolicy != null
-                        && mCheckOpsDelegateDispatcher.mPolicy instanceof AppOpsPolicy) {
-                    AppOpsPolicy policy = (AppOpsPolicy) mCheckOpsDelegateDispatcher.mPolicy;
-                    policy.dumpTags(pw);
-                } else {
-                    pw.println("  AppOps policy not set.");
-                }
-            }
-
-            if (dumpAll || dumpUidStateChangeLogs) {
-                pw.println();
-                pw.println("Uid State Changes Event Log:");
-                getUidStateTracker().dumpEvents(pw);
-            }
-        }
-
-        // Must not hold the appops lock
-        if (dumpHistory && !dumpWatchers) {
-            mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
-                    dumpFilter);
-        }
-        if (includeDiscreteOps) {
-            pw.println("Discrete accesses: ");
-            mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
-                    dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
-        }
-    }
-
     @Override
     public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
-        checkSystemUid("setUserRestrictions");
-        Objects.requireNonNull(restrictions);
-        Objects.requireNonNull(token);
-        for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
-            String restriction = AppOpsManager.opToRestriction(i);
-            if (restriction != null) {
-                setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
-                        userHandle, null);
-            }
-        }
+        mAppOpsService.setUserRestrictions(restrictions, token, userHandle);
     }
 
     @Override
     public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
             PackageTagsList excludedPackageTags) {
-        if (Binder.getCallingPid() != Process.myPid()) {
-            mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
-                    Binder.getCallingPid(), Binder.getCallingUid(), null);
-        }
-        if (userHandle != UserHandle.getCallingUserId()) {
-            if (mContext.checkCallingOrSelfPermission(Manifest.permission
-                    .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
-                && mContext.checkCallingOrSelfPermission(Manifest.permission
-                    .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
-                throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
-                        + " INTERACT_ACROSS_USERS to interact cross user ");
-            }
-        }
-        verifyIncomingOp(code);
-        Objects.requireNonNull(token);
-        setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
-    }
-
-    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
-            int userHandle, PackageTagsList excludedPackageTags) {
-        synchronized (AppOpsService.this) {
-            ClientUserRestrictionState restrictionState = mOpUserRestrictions.get(token);
-
-            if (restrictionState == null) {
-                try {
-                    restrictionState = new ClientUserRestrictionState(token);
-                } catch (RemoteException e) {
-                    return;
-                }
-                mOpUserRestrictions.put(token, restrictionState);
-            }
-
-            if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
-                    userHandle)) {
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        AppOpsService::notifyWatchersOfChange, this, code, UID_ANY));
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        AppOpsService::updateStartedOpModeForUser, this, code, restricted,
-                        userHandle));
-            }
-
-            if (restrictionState.isDefault()) {
-                mOpUserRestrictions.remove(token);
-                restrictionState.destroy();
-            }
-        }
-    }
-
-    private void updateStartedOpModeForUser(int code, boolean restricted, int userId) {
-        synchronized (AppOpsService.this) {
-            int numUids = mUidStates.size();
-            for (int uidNum = 0; uidNum < numUids; uidNum++) {
-                int uid = mUidStates.keyAt(uidNum);
-                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(uid) != userId) {
-                    continue;
-                }
-                updateStartedOpModeForUidLocked(code, restricted, uid);
-            }
-        }
-    }
-
-    private void updateStartedOpModeForUidLocked(int code, boolean restricted, int uid) {
-        UidState uidState = mUidStates.get(uid);
-        if (uidState == null || uidState.pkgOps == null) {
-            return;
-        }
-
-        int numPkgOps = uidState.pkgOps.size();
-        for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) {
-            Ops ops = uidState.pkgOps.valueAt(pkgNum);
-            Op op = ops != null ? ops.get(code) : null;
-            if (op == null || (op.getMode() != MODE_ALLOWED && op.getMode() != MODE_FOREGROUND)) {
-                continue;
-            }
-            int numAttrTags = op.mAttributions.size();
-            for (int attrNum = 0; attrNum < numAttrTags; attrNum++) {
-                AttributedOp attrOp = op.mAttributions.valueAt(attrNum);
-                if (restricted && attrOp.isRunning()) {
-                    attrOp.pause();
-                } else if (attrOp.isPaused()) {
-                    attrOp.resume();
-                }
-            }
-        }
-    }
-
-    private void notifyWatchersOfChange(int code, int uid) {
-        final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
-        synchronized (this) {
-            modeChangedListenerSet = mAppOpsServiceInterface.getOpModeChangedListeners(code);
-            if (modeChangedListenerSet == null) {
-                return;
-            }
-        }
-
-        notifyOpChanged(modeChangedListenerSet,  code, uid, null);
+        mAppOpsService.setUserRestriction(code, restricted, token, userHandle,
+                excludedPackageTags);
     }
 
     @Override
     public void removeUser(int userHandle) throws RemoteException {
-        checkSystemUid("removeUser");
-        synchronized (AppOpsService.this) {
-            final int tokenCount = mOpUserRestrictions.size();
-            for (int i = tokenCount - 1; i >= 0; i--) {
-                ClientUserRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
-                opRestrictions.removeUser(userHandle);
-            }
-            removeUidsForUserLocked(userHandle);
-        }
+        mAppOpsService.removeUser(userHandle);
     }
 
     @Override
     public boolean isOperationActive(int code, int uid, String packageName) {
-        if (Binder.getCallingUid() != uid) {
-            if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
-                    != PackageManager.PERMISSION_GRANTED) {
-                return false;
-            }
-        }
-        verifyIncomingOp(code);
-        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
-            return false;
-        }
-
-        final String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
-        if (resolvedPackageName == null) {
-            return false;
-        }
-        // TODO moltmann: Allow to check for attribution op activeness
-        synchronized (AppOpsService.this) {
-            Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null, false);
-            if (pkgOps == null) {
-                return false;
-            }
-
-            Op op = pkgOps.get(code);
-            if (op == null) {
-                return false;
-            }
-
-            return op.isRunning();
-        }
+        return mAppOpsService.isOperationActive(code, uid, packageName);
     }
 
     @Override
     public boolean isProxying(int op, @NonNull String proxyPackageName,
             @NonNull String proxyAttributionTag, int proxiedUid,
             @NonNull String proxiedPackageName) {
-        Objects.requireNonNull(proxyPackageName);
-        Objects.requireNonNull(proxiedPackageName);
-        final long callingUid = Binder.getCallingUid();
-        final long identity = Binder.clearCallingIdentity();
-        try {
-            final List<AppOpsManager.PackageOps> packageOps = getOpsForPackage(proxiedUid,
-                    proxiedPackageName, new int[] {op});
-            if (packageOps == null || packageOps.isEmpty()) {
-                return false;
-            }
-            final List<OpEntry> opEntries = packageOps.get(0).getOps();
-            if (opEntries.isEmpty()) {
-                return false;
-            }
-            final OpEntry opEntry = opEntries.get(0);
-            if (!opEntry.isRunning()) {
-                return false;
-            }
-            final OpEventProxyInfo proxyInfo = opEntry.getLastProxyInfo(
-                    OP_FLAG_TRUSTED_PROXIED | AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED);
-            return proxyInfo != null && callingUid == proxyInfo.getUid()
-                    && proxyPackageName.equals(proxyInfo.getPackageName())
-                    && Objects.equals(proxyAttributionTag, proxyInfo.getAttributionTag());
-        } finally {
-            Binder.restoreCallingIdentity(identity);
-        }
+        return mAppOpsService.isProxying(op, proxyPackageName, proxyAttributionTag,
+                proxiedUid, proxiedPackageName);
     }
 
     @Override
     public void resetPackageOpsNoHistory(@NonNull String packageName) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "resetPackageOpsNoHistory");
-        synchronized (AppOpsService.this) {
-            final int uid = mPackageManagerInternal.getPackageUid(packageName, 0,
-                    UserHandle.getCallingUserId());
-            if (uid == Process.INVALID_UID) {
-                return;
-            }
-            UidState uidState = mUidStates.get(uid);
-            if (uidState == null || uidState.pkgOps == null) {
-                return;
-            }
-            Ops removedOps = uidState.pkgOps.remove(packageName);
-            mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
-            if (removedOps != null) {
-                scheduleFastWriteLocked();
-            }
-        }
+        mAppOpsService.resetPackageOpsNoHistory(packageName);
     }
 
     @Override
     public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
             long baseSnapshotInterval, int compressionStep) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "setHistoryParameters");
-        // Must not hold the appops lock
-        mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+        mAppOpsService.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
     }
 
     @Override
     public void offsetHistory(long offsetMillis) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "offsetHistory");
-        // Must not hold the appops lock
-        mHistoricalRegistry.offsetHistory(offsetMillis);
-        mHistoricalRegistry.offsetDiscreteHistory(offsetMillis);
+        mAppOpsService.offsetHistory(offsetMillis);
     }
 
     @Override
     public void addHistoricalOps(HistoricalOps ops) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "addHistoricalOps");
-        // Must not hold the appops lock
-        mHistoricalRegistry.addHistoricalOps(ops);
+        mAppOpsService.addHistoricalOps(ops);
     }
 
     @Override
     public void resetHistoryParameters() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "resetHistoryParameters");
-        // Must not hold the appops lock
-        mHistoricalRegistry.resetHistoryParameters();
+        mAppOpsService.resetHistoryParameters();
     }
 
     @Override
     public void clearHistory() {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "clearHistory");
-        // Must not hold the appops lock
-        mHistoricalRegistry.clearAllHistory();
+        mAppOpsService.clearHistory();
     }
 
     @Override
     public void rebootHistory(long offlineDurationMillis) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
-                "rebootHistory");
-
-        Preconditions.checkArgument(offlineDurationMillis >= 0);
-
-        // Must not hold the appops lock
-        mHistoricalRegistry.shutdown();
-
-        if (offlineDurationMillis > 0) {
-            SystemClock.sleep(offlineDurationMillis);
-        }
-
-        mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry);
-        mHistoricalRegistry.systemReady(mContext.getContentResolver());
-        mHistoricalRegistry.persistPendingHistory();
+        mAppOpsService.rebootHistory(offlineDurationMillis);
     }
 
     /**
@@ -5920,24 +1998,6 @@
         return false;
     }
 
-    @GuardedBy("this")
-    private void removeUidsForUserLocked(int userHandle) {
-        for (int i = mUidStates.size() - 1; i >= 0; --i) {
-            final int uid = mUidStates.keyAt(i);
-            if (UserHandle.getUserId(uid) == userHandle) {
-                mUidStates.valueAt(i).clear();
-                mUidStates.removeAt(i);
-            }
-        }
-    }
-
-    private void checkSystemUid(String function) {
-        int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID) {
-            throw new SecurityException(function + " must by called by the system");
-        }
-    }
-
     private static int resolveUid(String packageName)  {
         if (packageName == null) {
             return Process.INVALID_UID;
@@ -5958,184 +2018,43 @@
         return Process.INVALID_UID;
     }
 
-    private static String[] getPackagesForUid(int uid) {
-        String[] packageNames = null;
-
-        // Very early during boot the package manager is not yet or not yet fully started. At this
-        // time there are no packages yet.
-        if (AppGlobals.getPackageManager() != null) {
-            try {
-                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
-            } catch (RemoteException e) {
-                /* ignore - local call */
-            }
-        }
-        if (packageNames == null) {
-            return EmptyArray.STRING;
-        }
-        return packageNames;
-    }
-
-    private final class ClientUserRestrictionState implements DeathRecipient {
-        private final IBinder token;
-
-        ClientUserRestrictionState(IBinder token)
-                throws RemoteException {
-            token.linkToDeath(this, 0);
-            this.token = token;
-        }
-
-        public boolean setRestriction(int code, boolean restricted,
-                PackageTagsList excludedPackageTags, int userId) {
-            return mAppOpsRestrictions.setUserRestriction(token, userId, code,
-                    restricted, excludedPackageTags);
-        }
-
-        public boolean hasRestriction(int code, String packageName, String attributionTag,
-                int userId, boolean isCheckOp) {
-            return mAppOpsRestrictions.getUserRestriction(token, userId, code, packageName,
-                    attributionTag, isCheckOp);
-        }
-
-        public void removeUser(int userId) {
-            mAppOpsRestrictions.clearUserRestrictions(token, userId);
-        }
-
-        public boolean isDefault() {
-            return !mAppOpsRestrictions.hasUserRestrictions(token);
-        }
-
-        @Override
-        public void binderDied() {
-            synchronized (AppOpsService.this) {
-                mAppOpsRestrictions.clearUserRestrictions(token);
-                mOpUserRestrictions.remove(token);
-                destroy();
-            }
-        }
-
-        public void destroy() {
-            token.unlinkToDeath(this, 0);
-        }
-    }
-
-    private final class ClientGlobalRestrictionState implements DeathRecipient {
-        final IBinder mToken;
-
-        ClientGlobalRestrictionState(IBinder token)
-                throws RemoteException {
-            token.linkToDeath(this, 0);
-            this.mToken = token;
-        }
-
-        boolean setRestriction(int code, boolean restricted) {
-            return mAppOpsRestrictions.setGlobalRestriction(mToken, code, restricted);
-        }
-
-        boolean hasRestriction(int code) {
-            return mAppOpsRestrictions.getGlobalRestriction(mToken, code);
-        }
-
-        boolean isDefault() {
-            return !mAppOpsRestrictions.hasGlobalRestrictions(mToken);
-        }
-
-        @Override
-        public void binderDied() {
-            mAppOpsRestrictions.clearGlobalRestrictions(mToken);
-            mOpGlobalRestrictions.remove(mToken);
-            destroy();
-        }
-
-        void destroy() {
-            mToken.unlinkToDeath(this, 0);
-        }
-    }
-
     private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
         @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
-            synchronized (AppOpsService.this) {
-                mProfileOwners = owners;
-            }
+            AppOpsService.this.mAppOpsService.setDeviceAndProfileOwners(owners);
         }
 
         @Override
         public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames,
                 boolean visible) {
-            AppOpsService.this.updateAppWidgetVisibility(uidPackageNames, visible);
+            AppOpsService.this.mAppOpsService
+                    .updateAppWidgetVisibility(uidPackageNames, visible);
         }
 
         @Override
         public void setUidModeFromPermissionPolicy(int code, int uid, int mode,
                 @Nullable IAppOpsCallback callback) {
-            setUidMode(code, uid, mode, callback);
+            AppOpsService.this.mAppOpsService.setUidMode(code, uid, mode, callback);
         }
 
         @Override
         public void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName,
                 int mode, @Nullable IAppOpsCallback callback) {
-            setMode(code, uid, packageName, mode, callback);
+            AppOpsService.this.mAppOpsService
+                    .setMode(code, uid, packageName, mode, callback);
         }
 
 
         @Override
         public void setGlobalRestriction(int code, boolean restricted, IBinder token) {
-            if (Binder.getCallingPid() != Process.myPid()) {
-                // TODO instead of this enforcement put in AppOpsManagerInternal
-                throw new SecurityException("Only the system can set global restrictions");
-            }
-
-            synchronized (AppOpsService.this) {
-                ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.get(token);
-
-                if (restrictionState == null) {
-                    try {
-                        restrictionState = new ClientGlobalRestrictionState(token);
-                    } catch (RemoteException  e) {
-                        return;
-                    }
-                    mOpGlobalRestrictions.put(token, restrictionState);
-                }
-
-                if (restrictionState.setRestriction(code, restricted)) {
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::notifyWatchersOfChange, AppOpsService.this, code,
-                            UID_ANY));
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppOpsService::updateStartedOpModeForUser, AppOpsService.this,
-                            code, restricted, UserHandle.USER_ALL));
-                }
-
-                if (restrictionState.isDefault()) {
-                    mOpGlobalRestrictions.remove(token);
-                    restrictionState.destroy();
-                }
-            }
+            AppOpsService.this.mAppOpsService
+                    .setGlobalRestriction(code, restricted, token);
         }
 
         @Override
         public int getOpRestrictionCount(int code, UserHandle user, String pkg,
                 String attributionTag) {
-            int number = 0;
-            synchronized (AppOpsService.this) {
-                int numRestrictions = mOpUserRestrictions.size();
-                for (int i = 0; i < numRestrictions; i++) {
-                    if (mOpUserRestrictions.valueAt(i)
-                            .hasRestriction(code, pkg, attributionTag, user.getIdentifier(),
-                                    false)) {
-                        number++;
-                    }
-                }
-
-                numRestrictions = mOpGlobalRestrictions.size();
-                for (int i = 0; i < numRestrictions; i++) {
-                    if (mOpGlobalRestrictions.valueAt(i).hasRestriction(code)) {
-                        number++;
-                    }
-                }
-            }
-
-            return number;
+            return AppOpsService.this.mAppOpsService
+                    .getOpRestrictionCount(code, user, pkg, attributionTag);
         }
     }
 
@@ -6431,7 +2350,7 @@
                     attributionFlags, attributionChainId, AppOpsService.this::startOperationImpl);
         }
 
-        public SyncNotedAppOp startProxyOperation(@NonNull IBinder clientId, int code,
+        public SyncNotedAppOp startProxyOperation(IBinder clientId, int code,
                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
@@ -6461,7 +2380,7 @@
                     proxyAttributionFlags, proxiedAttributionFlags, attributionChainId);
         }
 
-        private SyncNotedAppOp startDelegateProxyOperationImpl(@NonNull IBinder clientId, int code,
+        private SyncNotedAppOp startDelegateProxyOperationImpl(IBinder clientId, int code,
                 @NonNull AttributionSource attributionSource, boolean startIfModeDefault,
                 boolean shouldCollectAsyncNotedOp, String message, boolean shouldCollectMessage,
                 boolean skipProxyOperation, @AttributionFlags int proxyAttributionFlags,
@@ -6495,7 +2414,7 @@
                     AppOpsService.this::finishOperationImpl);
         }
 
-        public void finishProxyOperation(@NonNull IBinder clientId, int code,
+        public void finishProxyOperation(IBinder clientId, int code,
                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
             if (mPolicy != null) {
                 if (mCheckOpsDelegate != null) {
@@ -6513,7 +2432,7 @@
             }
         }
 
-        private Void finishDelegateProxyOperationImpl(@NonNull IBinder clientId, int code,
+        private Void finishDelegateProxyOperationImpl(IBinder clientId, int code,
                 @NonNull AttributionSource attributionSource, boolean skipProxyOperation) {
             mCheckOpsDelegate.finishProxyOperation(clientId, code, attributionSource,
                     skipProxyOperation, AppOpsService.this::finishProxyOperationImpl);
diff --git a/services/core/java/com/android/server/appop/AppOpsServiceImpl.java b/services/core/java/com/android/server/appop/AppOpsServiceImpl.java
new file mode 100644
index 0000000..70f3bcc
--- /dev/null
+++ b/services/core/java/com/android/server/appop/AppOpsServiceImpl.java
@@ -0,0 +1,4679 @@
+/*
+ * 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.
+ */
+
+package com.android.server.appop;
+
+import static android.app.AppOpsManager.AttributedOpEntry;
+import static android.app.AppOpsManager.AttributionFlags;
+import static android.app.AppOpsManager.CALL_BACK_ON_SWITCHED_OP;
+import static android.app.AppOpsManager.FILTER_BY_ATTRIBUTION_TAG;
+import static android.app.AppOpsManager.FILTER_BY_OP_NAMES;
+import static android.app.AppOpsManager.FILTER_BY_PACKAGE_NAME;
+import static android.app.AppOpsManager.FILTER_BY_UID;
+import static android.app.AppOpsManager.HISTORY_FLAG_GET_ATTRIBUTION_CHAINS;
+import static android.app.AppOpsManager.HistoricalOps;
+import static android.app.AppOpsManager.HistoricalOpsRequestFilter;
+import static android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME;
+import static android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME;
+import static android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
+import static android.app.AppOpsManager.MODE_ERRORED;
+import static android.app.AppOpsManager.MODE_FOREGROUND;
+import static android.app.AppOpsManager.MODE_IGNORED;
+import static android.app.AppOpsManager.Mode;
+import static android.app.AppOpsManager.OP_CAMERA;
+import static android.app.AppOpsManager.OP_FLAGS_ALL;
+import static android.app.AppOpsManager.OP_FLAG_SELF;
+import static android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED;
+import static android.app.AppOpsManager.OP_NONE;
+import static android.app.AppOpsManager.OP_PLAY_AUDIO;
+import static android.app.AppOpsManager.OP_RECEIVE_AMBIENT_TRIGGER_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO;
+import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
+import static android.app.AppOpsManager.OP_VIBRATE;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_FAILED;
+import static android.app.AppOpsManager.OnOpStartedListener.START_TYPE_STARTED;
+import static android.app.AppOpsManager.OpEntry;
+import static android.app.AppOpsManager.OpEventProxyInfo;
+import static android.app.AppOpsManager.OpFlags;
+import static android.app.AppOpsManager.RestrictionBypass;
+import static android.app.AppOpsManager.SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE;
+import static android.app.AppOpsManager._NUM_OP;
+import static android.app.AppOpsManager.extractFlagsFromKey;
+import static android.app.AppOpsManager.extractUidStateFromKey;
+import static android.app.AppOpsManager.modeToName;
+import static android.app.AppOpsManager.opAllowSystemBypassRestriction;
+import static android.app.AppOpsManager.opRestrictsRead;
+import static android.app.AppOpsManager.opToName;
+import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.EXTRA_REPLACING;
+
+import static com.android.server.appop.AppOpsServiceImpl.ModeCallback.ALL_OPS;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
+import android.app.AppGlobals;
+import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.PermissionInfo;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
+import android.os.PackageTagsList;
+import android.os.Process;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.os.storage.StorageManagerInternal;
+import android.permission.PermissionManager;
+import android.provider.Settings;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+import android.util.KeyValueListParser;
+import android.util.Slog;
+import android.util.SparseArray;
+import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.IAppOpsActiveCallback;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsNotedCallback;
+import com.android.internal.app.IAppOpsStartedCallback;
+import com.android.internal.compat.IPlatformCompat;
+import com.android.internal.os.Clock;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
+import com.android.internal.util.XmlUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
+import com.android.modules.utils.TypedXmlPullParser;
+import com.android.modules.utils.TypedXmlSerializer;
+import com.android.server.LocalServices;
+import com.android.server.LockGuard;
+import com.android.server.SystemServerInitThreadPool;
+import com.android.server.pm.pkg.AndroidPackage;
+import com.android.server.pm.pkg.component.ParsedAttribution;
+
+import dalvik.annotation.optimization.NeverCompile;
+
+import libcore.util.EmptyArray;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+class AppOpsServiceImpl implements AppOpsServiceInterface {
+    static final String TAG = "AppOps";
+    static final boolean DEBUG = false;
+
+    private static final int NO_VERSION = -1;
+    /**
+     * Increment by one every time and add the corresponding upgrade logic in
+     * {@link #upgradeLocked(int)} below. The first version was 1
+     */
+    private static final int CURRENT_VERSION = 1;
+
+    // Write at most every 30 minutes.
+    static final long WRITE_DELAY = DEBUG ? 1000 : 30 * 60 * 1000;
+
+    // Constant meaning that any UID should be matched when dispatching callbacks
+    private static final int UID_ANY = -2;
+
+    private static final int[] OPS_RESTRICTED_ON_SUSPEND = {
+            OP_PLAY_AUDIO,
+            OP_RECORD_AUDIO,
+            OP_CAMERA,
+            OP_VIBRATE,
+    };
+    private static final int MAX_UNUSED_POOLED_OBJECTS = 3;
+
+    final Context mContext;
+    final AtomicFile mFile;
+    final Handler mHandler;
+
+    /**
+     * Pool for {@link AttributedOp.OpEventProxyInfoPool} to avoid to constantly reallocate new
+     * objects
+     */
+    @GuardedBy("this")
+    final AttributedOp.OpEventProxyInfoPool mOpEventProxyInfoPool =
+            new AttributedOp.OpEventProxyInfoPool(MAX_UNUSED_POOLED_OBJECTS);
+
+    /**
+     * Pool for {@link AttributedOp.InProgressStartOpEventPool} to avoid to constantly reallocate
+     * new objects
+     */
+    @GuardedBy("this")
+    final AttributedOp.InProgressStartOpEventPool mInProgressStartOpEventPool =
+            new AttributedOp.InProgressStartOpEventPool(mOpEventProxyInfoPool,
+                    MAX_UNUSED_POOLED_OBJECTS);
+    @Nullable
+    private final DevicePolicyManagerInternal dpmi =
+            LocalServices.getService(DevicePolicyManagerInternal.class);
+
+    private final IPlatformCompat mPlatformCompat = IPlatformCompat.Stub.asInterface(
+            ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
+
+    boolean mWriteScheduled;
+    boolean mFastWriteScheduled;
+    final Runnable mWriteRunner = new Runnable() {
+        public void run() {
+            synchronized (AppOpsServiceImpl.this) {
+                mWriteScheduled = false;
+                mFastWriteScheduled = false;
+                AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
+                    @Override
+                    protected Void doInBackground(Void... params) {
+                        writeState();
+                        return null;
+                    }
+                };
+                task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[]) null);
+            }
+        }
+    };
+
+    @GuardedBy("this")
+    @VisibleForTesting
+    final SparseArray<UidState> mUidStates = new SparseArray<>();
+
+    volatile @NonNull HistoricalRegistry mHistoricalRegistry = new HistoricalRegistry(this);
+
+    /*
+     * These are app op restrictions imposed per user from various parties.
+     */
+    private final ArrayMap<IBinder, ClientUserRestrictionState> mOpUserRestrictions =
+            new ArrayMap<>();
+
+    /*
+     * These are app op restrictions imposed globally from various parties within the system.
+     */
+    private final ArrayMap<IBinder, ClientGlobalRestrictionState> mOpGlobalRestrictions =
+            new ArrayMap<>();
+
+    SparseIntArray mProfileOwners;
+
+    /**
+     * Reverse lookup for {@link AppOpsManager#opToSwitch(int)}. Initialized once and never
+     * changed
+     */
+    private final SparseArray<int[]> mSwitchedOps = new SparseArray<>();
+
+    /**
+     * Package Manager internal. Access via {@link #getPackageManagerInternal()}
+     */
+    private @Nullable PackageManagerInternal mPackageManagerInternal;
+
+    /**
+     * Interface for app-op modes.
+     */
+    @VisibleForTesting
+    AppOpsCheckingServiceInterface mAppOpsServiceInterface;
+
+    /**
+     * Interface for app-op restrictions.
+     */
+    @VisibleForTesting
+    AppOpsRestrictions mAppOpsRestrictions;
+
+    private AppOpsUidStateTracker mUidStateTracker;
+
+    /**
+     * Hands the definition of foreground and uid states
+     */
+    @GuardedBy("this")
+    public AppOpsUidStateTracker getUidStateTracker() {
+        if (mUidStateTracker == null) {
+            mUidStateTracker = new AppOpsUidStateTrackerImpl(
+                    LocalServices.getService(ActivityManagerInternal.class),
+                    mHandler,
+                    r -> {
+                        synchronized (AppOpsServiceImpl.this) {
+                            r.run();
+                        }
+                    },
+                    Clock.SYSTEM_CLOCK, mConstants);
+
+            mUidStateTracker.addUidStateChangedCallback(new HandlerExecutor(mHandler),
+                    this::onUidStateChanged);
+        }
+        return mUidStateTracker;
+    }
+
+    /**
+     * All times are in milliseconds. These constants are kept synchronized with the system
+     * global Settings. Any access to this class or its fields should be done while
+     * holding the AppOpsService lock.
+     */
+    final class Constants extends ContentObserver {
+
+        /**
+         * How long we want for a drop in uid state from top to settle before applying it.
+         *
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see AppOpsManager#KEY_TOP_STATE_SETTLE_TIME
+         */
+        public long TOP_STATE_SETTLE_TIME;
+
+        /**
+         * How long we want for a drop in uid state from foreground to settle before applying it.
+         *
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see AppOpsManager#KEY_FG_SERVICE_STATE_SETTLE_TIME
+         */
+        public long FG_SERVICE_STATE_SETTLE_TIME;
+
+        /**
+         * How long we want for a drop in uid state from background to settle before applying it.
+         *
+         * @see Settings.Global#APP_OPS_CONSTANTS
+         * @see AppOpsManager#KEY_BG_STATE_SETTLE_TIME
+         */
+        public long BG_STATE_SETTLE_TIME;
+
+        private final KeyValueListParser mParser = new KeyValueListParser(',');
+        private ContentResolver mResolver;
+
+        Constants(Handler handler) {
+            super(handler);
+            updateConstants();
+        }
+
+        public void startMonitoring(ContentResolver resolver) {
+            mResolver = resolver;
+            mResolver.registerContentObserver(
+                    Settings.Global.getUriFor(Settings.Global.APP_OPS_CONSTANTS),
+                    false, this);
+            updateConstants();
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            updateConstants();
+        }
+
+        private void updateConstants() {
+            String value = mResolver != null ? Settings.Global.getString(mResolver,
+                    Settings.Global.APP_OPS_CONSTANTS) : "";
+
+            synchronized (AppOpsServiceImpl.this) {
+                try {
+                    mParser.setString(value);
+                } catch (IllegalArgumentException e) {
+                    // Failed to parse the settings string, log this and move on
+                    // with defaults.
+                    Slog.e(TAG, "Bad app ops settings", e);
+                }
+                TOP_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_TOP_STATE_SETTLE_TIME, 5 * 1000L);
+                FG_SERVICE_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_FG_SERVICE_STATE_SETTLE_TIME, 5 * 1000L);
+                BG_STATE_SETTLE_TIME = mParser.getDurationMillis(
+                        KEY_BG_STATE_SETTLE_TIME, 1 * 1000L);
+            }
+        }
+
+        void dump(PrintWriter pw) {
+            pw.println("  Settings:");
+
+            pw.print("    ");
+            pw.print(KEY_TOP_STATE_SETTLE_TIME);
+            pw.print("=");
+            TimeUtils.formatDuration(TOP_STATE_SETTLE_TIME, pw);
+            pw.println();
+            pw.print("    ");
+            pw.print(KEY_FG_SERVICE_STATE_SETTLE_TIME);
+            pw.print("=");
+            TimeUtils.formatDuration(FG_SERVICE_STATE_SETTLE_TIME, pw);
+            pw.println();
+            pw.print("    ");
+            pw.print(KEY_BG_STATE_SETTLE_TIME);
+            pw.print("=");
+            TimeUtils.formatDuration(BG_STATE_SETTLE_TIME, pw);
+            pw.println();
+        }
+    }
+
+    @VisibleForTesting
+    final Constants mConstants;
+
+    @VisibleForTesting
+    final class UidState {
+        public final int uid;
+
+        public ArrayMap<String, Ops> pkgOps;
+
+        // true indicates there is an interested observer, false there isn't but it has such an op
+        //TODO: Move foregroundOps and hasForegroundWatchers into the AppOpsServiceInterface.
+        public SparseBooleanArray foregroundOps;
+        public boolean hasForegroundWatchers;
+
+        public UidState(int uid) {
+            this.uid = uid;
+        }
+
+        public void clear() {
+            mAppOpsServiceInterface.removeUid(uid);
+            if (pkgOps != null) {
+                for (String packageName : pkgOps.keySet()) {
+                    mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
+                }
+            }
+            pkgOps = null;
+        }
+
+        public boolean isDefault() {
+            boolean areAllPackageModesDefault = true;
+            if (pkgOps != null) {
+                for (String packageName : pkgOps.keySet()) {
+                    if (!mAppOpsServiceInterface.arePackageModesDefault(packageName,
+                            UserHandle.getUserId(uid))) {
+                        areAllPackageModesDefault = false;
+                        break;
+                    }
+                }
+            }
+            return (pkgOps == null || pkgOps.isEmpty())
+                    && mAppOpsServiceInterface.areUidModesDefault(uid)
+                    && areAllPackageModesDefault;
+        }
+
+        // Functions for uid mode access and manipulation.
+        public SparseIntArray getNonDefaultUidModes() {
+            return mAppOpsServiceInterface.getNonDefaultUidModes(uid);
+        }
+
+        public int getUidMode(int op) {
+            return mAppOpsServiceInterface.getUidMode(uid, op);
+        }
+
+        public boolean setUidMode(int op, int mode) {
+            return mAppOpsServiceInterface.setUidMode(uid, op, mode);
+        }
+
+        @SuppressWarnings("GuardedBy")
+        int evalMode(int op, int mode) {
+            return getUidStateTracker().evalMode(uid, op, mode);
+        }
+
+        public void evalForegroundOps() {
+            foregroundOps = null;
+            foregroundOps = mAppOpsServiceInterface.evalForegroundUidOps(uid, foregroundOps);
+            if (pkgOps != null) {
+                for (int i = pkgOps.size() - 1; i >= 0; i--) {
+                    foregroundOps = mAppOpsServiceInterface
+                            .evalForegroundPackageOps(pkgOps.valueAt(i).packageName,
+                                    foregroundOps,
+                                    UserHandle.getUserId(uid));
+                }
+            }
+            hasForegroundWatchers = false;
+            if (foregroundOps != null) {
+                for (int i = 0; i < foregroundOps.size(); i++) {
+                    if (foregroundOps.valueAt(i)) {
+                        hasForegroundWatchers = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        @SuppressWarnings("GuardedBy")
+        public int getState() {
+            return getUidStateTracker().getUidState(uid);
+        }
+
+        @SuppressWarnings("GuardedBy")
+        public void dump(PrintWriter pw, long nowElapsed) {
+            getUidStateTracker().dumpUidState(pw, uid, nowElapsed);
+        }
+    }
+
+    static final class Ops extends SparseArray<Op> {
+        final String packageName;
+        final UidState uidState;
+
+        /**
+         * The restriction properties of the package. If {@code null} it could not have been read
+         * yet and has to be refreshed.
+         */
+        @Nullable RestrictionBypass bypass;
+
+        /** Lazily populated cache of attributionTags of this package */
+        final @NonNull ArraySet<String> knownAttributionTags = new ArraySet<>();
+
+        /**
+         * Lazily populated cache of <b>valid</b> attributionTags of this package, a set smaller
+         * than or equal to {@link #knownAttributionTags}.
+         */
+        final @NonNull ArraySet<String> validAttributionTags = new ArraySet<>();
+
+        Ops(String _packageName, UidState _uidState) {
+            packageName = _packageName;
+            uidState = _uidState;
+        }
+    }
+
+    /** Returned from {@link #verifyAndGetBypass(int, String, String, String)}. */
+    private static final class PackageVerificationResult {
+
+        final RestrictionBypass bypass;
+        final boolean isAttributionTagValid;
+
+        PackageVerificationResult(RestrictionBypass bypass, boolean isAttributionTagValid) {
+            this.bypass = bypass;
+            this.isAttributionTagValid = isAttributionTagValid;
+        }
+    }
+
+    final class Op {
+        int op;
+        int uid;
+        final UidState uidState;
+        final @NonNull String packageName;
+
+        /** attributionTag -> AttributedOp */
+        final ArrayMap<String, AttributedOp> mAttributions = new ArrayMap<>(1);
+
+        Op(UidState uidState, String packageName, int op, int uid) {
+            this.op = op;
+            this.uid = uid;
+            this.uidState = uidState;
+            this.packageName = packageName;
+        }
+
+        @Mode int getMode() {
+            return mAppOpsServiceInterface.getPackageMode(packageName, this.op,
+                    UserHandle.getUserId(this.uid));
+        }
+
+        void setMode(@Mode int mode) {
+            mAppOpsServiceInterface.setPackageMode(packageName, this.op, mode,
+                    UserHandle.getUserId(this.uid));
+        }
+
+        void removeAttributionsWithNoTime() {
+            for (int i = mAttributions.size() - 1; i >= 0; i--) {
+                if (!mAttributions.valueAt(i).hasAnyTime()) {
+                    mAttributions.removeAt(i);
+                }
+            }
+        }
+
+        private @NonNull AttributedOp getOrCreateAttribution(@NonNull Op parent,
+                @Nullable String attributionTag) {
+            AttributedOp attributedOp;
+
+            attributedOp = mAttributions.get(attributionTag);
+            if (attributedOp == null) {
+                attributedOp = new AttributedOp(AppOpsServiceImpl.this, attributionTag,
+                        parent);
+                mAttributions.put(attributionTag, attributedOp);
+            }
+
+            return attributedOp;
+        }
+
+        @NonNull
+        OpEntry createEntryLocked() {
+            final int numAttributions = mAttributions.size();
+
+            final ArrayMap<String, AppOpsManager.AttributedOpEntry> attributionEntries =
+                    new ArrayMap<>(numAttributions);
+            for (int i = 0; i < numAttributions; i++) {
+                attributionEntries.put(mAttributions.keyAt(i),
+                        mAttributions.valueAt(i).createAttributedOpEntryLocked());
+            }
+
+            return new OpEntry(op, getMode(), attributionEntries);
+        }
+
+        @NonNull
+        OpEntry createSingleAttributionEntryLocked(@Nullable String attributionTag) {
+            final int numAttributions = mAttributions.size();
+
+            final ArrayMap<String, AttributedOpEntry> attributionEntries = new ArrayMap<>(1);
+            for (int i = 0; i < numAttributions; i++) {
+                if (Objects.equals(mAttributions.keyAt(i), attributionTag)) {
+                    attributionEntries.put(mAttributions.keyAt(i),
+                            mAttributions.valueAt(i).createAttributedOpEntryLocked());
+                    break;
+                }
+            }
+
+            return new OpEntry(op, getMode(), attributionEntries);
+        }
+
+        boolean isRunning() {
+            final int numAttributions = mAttributions.size();
+            for (int i = 0; i < numAttributions; i++) {
+                if (mAttributions.valueAt(i).isRunning()) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+    }
+
+    final ArrayMap<IBinder, ModeCallback> mModeWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, SparseArray<ActiveCallback>> mActiveWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, SparseArray<StartedCallback>> mStartedWatchers = new ArrayMap<>();
+    final ArrayMap<IBinder, SparseArray<NotedCallback>> mNotedWatchers = new ArrayMap<>();
+
+    final class ModeCallback extends OnOpModeChangedListener implements DeathRecipient  {
+        /** If mWatchedOpCode==ALL_OPS notify for ops affected by the switch-op */
+        public static final int ALL_OPS = -2;
+
+        // Need to keep this only because stopWatchingMode needs an IAppOpsCallback.
+        // Otherwise we can just use the IBinder object.
+        private final IAppOpsCallback mCallback;
+
+        ModeCallback(IAppOpsCallback callback, int watchingUid, int flags, int watchedOpCode,
+                int callingUid, int callingPid) {
+            super(watchingUid, flags, watchedOpCode, callingUid, callingPid);
+            this.mCallback = callback;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ModeCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, getWatchingUid());
+            sb.append(" flags=0x");
+            sb.append(Integer.toHexString(getFlags()));
+            switch (getWatchedOpCode()) {
+                case OP_NONE:
+                    break;
+                case ALL_OPS:
+                    sb.append(" op=(all)");
+                    break;
+                default:
+                    sb.append(" op=");
+                    sb.append(opToName(getWatchedOpCode()));
+                    break;
+            }
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, getCallingUid());
+            sb.append(" pid=");
+            sb.append(getCallingPid());
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void unlinkToDeath() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingMode(mCallback);
+        }
+
+        @Override
+        public void onOpModeChanged(int op, int uid, String packageName) throws RemoteException {
+            mCallback.opChanged(op, uid, packageName);
+        }
+    }
+
+    final class ActiveCallback implements DeathRecipient {
+        final IAppOpsActiveCallback mCallback;
+        final int mWatchingUid;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        ActiveCallback(IAppOpsActiveCallback callback, int watchingUid, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("ActiveCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void destroy() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingActive(mCallback);
+        }
+    }
+
+    final class StartedCallback implements DeathRecipient {
+        final IAppOpsStartedCallback mCallback;
+        final int mWatchingUid;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        StartedCallback(IAppOpsStartedCallback callback, int watchingUid, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("StartedCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void destroy() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingStarted(mCallback);
+        }
+    }
+
+    final class NotedCallback implements DeathRecipient {
+        final IAppOpsNotedCallback mCallback;
+        final int mWatchingUid;
+        final int mCallingUid;
+        final int mCallingPid;
+
+        NotedCallback(IAppOpsNotedCallback callback, int watchingUid, int callingUid,
+                int callingPid) {
+            mCallback = callback;
+            mWatchingUid = watchingUid;
+            mCallingUid = callingUid;
+            mCallingPid = callingPid;
+            try {
+                mCallback.asBinder().linkToDeath(this, 0);
+            } catch (RemoteException e) {
+                /*ignored*/
+            }
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder(128);
+            sb.append("NotedCallback{");
+            sb.append(Integer.toHexString(System.identityHashCode(this)));
+            sb.append(" watchinguid=");
+            UserHandle.formatUid(sb, mWatchingUid);
+            sb.append(" from uid=");
+            UserHandle.formatUid(sb, mCallingUid);
+            sb.append(" pid=");
+            sb.append(mCallingPid);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        void destroy() {
+            mCallback.asBinder().unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            stopWatchingNoted(mCallback);
+        }
+    }
+
+    /**
+     * Call {@link AttributedOp#onClientDeath attributedOp.onClientDeath(clientId)}.
+     */
+    static void onClientDeath(@NonNull AttributedOp attributedOp,
+            @NonNull IBinder clientId) {
+        attributedOp.onClientDeath(clientId);
+    }
+
+    AppOpsServiceImpl(File storagePath, Handler handler, Context context) {
+        mContext = context;
+
+        for (int switchedCode = 0; switchedCode < _NUM_OP; switchedCode++) {
+            int switchCode = AppOpsManager.opToSwitch(switchedCode);
+            mSwitchedOps.put(switchCode,
+                    ArrayUtils.appendInt(mSwitchedOps.get(switchCode), switchedCode));
+        }
+        mAppOpsServiceInterface =
+                new AppOpsCheckingServiceImpl(this, this, handler, context, mSwitchedOps);
+        mAppOpsRestrictions = new AppOpsRestrictionsImpl(context, handler,
+                mAppOpsServiceInterface);
+
+        LockGuard.installLock(this, LockGuard.INDEX_APP_OPS);
+        mFile = new AtomicFile(storagePath, "appops");
+
+        mHandler = handler;
+        mConstants = new Constants(mHandler);
+        readState();
+    }
+
+    /**
+     * Handler for work when packages are removed or updated
+     */
+    private BroadcastReceiver mOnPackageUpdatedReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            String pkgName = intent.getData().getEncodedSchemeSpecificPart();
+            int uid = intent.getIntExtra(Intent.EXTRA_UID, Process.INVALID_UID);
+
+            if (action.equals(ACTION_PACKAGE_REMOVED) && !intent.hasExtra(EXTRA_REPLACING)) {
+                synchronized (AppOpsServiceImpl.this) {
+                    UidState uidState = mUidStates.get(uid);
+                    if (uidState == null || uidState.pkgOps == null) {
+                        return;
+                    }
+                    mAppOpsServiceInterface.removePackage(pkgName, UserHandle.getUserId(uid));
+                    Ops removedOps = uidState.pkgOps.remove(pkgName);
+                    if (removedOps != null) {
+                        scheduleFastWriteLocked();
+                    }
+                }
+            } else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
+                AndroidPackage pkg = getPackageManagerInternal().getPackage(pkgName);
+                if (pkg == null) {
+                    return;
+                }
+
+                ArrayMap<String, String> dstAttributionTags = new ArrayMap<>();
+                ArraySet<String> attributionTags = new ArraySet<>();
+                attributionTags.add(null);
+                if (pkg.getAttributions() != null) {
+                    int numAttributions = pkg.getAttributions().size();
+                    for (int attributionNum = 0; attributionNum < numAttributions;
+                            attributionNum++) {
+                        ParsedAttribution attribution = pkg.getAttributions().get(attributionNum);
+                        attributionTags.add(attribution.getTag());
+
+                        int numInheritFrom = attribution.getInheritFrom().size();
+                        for (int inheritFromNum = 0; inheritFromNum < numInheritFrom;
+                                inheritFromNum++) {
+                            dstAttributionTags.put(attribution.getInheritFrom().get(inheritFromNum),
+                                    attribution.getTag());
+                        }
+                    }
+                }
+
+                synchronized (AppOpsServiceImpl.this) {
+                    UidState uidState = mUidStates.get(uid);
+                    if (uidState == null || uidState.pkgOps == null) {
+                        return;
+                    }
+
+                    Ops ops = uidState.pkgOps.get(pkgName);
+                    if (ops == null) {
+                        return;
+                    }
+
+                    // Reset cached package properties to re-initialize when needed
+                    ops.bypass = null;
+                    ops.knownAttributionTags.clear();
+
+                    // Merge data collected for removed attributions into their successor
+                    // attributions
+                    int numOps = ops.size();
+                    for (int opNum = 0; opNum < numOps; opNum++) {
+                        Op op = ops.valueAt(opNum);
+
+                        int numAttributions = op.mAttributions.size();
+                        for (int attributionNum = numAttributions - 1; attributionNum >= 0;
+                                attributionNum--) {
+                            String attributionTag = op.mAttributions.keyAt(attributionNum);
+
+                            if (attributionTags.contains(attributionTag)) {
+                                // attribution still exist after upgrade
+                                continue;
+                            }
+
+                            String newAttributionTag = dstAttributionTags.get(attributionTag);
+
+                            AttributedOp newAttributedOp = op.getOrCreateAttribution(op,
+                                    newAttributionTag);
+                            newAttributedOp.add(op.mAttributions.valueAt(attributionNum));
+                            op.mAttributions.removeAt(attributionNum);
+
+                            scheduleFastWriteLocked();
+                        }
+                    }
+                }
+            }
+        }
+    };
+
+    @Override
+    public void systemReady() {
+        mConstants.startMonitoring(mContext.getContentResolver());
+        mHistoricalRegistry.systemReady(mContext.getContentResolver());
+
+        IntentFilter packageUpdateFilter = new IntentFilter();
+        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        packageUpdateFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        packageUpdateFilter.addDataScheme("package");
+
+        mContext.registerReceiverAsUser(mOnPackageUpdatedReceiver, UserHandle.ALL,
+                packageUpdateFilter, null, null);
+
+        synchronized (this) {
+            for (int uidNum = mUidStates.size() - 1; uidNum >= 0; uidNum--) {
+                int uid = mUidStates.keyAt(uidNum);
+                UidState uidState = mUidStates.valueAt(uidNum);
+
+                String[] pkgsInUid = getPackagesForUid(uidState.uid);
+                if (ArrayUtils.isEmpty(pkgsInUid)) {
+                    uidState.clear();
+                    mUidStates.removeAt(uidNum);
+                    scheduleFastWriteLocked();
+                    continue;
+                }
+
+                ArrayMap<String, Ops> pkgs = uidState.pkgOps;
+                if (pkgs == null) {
+                    continue;
+                }
+
+                int numPkgs = pkgs.size();
+                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                    String pkg = pkgs.keyAt(pkgNum);
+
+                    String action;
+                    if (!ArrayUtils.contains(pkgsInUid, pkg)) {
+                        action = Intent.ACTION_PACKAGE_REMOVED;
+                    } else {
+                        action = Intent.ACTION_PACKAGE_REPLACED;
+                    }
+
+                    SystemServerInitThreadPool.submit(
+                            () -> mOnPackageUpdatedReceiver.onReceive(mContext, new Intent(action)
+                                    .setData(Uri.fromParts("package", pkg, null))
+                                    .putExtra(Intent.EXTRA_UID, uid)),
+                            "Update app-ops uidState in case package " + pkg + " changed");
+                }
+            }
+        }
+
+        final IntentFilter packageSuspendFilter = new IntentFilter();
+        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);
+        packageSuspendFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);
+        mContext.registerReceiverAsUser(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                final int[] changedUids = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
+                final String[] changedPkgs = intent.getStringArrayExtra(
+                        Intent.EXTRA_CHANGED_PACKAGE_LIST);
+                for (int code : OPS_RESTRICTED_ON_SUSPEND) {
+                    ArraySet<OnOpModeChangedListener> onModeChangedListeners;
+                    synchronized (AppOpsServiceImpl.this) {
+                        onModeChangedListeners =
+                                mAppOpsServiceInterface.getOpModeChangedListeners(code);
+                        if (onModeChangedListeners == null) {
+                            continue;
+                        }
+                    }
+                    for (int i = 0; i < changedUids.length; i++) {
+                        final int changedUid = changedUids[i];
+                        final String changedPkg = changedPkgs[i];
+                        // We trust packagemanager to insert matching uid and packageNames in the
+                        // extras
+                        notifyOpChanged(onModeChangedListeners, code, changedUid, changedPkg);
+                    }
+                }
+            }
+        }, UserHandle.ALL, packageSuspendFilter, null, null);
+    }
+
+    @Override
+    public void packageRemoved(int uid, String packageName) {
+        synchronized (this) {
+            UidState uidState = mUidStates.get(uid);
+            if (uidState == null) {
+                return;
+            }
+
+            Ops removedOps = null;
+
+            // Remove any package state if such.
+            if (uidState.pkgOps != null) {
+                removedOps = uidState.pkgOps.remove(packageName);
+                mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
+            }
+
+            // If we just nuked the last package state check if the UID is valid.
+            if (removedOps != null && uidState.pkgOps.isEmpty()
+                    && getPackagesForUid(uid).length <= 0) {
+                uidState.clear();
+                mUidStates.remove(uid);
+            }
+
+            if (removedOps != null) {
+                scheduleFastWriteLocked();
+
+                final int numOps = removedOps.size();
+                for (int opNum = 0; opNum < numOps; opNum++) {
+                    final Op op = removedOps.valueAt(opNum);
+
+                    final int numAttributions = op.mAttributions.size();
+                    for (int attributionNum = 0; attributionNum < numAttributions;
+                            attributionNum++) {
+                        AttributedOp attributedOp = op.mAttributions.valueAt(attributionNum);
+
+                        while (attributedOp.isRunning()) {
+                            attributedOp.finished(attributedOp.mInProgressEvents.keyAt(0));
+                        }
+                        while (attributedOp.isPaused()) {
+                            attributedOp.finished(attributedOp.mPausedInProgressEvents.keyAt(0));
+                        }
+                    }
+                }
+            }
+        }
+
+        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::clearHistory,
+                mHistoricalRegistry, uid, packageName));
+    }
+
+    @Override
+    public void uidRemoved(int uid) {
+        synchronized (this) {
+            if (mUidStates.indexOfKey(uid) >= 0) {
+                mUidStates.get(uid).clear();
+                mUidStates.remove(uid);
+                scheduleFastWriteLocked();
+            }
+        }
+    }
+
+    // The callback method from ForegroundPolicyInterface
+    private void onUidStateChanged(int uid, int state, boolean foregroundModeMayChange) {
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, true);
+
+            if (uidState != null && foregroundModeMayChange && uidState.hasForegroundWatchers) {
+                for (int fgi = uidState.foregroundOps.size() - 1; fgi >= 0; fgi--) {
+                    if (!uidState.foregroundOps.valueAt(fgi)) {
+                        continue;
+                    }
+                    final int code = uidState.foregroundOps.keyAt(fgi);
+
+                    if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)
+                            && uidState.getUidMode(code) == AppOpsManager.MODE_FOREGROUND) {
+                        mHandler.sendMessage(PooledLambda.obtainMessage(
+                                AppOpsServiceImpl::notifyOpChangedForAllPkgsInUid,
+                                this, code, uidState.uid, true, null));
+                    } else if (uidState.pkgOps != null) {
+                        final ArraySet<OnOpModeChangedListener> listenerSet =
+                                mAppOpsServiceInterface.getOpModeChangedListeners(code);
+                        if (listenerSet != null) {
+                            for (int cbi = listenerSet.size() - 1; cbi >= 0; cbi--) {
+                                final OnOpModeChangedListener listener = listenerSet.valueAt(cbi);
+                                if ((listener.getFlags()
+                                        & AppOpsManager.WATCH_FOREGROUND_CHANGES) == 0
+                                        || !listener.isWatchingUid(uidState.uid)) {
+                                    continue;
+                                }
+                                for (int pkgi = uidState.pkgOps.size() - 1; pkgi >= 0; pkgi--) {
+                                    final Op op = uidState.pkgOps.valueAt(pkgi).get(code);
+                                    if (op == null) {
+                                        continue;
+                                    }
+                                    if (op.getMode() == AppOpsManager.MODE_FOREGROUND) {
+                                        mHandler.sendMessage(PooledLambda.obtainMessage(
+                                                AppOpsServiceImpl::notifyOpChanged,
+                                                this, listenerSet.valueAt(cbi), code, uidState.uid,
+                                                uidState.pkgOps.keyAt(pkgi)));
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (uidState != null && uidState.pkgOps != null) {
+                int numPkgs = uidState.pkgOps.size();
+                for (int pkgNum = 0; pkgNum < numPkgs; pkgNum++) {
+                    Ops ops = uidState.pkgOps.valueAt(pkgNum);
+
+                    int numOps = ops.size();
+                    for (int opNum = 0; opNum < numOps; opNum++) {
+                        Op op = ops.valueAt(opNum);
+
+                        int numAttributions = op.mAttributions.size();
+                        for (int attributionNum = 0; attributionNum < numAttributions;
+                                attributionNum++) {
+                            AttributedOp attributedOp = op.mAttributions.valueAt(
+                                    attributionNum);
+
+                            attributedOp.onUidStateChanged(state);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Notify the proc state or capability has changed for a certain UID.
+     */
+    @Override
+    public void updateUidProcState(int uid, int procState,
+            @ActivityManager.ProcessCapability int capability) {
+        synchronized (this) {
+            getUidStateTracker().updateUidProcState(uid, procState, capability);
+            if (!mUidStates.contains(uid)) {
+                UidState uidState = new UidState(uid);
+                mUidStates.put(uid, uidState);
+                onUidStateChanged(uid,
+                        AppOpsUidStateTracker.processStateToUidState(procState), false);
+            }
+        }
+    }
+
+    @Override
+    public void shutdown() {
+        Slog.w(TAG, "Writing app ops before shutdown...");
+        boolean doWrite = false;
+        synchronized (this) {
+            if (mWriteScheduled) {
+                mWriteScheduled = false;
+                mFastWriteScheduled = false;
+                mHandler.removeCallbacks(mWriteRunner);
+                doWrite = true;
+            }
+        }
+        if (doWrite) {
+            writeState();
+        }
+
+        mHistoricalRegistry.shutdown();
+    }
+
+    private ArrayList<AppOpsManager.OpEntry> collectOps(Ops pkgOps, int[] ops) {
+        ArrayList<AppOpsManager.OpEntry> resOps = null;
+        if (ops == null) {
+            resOps = new ArrayList<>();
+            for (int j = 0; j < pkgOps.size(); j++) {
+                Op curOp = pkgOps.valueAt(j);
+                resOps.add(getOpEntryForResult(curOp));
+            }
+        } else {
+            for (int j = 0; j < ops.length; j++) {
+                Op curOp = pkgOps.get(ops[j]);
+                if (curOp != null) {
+                    if (resOps == null) {
+                        resOps = new ArrayList<>();
+                    }
+                    resOps.add(getOpEntryForResult(curOp));
+                }
+            }
+        }
+        return resOps;
+    }
+
+    @Nullable
+    private ArrayList<AppOpsManager.OpEntry> collectUidOps(@NonNull UidState uidState,
+            @Nullable int[] ops) {
+        final SparseIntArray opModes = uidState.getNonDefaultUidModes();
+        if (opModes == null) {
+            return null;
+        }
+
+        int opModeCount = opModes.size();
+        if (opModeCount == 0) {
+            return null;
+        }
+        ArrayList<AppOpsManager.OpEntry> resOps = null;
+        if (ops == null) {
+            resOps = new ArrayList<>();
+            for (int i = 0; i < opModeCount; i++) {
+                int code = opModes.keyAt(i);
+                resOps.add(new OpEntry(code, opModes.get(code), Collections.emptyMap()));
+            }
+        } else {
+            for (int j = 0; j < ops.length; j++) {
+                int code = ops[j];
+                if (opModes.indexOfKey(code) >= 0) {
+                    if (resOps == null) {
+                        resOps = new ArrayList<>();
+                    }
+                    resOps.add(new OpEntry(code, opModes.get(code), Collections.emptyMap()));
+                }
+            }
+        }
+        return resOps;
+    }
+
+    private static @NonNull OpEntry getOpEntryForResult(@NonNull Op op) {
+        return op.createEntryLocked();
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops) {
+        final int callingUid = Binder.getCallingUid();
+        final boolean hasAllPackageAccess = mContext.checkPermission(
+                Manifest.permission.GET_APP_OPS_STATS, Binder.getCallingPid(),
+                Binder.getCallingUid(), null) == PackageManager.PERMISSION_GRANTED;
+        ArrayList<AppOpsManager.PackageOps> res = null;
+        synchronized (this) {
+            final int uidStateCount = mUidStates.size();
+            for (int i = 0; i < uidStateCount; i++) {
+                UidState uidState = mUidStates.valueAt(i);
+                if (uidState.pkgOps == null || uidState.pkgOps.isEmpty()) {
+                    continue;
+                }
+                ArrayMap<String, Ops> packages = uidState.pkgOps;
+                final int packageCount = packages.size();
+                for (int j = 0; j < packageCount; j++) {
+                    Ops pkgOps = packages.valueAt(j);
+                    ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+                    if (resOps != null) {
+                        if (res == null) {
+                            res = new ArrayList<>();
+                        }
+                        AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                                pkgOps.packageName, pkgOps.uidState.uid, resOps);
+                        // Caller can always see their packages and with a permission all.
+                        if (hasAllPackageAccess || callingUid == pkgOps.uidState.uid) {
+                            res.add(resPackage);
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
+            int[] ops) {
+        enforceGetAppOpsStatsPermissionIfNeeded(uid, packageName);
+        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return Collections.emptyList();
+        }
+        synchronized (this) {
+            Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null,
+                    /* edit */ false);
+            if (pkgOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.OpEntry> resOps = collectOps(pkgOps, ops);
+            if (resOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<>();
+            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                    pkgOps.packageName, pkgOps.uidState.uid, resOps);
+            res.add(resPackage);
+            return res;
+        }
+    }
+
+    private void enforceGetAppOpsStatsPermissionIfNeeded(int uid, String packageName) {
+        final int callingUid = Binder.getCallingUid();
+        // We get to access everything
+        if (callingUid == Process.myPid()) {
+            return;
+        }
+        // Apps can access their own data
+        if (uid == callingUid && packageName != null
+                && checkPackage(uid, packageName) == MODE_ALLOWED) {
+            return;
+        }
+        // Otherwise, you need a permission...
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), callingUid, null);
+    }
+
+    /**
+     * Verify that historical appop request arguments are valid.
+     */
+    private void ensureHistoricalOpRequestIsValid(int uid, String packageName,
+            String attributionTag, List<String> opNames, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags) {
+        if ((filter & FILTER_BY_UID) != 0) {
+            Preconditions.checkArgument(uid != Process.INVALID_UID);
+        } else {
+            Preconditions.checkArgument(uid == Process.INVALID_UID);
+        }
+
+        if ((filter & FILTER_BY_PACKAGE_NAME) != 0) {
+            Objects.requireNonNull(packageName);
+        } else {
+            Preconditions.checkArgument(packageName == null);
+        }
+
+        if ((filter & FILTER_BY_ATTRIBUTION_TAG) == 0) {
+            Preconditions.checkArgument(attributionTag == null);
+        }
+
+        if ((filter & FILTER_BY_OP_NAMES) != 0) {
+            Objects.requireNonNull(opNames);
+        } else {
+            Preconditions.checkArgument(opNames == null);
+        }
+
+        Preconditions.checkFlagsArgument(filter,
+                FILTER_BY_UID | FILTER_BY_PACKAGE_NAME | FILTER_BY_ATTRIBUTION_TAG
+                        | FILTER_BY_OP_NAMES);
+        Preconditions.checkArgumentNonnegative(beginTimeMillis);
+        Preconditions.checkArgument(endTimeMillis > beginTimeMillis);
+        Preconditions.checkFlagsArgument(flags, OP_FLAGS_ALL);
+    }
+
+    @Override
+    public void getHistoricalOps(int uid, String packageName, String attributionTag,
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
+        PackageManager pm = mContext.getPackageManager();
+
+        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
+                beginTimeMillis, endTimeMillis, flags);
+        Objects.requireNonNull(callback, "callback cannot be null");
+        ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
+        boolean isSelfRequest = (filter & FILTER_BY_UID) != 0 && uid == Binder.getCallingUid();
+        if (!isSelfRequest) {
+            boolean isCallerInstrumented =
+                    ami.getInstrumentationSourceUid(Binder.getCallingUid()) != Process.INVALID_UID;
+            boolean isCallerSystem = Binder.getCallingPid() == Process.myPid();
+            boolean isCallerPermissionController;
+            try {
+                isCallerPermissionController = pm.getPackageUidAsUser(
+                        mContext.getPackageManager().getPermissionControllerPackageName(), 0,
+                        UserHandle.getUserId(Binder.getCallingUid()))
+                        == Binder.getCallingUid();
+            } catch (PackageManager.NameNotFoundException doesNotHappen) {
+                return;
+            }
+
+            boolean doesCallerHavePermission = mContext.checkPermission(
+                    android.Manifest.permission.GET_HISTORICAL_APP_OPS_STATS,
+                    Binder.getCallingPid(), Binder.getCallingUid())
+                    == PackageManager.PERMISSION_GRANTED;
+
+            if (!isCallerSystem && !isCallerInstrumented && !isCallerPermissionController
+                    && !doesCallerHavePermission) {
+                mHandler.post(() -> callback.sendResult(new Bundle()));
+                return;
+            }
+
+            mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                    Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+        }
+
+        final String[] opNamesArray = (opNames != null)
+                ? opNames.toArray(new String[opNames.size()]) : null;
+
+        Set<String> attributionChainExemptPackages = null;
+        if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+            attributionChainExemptPackages =
+                    PermissionManager.getIndicatorExemptedPackages(mContext);
+        }
+
+        final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+                ? attributionChainExemptPackages.toArray(
+                new String[attributionChainExemptPackages.size()]) : null;
+
+        // Must not hold the appops lock
+        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOps,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
+                filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+                callback).recycleOnUse());
+    }
+
+    @Override
+    public void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback) {
+        ensureHistoricalOpRequestIsValid(uid, packageName, attributionTag, opNames, filter,
+                beginTimeMillis, endTimeMillis, flags);
+        Objects.requireNonNull(callback, "callback cannot be null");
+
+        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
+                Binder.getCallingPid(), Binder.getCallingUid(), "getHistoricalOps");
+
+        final String[] opNamesArray = (opNames != null)
+                ? opNames.toArray(new String[opNames.size()]) : null;
+
+        Set<String> attributionChainExemptPackages = null;
+        if ((dataType & HISTORY_FLAG_GET_ATTRIBUTION_CHAINS) != 0) {
+            attributionChainExemptPackages =
+                    PermissionManager.getIndicatorExemptedPackages(mContext);
+        }
+
+        final String[] chainExemptPkgArray = attributionChainExemptPackages != null
+                ? attributionChainExemptPackages.toArray(
+                new String[attributionChainExemptPackages.size()]) : null;
+
+        // Must not hold the appops lock
+        mHandler.post(PooledLambda.obtainRunnable(HistoricalRegistry::getHistoricalOpsFromDiskRaw,
+                mHistoricalRegistry, uid, packageName, attributionTag, opNamesArray, dataType,
+                filter, beginTimeMillis, endTimeMillis, flags, chainExemptPkgArray,
+                callback).recycleOnUse());
+    }
+
+    @Override
+    public void reloadNonHistoricalState() {
+        mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
+                Binder.getCallingPid(), Binder.getCallingUid(), "reloadNonHistoricalState");
+        writeState();
+        readState();
+    }
+
+    @Override
+    public List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops) {
+        mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.OpEntry> resOps = collectUidOps(uidState, ops);
+            if (resOps == null) {
+                return null;
+            }
+            ArrayList<AppOpsManager.PackageOps> res = new ArrayList<AppOpsManager.PackageOps>();
+            AppOpsManager.PackageOps resPackage = new AppOpsManager.PackageOps(
+                    null, uidState.uid, resOps);
+            res.add(resPackage);
+            return res;
+        }
+    }
+
+    private void pruneOpLocked(Op op, int uid, String packageName) {
+        op.removeAttributionsWithNoTime();
+
+        if (op.mAttributions.isEmpty()) {
+            Ops ops = getOpsLocked(uid, packageName, null, false, null, /* edit */ false);
+            if (ops != null) {
+                ops.remove(op.op);
+                op.setMode(AppOpsManager.opToDefaultMode(op.op));
+                if (ops.size() <= 0) {
+                    UidState uidState = ops.uidState;
+                    ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+                    if (pkgOps != null) {
+                        pkgOps.remove(ops.packageName);
+                        mAppOpsServiceInterface.removePackage(ops.packageName,
+                                UserHandle.getUserId(uidState.uid));
+                        if (pkgOps.isEmpty()) {
+                            uidState.pkgOps = null;
+                        }
+                        if (uidState.isDefault()) {
+                            uidState.clear();
+                            mUidStates.remove(uid);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    @Override
+    public void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid) {
+        if (callingPid == Process.myPid()) {
+            return;
+        }
+        final int callingUser = UserHandle.getUserId(callingUid);
+        synchronized (this) {
+            if (mProfileOwners != null && mProfileOwners.get(callingUser, -1) == callingUid) {
+                if (targetUid >= 0 && callingUser == UserHandle.getUserId(targetUid)) {
+                    // Profile owners are allowed to change modes but only for apps
+                    // within their user.
+                    return;
+                }
+            }
+        }
+        mContext.enforcePermission(android.Manifest.permission.MANAGE_APP_OPS_MODES,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+    }
+
+    @Override
+    public void setUidMode(int code, int uid, int mode,
+            @Nullable IAppOpsCallback permissionPolicyCallback) {
+        if (DEBUG) {
+            Slog.i(TAG, "uid " + uid + " OP_" + opToName(code) + " := " + modeToName(mode)
+                    + " by uid " + Binder.getCallingUid());
+        }
+
+        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        verifyIncomingOp(code);
+        code = AppOpsManager.opToSwitch(code);
+
+        if (permissionPolicyCallback == null) {
+            updatePermissionRevokedCompat(uid, code, mode);
+        }
+
+        int previousMode;
+        synchronized (this) {
+            final int defaultMode = AppOpsManager.opToDefaultMode(code);
+
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState == null) {
+                if (mode == defaultMode) {
+                    return;
+                }
+                uidState = new UidState(uid);
+                mUidStates.put(uid, uidState);
+            }
+            if (uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) {
+                previousMode = uidState.getUidMode(code);
+            } else {
+                // doesn't look right but is legacy behavior.
+                previousMode = MODE_DEFAULT;
+            }
+
+            if (!uidState.setUidMode(code, mode)) {
+                return;
+            }
+            uidState.evalForegroundOps();
+            if (mode != MODE_ERRORED && mode != previousMode) {
+                updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
+            }
+        }
+
+        notifyOpChangedForAllPkgsInUid(code, uid, false, permissionPolicyCallback);
+        notifyOpChangedSync(code, uid, null, mode, previousMode);
+    }
+
+    /**
+     * Notify that an op changed for all packages in an uid.
+     *
+     * @param code           The op that changed
+     * @param uid            The uid the op was changed for
+     * @param onlyForeground Only notify watchers that watch for foreground changes
+     */
+    private void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
+            @Nullable IAppOpsCallback callbackToIgnore) {
+        ModeCallback listenerToIgnore = callbackToIgnore != null
+                ? mModeWatchers.get(callbackToIgnore.asBinder()) : null;
+        mAppOpsServiceInterface.notifyOpChangedForAllPkgsInUid(code, uid, onlyForeground,
+                listenerToIgnore);
+    }
+
+    private void updatePermissionRevokedCompat(int uid, int switchCode, int mode) {
+        PackageManager packageManager = mContext.getPackageManager();
+        if (packageManager == null) {
+            // This can only happen during early boot. At this time the permission state and appop
+            // state are in sync
+            return;
+        }
+
+        String[] packageNames = packageManager.getPackagesForUid(uid);
+        if (ArrayUtils.isEmpty(packageNames)) {
+            return;
+        }
+        String packageName = packageNames[0];
+
+        int[] ops = mSwitchedOps.get(switchCode);
+        for (int code : ops) {
+            String permissionName = AppOpsManager.opToPermission(code);
+            if (permissionName == null) {
+                continue;
+            }
+
+            if (packageManager.checkPermission(permissionName, packageName)
+                    != PackageManager.PERMISSION_GRANTED) {
+                continue;
+            }
+
+            PermissionInfo permissionInfo;
+            try {
+                permissionInfo = packageManager.getPermissionInfo(permissionName, 0);
+            } catch (PackageManager.NameNotFoundException e) {
+                e.printStackTrace();
+                continue;
+            }
+
+            if (!permissionInfo.isRuntime()) {
+                continue;
+            }
+
+            boolean supportsRuntimePermissions = getPackageManagerInternal()
+                    .getUidTargetSdkVersion(uid) >= Build.VERSION_CODES.M;
+
+            UserHandle user = UserHandle.getUserHandleForUid(uid);
+            boolean isRevokedCompat;
+            if (permissionInfo.backgroundPermission != null) {
+                if (packageManager.checkPermission(permissionInfo.backgroundPermission, packageName)
+                        == PackageManager.PERMISSION_GRANTED) {
+                    boolean isBackgroundRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
+
+                    if (isBackgroundRevokedCompat && supportsRuntimePermissions) {
+                        Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
+                                + " permission state, this is discouraged and you should revoke the"
+                                + " runtime permission instead: uid=" + uid + ", switchCode="
+                                + switchCode + ", mode=" + mode + ", permission="
+                                + permissionInfo.backgroundPermission);
+                    }
+
+                    final long identity = Binder.clearCallingIdentity();
+                    try {
+                        packageManager.updatePermissionFlags(permissionInfo.backgroundPermission,
+                                packageName, PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
+                                isBackgroundRevokedCompat
+                                        ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
+                    } finally {
+                        Binder.restoreCallingIdentity(identity);
+                    }
+                }
+
+                isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED
+                        && mode != AppOpsManager.MODE_FOREGROUND;
+            } else {
+                isRevokedCompat = mode != AppOpsManager.MODE_ALLOWED;
+            }
+
+            if (isRevokedCompat && supportsRuntimePermissions) {
+                Slog.w(TAG, "setUidMode() called with a mode inconsistent with runtime"
+                        + " permission state, this is discouraged and you should revoke the"
+                        + " runtime permission instead: uid=" + uid + ", switchCode="
+                        + switchCode + ", mode=" + mode + ", permission=" + permissionName);
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                packageManager.updatePermissionFlags(permissionName, packageName,
+                        PackageManager.FLAG_PERMISSION_REVOKED_COMPAT, isRevokedCompat
+                                ? PackageManager.FLAG_PERMISSION_REVOKED_COMPAT : 0, user);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    }
+
+    private void notifyOpChangedSync(int code, int uid, @NonNull String packageName, int mode,
+            int previousMode) {
+        final StorageManagerInternal storageManagerInternal =
+                LocalServices.getService(StorageManagerInternal.class);
+        if (storageManagerInternal != null) {
+            storageManagerInternal.onAppOpsChanged(code, uid, packageName, mode, previousMode);
+        }
+    }
+
+    @Override
+    public void setMode(int code, int uid, @NonNull String packageName, int mode,
+            @Nullable IAppOpsCallback permissionPolicyCallback) {
+        enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid);
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return;
+        }
+
+        ArraySet<OnOpModeChangedListener> repCbs = null;
+        code = AppOpsManager.opToSwitch(code);
+
+        PackageVerificationResult pvr;
+        try {
+            pvr = verifyAndGetBypass(uid, packageName, null);
+        } catch (SecurityException e) {
+            Slog.e(TAG, "Cannot setMode", e);
+            return;
+        }
+
+        int previousMode = MODE_DEFAULT;
+        synchronized (this) {
+            UidState uidState = getUidStateLocked(uid, false);
+            Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ true);
+            if (op != null) {
+                if (op.getMode() != mode) {
+                    previousMode = op.getMode();
+                    op.setMode(mode);
+
+                    if (uidState != null) {
+                        uidState.evalForegroundOps();
+                    }
+                    ArraySet<OnOpModeChangedListener> cbs =
+                            mAppOpsServiceInterface.getOpModeChangedListeners(code);
+                    if (cbs != null) {
+                        if (repCbs == null) {
+                            repCbs = new ArraySet<>();
+                        }
+                        repCbs.addAll(cbs);
+                    }
+                    cbs = mAppOpsServiceInterface.getPackageModeChangedListeners(packageName);
+                    if (cbs != null) {
+                        if (repCbs == null) {
+                            repCbs = new ArraySet<>();
+                        }
+                        repCbs.addAll(cbs);
+                    }
+                    if (repCbs != null && permissionPolicyCallback != null) {
+                        repCbs.remove(mModeWatchers.get(permissionPolicyCallback.asBinder()));
+                    }
+                    if (mode == AppOpsManager.opToDefaultMode(op.op)) {
+                        // If going into the default mode, prune this op
+                        // if there is nothing else interesting in it.
+                        pruneOpLocked(op, uid, packageName);
+                    }
+                    scheduleFastWriteLocked();
+                    if (mode != MODE_ERRORED) {
+                        updateStartedOpModeForUidLocked(code, mode == MODE_IGNORED, uid);
+                    }
+                }
+            }
+        }
+        if (repCbs != null) {
+            mHandler.sendMessage(PooledLambda.obtainMessage(
+                    AppOpsServiceImpl::notifyOpChanged,
+                    this, repCbs, code, uid, packageName));
+        }
+
+        notifyOpChangedSync(code, uid, packageName, mode, previousMode);
+    }
+
+    private void notifyOpChanged(ArraySet<OnOpModeChangedListener> callbacks, int code,
+            int uid, String packageName) {
+        for (int i = 0; i < callbacks.size(); i++) {
+            final OnOpModeChangedListener callback = callbacks.valueAt(i);
+            notifyOpChanged(callback, code, uid, packageName);
+        }
+    }
+
+    private void notifyOpChanged(OnOpModeChangedListener callback, int code,
+            int uid, String packageName) {
+        mAppOpsServiceInterface.notifyOpChanged(callback, code, uid, packageName);
+    }
+
+    private static ArrayList<ChangeRec> addChange(ArrayList<ChangeRec> reports,
+            int op, int uid, String packageName, int previousMode) {
+        boolean duplicate = false;
+        if (reports == null) {
+            reports = new ArrayList<>();
+        } else {
+            final int reportCount = reports.size();
+            for (int j = 0; j < reportCount; j++) {
+                ChangeRec report = reports.get(j);
+                if (report.op == op && report.pkg.equals(packageName)) {
+                    duplicate = true;
+                    break;
+                }
+            }
+        }
+        if (!duplicate) {
+            reports.add(new ChangeRec(op, uid, packageName, previousMode));
+        }
+
+        return reports;
+    }
+
+    private static HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> addCallbacks(
+            HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks,
+            int op, int uid, String packageName, int previousMode,
+            ArraySet<OnOpModeChangedListener> cbs) {
+        if (cbs == null) {
+            return callbacks;
+        }
+        if (callbacks == null) {
+            callbacks = new HashMap<>();
+        }
+        final int N = cbs.size();
+        for (int i=0; i<N; i++) {
+            OnOpModeChangedListener cb = cbs.valueAt(i);
+            ArrayList<ChangeRec> reports = callbacks.get(cb);
+            ArrayList<ChangeRec> changed = addChange(reports, op, uid, packageName, previousMode);
+            if (changed != reports) {
+                callbacks.put(cb, changed);
+            }
+        }
+        return callbacks;
+    }
+
+    static final class ChangeRec {
+        final int op;
+        final int uid;
+        final String pkg;
+        final int previous_mode;
+
+        ChangeRec(int _op, int _uid, String _pkg, int _previous_mode) {
+            op = _op;
+            uid = _uid;
+            pkg = _pkg;
+            previous_mode = _previous_mode;
+        }
+    }
+
+    @Override
+    public void resetAllModes(int reqUserId, String reqPackageName) {
+        final int callingPid = Binder.getCallingPid();
+        final int callingUid = Binder.getCallingUid();
+        reqUserId = ActivityManager.handleIncomingUser(callingPid, callingUid, reqUserId,
+                true, true, "resetAllModes", null);
+
+        int reqUid = -1;
+        if (reqPackageName != null) {
+            try {
+                reqUid = AppGlobals.getPackageManager().getPackageUid(
+                        reqPackageName, PackageManager.MATCH_UNINSTALLED_PACKAGES, reqUserId);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        }
+
+        enforceManageAppOpsModes(callingPid, callingUid, reqUid);
+
+        HashMap<OnOpModeChangedListener, ArrayList<ChangeRec>> callbacks = null;
+        ArrayList<ChangeRec> allChanges = new ArrayList<>();
+        synchronized (this) {
+            boolean changed = false;
+            for (int i = mUidStates.size() - 1; i >= 0; i--) {
+                UidState uidState = mUidStates.valueAt(i);
+
+                SparseIntArray opModes = uidState.getNonDefaultUidModes();
+                if (opModes != null && (uidState.uid == reqUid || reqUid == -1)) {
+                    final int uidOpCount = opModes.size();
+                    for (int j = uidOpCount - 1; j >= 0; j--) {
+                        final int code = opModes.keyAt(j);
+                        if (AppOpsManager.opAllowsReset(code)) {
+                            int previousMode = opModes.valueAt(j);
+                            uidState.setUidMode(code, AppOpsManager.opToDefaultMode(code));
+                            for (String packageName : getPackagesForUid(uidState.uid)) {
+                                callbacks = addCallbacks(callbacks, code, uidState.uid,
+                                        packageName, previousMode,
+                                        mAppOpsServiceInterface.getOpModeChangedListeners(code));
+                                callbacks = addCallbacks(callbacks, code, uidState.uid,
+                                        packageName, previousMode, mAppOpsServiceInterface
+                                                .getPackageModeChangedListeners(packageName));
+
+                                allChanges = addChange(allChanges, code, uidState.uid,
+                                        packageName, previousMode);
+                            }
+                        }
+                    }
+                }
+
+                if (uidState.pkgOps == null) {
+                    continue;
+                }
+
+                if (reqUserId != UserHandle.USER_ALL
+                        && reqUserId != UserHandle.getUserId(uidState.uid)) {
+                    // Skip any ops for a different user
+                    continue;
+                }
+
+                Map<String, Ops> packages = uidState.pkgOps;
+                Iterator<Map.Entry<String, Ops>> it = packages.entrySet().iterator();
+                boolean uidChanged = false;
+                while (it.hasNext()) {
+                    Map.Entry<String, Ops> ent = it.next();
+                    String packageName = ent.getKey();
+                    if (reqPackageName != null && !reqPackageName.equals(packageName)) {
+                        // Skip any ops for a different package
+                        continue;
+                    }
+                    Ops pkgOps = ent.getValue();
+                    for (int j=pkgOps.size()-1; j>=0; j--) {
+                        Op curOp = pkgOps.valueAt(j);
+                        if (shouldDeferResetOpToDpm(curOp.op)) {
+                            deferResetOpToDpm(curOp.op, reqPackageName, reqUserId);
+                            continue;
+                        }
+                        if (AppOpsManager.opAllowsReset(curOp.op)
+                                && curOp.getMode() != AppOpsManager.opToDefaultMode(curOp.op)) {
+                            int previousMode = curOp.getMode();
+                            curOp.setMode(AppOpsManager.opToDefaultMode(curOp.op));
+                            changed = true;
+                            uidChanged = true;
+                            final int uid = curOp.uidState.uid;
+                            callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
+                                    previousMode,
+                                    mAppOpsServiceInterface.getOpModeChangedListeners(curOp.op));
+                            callbacks = addCallbacks(callbacks, curOp.op, uid, packageName,
+                                    previousMode, mAppOpsServiceInterface
+                                            .getPackageModeChangedListeners(packageName));
+
+                            allChanges = addChange(allChanges, curOp.op, uid, packageName,
+                                    previousMode);
+                            curOp.removeAttributionsWithNoTime();
+                            if (curOp.mAttributions.isEmpty()) {
+                                pkgOps.removeAt(j);
+                            }
+                        }
+                    }
+                    if (pkgOps.size() == 0) {
+                        it.remove();
+                        mAppOpsServiceInterface.removePackage(packageName,
+                                UserHandle.getUserId(uidState.uid));
+                    }
+                }
+                if (uidState.isDefault()) {
+                    uidState.clear();
+                    mUidStates.remove(uidState.uid);
+                }
+                if (uidChanged) {
+                    uidState.evalForegroundOps();
+                }
+            }
+
+            if (changed) {
+                scheduleFastWriteLocked();
+            }
+        }
+        if (callbacks != null) {
+            for (Map.Entry<OnOpModeChangedListener, ArrayList<ChangeRec>> ent
+                    : callbacks.entrySet()) {
+                OnOpModeChangedListener cb = ent.getKey();
+                ArrayList<ChangeRec> reports = ent.getValue();
+                for (int i=0; i<reports.size(); i++) {
+                    ChangeRec rep = reports.get(i);
+                    mHandler.sendMessage(PooledLambda.obtainMessage(
+                            AppOpsServiceImpl::notifyOpChanged,
+                            this, cb, rep.op, rep.uid, rep.pkg));
+                }
+            }
+        }
+
+        int numChanges = allChanges.size();
+        for (int i = 0; i < numChanges; i++) {
+            ChangeRec change = allChanges.get(i);
+            notifyOpChangedSync(change.op, change.uid, change.pkg,
+                    AppOpsManager.opToDefaultMode(change.op), change.previous_mode);
+        }
+    }
+
+    private boolean shouldDeferResetOpToDpm(int op) {
+        // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
+        //  pre-grants to a role-based mechanism or another general-purpose mechanism.
+        return dpmi != null && dpmi.supportsResetOp(op);
+    }
+
+    /** Assumes {@link #shouldDeferResetOpToDpm(int)} is true. */
+    private void deferResetOpToDpm(int op, String packageName, @UserIdInt int userId) {
+        // TODO(b/174582385): avoid special-casing app-op resets by migrating app-op permission
+        //  pre-grants to a role-based mechanism or another general-purpose mechanism.
+        dpmi.resetOp(op, packageName, userId);
+    }
+
+    private void evalAllForegroundOpsLocked() {
+        for (int uidi = mUidStates.size() - 1; uidi >= 0; uidi--) {
+            final UidState uidState = mUidStates.valueAt(uidi);
+            if (uidState.foregroundOps != null) {
+                uidState.evalForegroundOps();
+            }
+        }
+    }
+
+    @Override
+    public void startWatchingModeWithFlags(int op, String packageName, int flags,
+            IAppOpsCallback callback) {
+        int watchedUid = -1;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        // TODO: should have a privileged permission to protect this.
+        // Also, if the caller has requested WATCH_FOREGROUND_CHANGES, should we require
+        // the USAGE_STATS permission since this can provide information about when an
+        // app is in the foreground?
+        Preconditions.checkArgumentInRange(op, AppOpsManager.OP_NONE,
+                AppOpsManager._NUM_OP - 1, "Invalid op code: " + op);
+        if (callback == null) {
+            return;
+        }
+        final boolean mayWatchPackageName = packageName != null
+                && !filterAppAccessUnlocked(packageName, UserHandle.getUserId(callingUid));
+        synchronized (this) {
+            int switchOp = (op != AppOpsManager.OP_NONE) ? AppOpsManager.opToSwitch(op) : op;
+
+            int notifiedOps;
+            if ((flags & CALL_BACK_ON_SWITCHED_OP) == 0) {
+                if (op == OP_NONE) {
+                    notifiedOps = ALL_OPS;
+                } else {
+                    notifiedOps = op;
+                }
+            } else {
+                notifiedOps = switchOp;
+            }
+
+            ModeCallback cb = mModeWatchers.get(callback.asBinder());
+            if (cb == null) {
+                cb = new ModeCallback(callback, watchedUid, flags, notifiedOps, callingUid,
+                        callingPid);
+                mModeWatchers.put(callback.asBinder(), cb);
+            }
+            if (switchOp != AppOpsManager.OP_NONE) {
+                mAppOpsServiceInterface.startWatchingOpModeChanged(cb, switchOp);
+            }
+            if (mayWatchPackageName) {
+                mAppOpsServiceInterface.startWatchingPackageModeChanged(cb, packageName);
+            }
+            evalAllForegroundOpsLocked();
+        }
+    }
+
+    @Override
+    public void stopWatchingMode(IAppOpsCallback callback) {
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            ModeCallback cb = mModeWatchers.remove(callback.asBinder());
+            if (cb != null) {
+                cb.unlinkToDeath();
+                mAppOpsServiceInterface.removeListener(cb);
+            }
+
+            evalAllForegroundOpsLocked();
+        }
+    }
+
+    @Override
+    public int checkOperation(int code, int uid, String packageName,
+            @Nullable String attributionTag, boolean raw) {
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return AppOpsManager.opToDefaultMode(code);
+        }
+
+        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return checkOperationUnchecked(code, uid, resolvedPackageName, attributionTag, raw);
+    }
+
+    /**
+     * Get the mode of an app-op.
+     *
+     * @param code        The code of the op
+     * @param uid         The uid of the package the op belongs to
+     * @param packageName The package the op belongs to
+     * @param raw         If the raw state of eval-ed state should be checked.
+     * @return The mode of the op
+     */
+    private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, boolean raw) {
+        PackageVerificationResult pvr;
+        try {
+            pvr = verifyAndGetBypass(uid, packageName, null);
+        } catch (SecurityException e) {
+            Slog.e(TAG, "checkOperation", e);
+            return AppOpsManager.opToDefaultMode(code);
+        }
+
+        if (isOpRestrictedDueToSuspend(code, packageName, uid)) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        synchronized (this) {
+            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, true)) {
+                return AppOpsManager.MODE_IGNORED;
+            }
+            code = AppOpsManager.opToSwitch(code);
+            UidState uidState = getUidStateLocked(uid, false);
+            if (uidState != null
+                    && uidState.getUidMode(code) != AppOpsManager.opToDefaultMode(code)) {
+                final int rawMode = uidState.getUidMode(code);
+                return raw ? rawMode : uidState.evalMode(code, rawMode);
+            }
+            Op op = getOpLocked(code, uid, packageName, null, false, pvr.bypass, /* edit */ false);
+            if (op == null) {
+                return AppOpsManager.opToDefaultMode(code);
+            }
+            return raw ? op.getMode() : op.uidState.evalMode(op.op, op.getMode());
+        }
+    }
+
+    @Override
+    public int checkPackage(int uid, String packageName) {
+        Objects.requireNonNull(packageName);
+        try {
+            verifyAndGetBypass(uid, packageName, null);
+            // When the caller is the system, it's possible that the packageName is the special
+            // one (e.g., "root") which isn't actually existed.
+            if (resolveUid(packageName) == uid
+                    || (isPackageExisted(packageName)
+                            && !filterAppAccessUnlocked(packageName, UserHandle.getUserId(uid)))) {
+                return AppOpsManager.MODE_ALLOWED;
+            }
+            return AppOpsManager.MODE_ERRORED;
+        } catch (SecurityException ignored) {
+            return AppOpsManager.MODE_ERRORED;
+        }
+    }
+
+    private boolean isPackageExisted(String packageName) {
+        return getPackageManagerInternal().getPackageStateInternal(packageName) != null;
+    }
+
+    /**
+     * This method will check with PackageManager to determine if the package provided should
+     * be visible to the {@link Binder#getCallingUid()}.
+     *
+     * NOTE: This must not be called while synchronized on {@code this} to avoid dead locks
+     */
+    private boolean filterAppAccessUnlocked(String packageName, int userId) {
+        final int callingUid = Binder.getCallingUid();
+        return LocalServices.getService(PackageManagerInternal.class)
+                .filterAppAccess(packageName, callingUid, userId);
+    }
+
+    @Override
+    public int noteOperation(int code, int uid, @Nullable String packageName,
+            @Nullable String attributionTag, @Nullable String message) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return AppOpsManager.MODE_ERRORED;
+        }
+
+        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+        return noteOperationUnchecked(code, uid, resolvedPackageName, attributionTag,
+                Process.INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
+    }
+
+    @Override
+    public int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, int proxyUid, String proxyPackageName,
+            @Nullable String proxyAttributionTag, @OpFlags int flags) {
+        PackageVerificationResult pvr;
+        try {
+            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
+            if (!pvr.isAttributionTagValid) {
+                attributionTag = null;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "noteOperation", e);
+            return AppOpsManager.MODE_ERRORED;
+        }
+
+        synchronized (this) {
+            final Ops ops = getOpsLocked(uid, packageName, attributionTag,
+                    pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
+            if (ops == null) {
+                scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                        AppOpsManager.MODE_IGNORED);
+                if (DEBUG) {
+                    Slog.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+                            + " package " + packageName + "flags: "
+                            + AppOpsManager.flagsToString(flags));
+                }
+                return AppOpsManager.MODE_ERRORED;
+            }
+            final Op op = getOpLocked(ops, code, uid, true);
+            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
+            if (attributedOp.isRunning()) {
+                Slog.w(TAG, "Noting op not finished: uid " + uid + " pkg " + packageName + " code "
+                        + code + " startTime of in progress event="
+                        + attributedOp.mInProgressEvents.valueAt(0).getStartTime());
+            }
+
+            final int switchCode = AppOpsManager.opToSwitch(code);
+            final UidState uidState = ops.uidState;
+            if (isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass, false)) {
+                attributedOp.rejected(uidState.getState(), flags);
+                scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                        AppOpsManager.MODE_IGNORED);
+                return AppOpsManager.MODE_IGNORED;
+            }
+            // If there is a non-default per UID policy (we set UID op mode only if
+            // non-default) it takes over, otherwise use the per package policy.
+            if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
+                final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
+                if (uidMode != AppOpsManager.MODE_ALLOWED) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "noteOperation: uid reject #" + uidMode + " for code "
+                                + switchCode + " (" + code + ") uid " + uid + " package "
+                                + packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                    }
+                    attributedOp.rejected(uidState.getState(), flags);
+                    scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                            uidMode);
+                    return uidMode;
+                }
+            } else {
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+                        : op;
+                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
+                if (mode != AppOpsManager.MODE_ALLOWED) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "noteOperation: reject #" + mode + " for code "
+                                + switchCode + " (" + code + ") uid " + uid + " package "
+                                + packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                    }
+                    attributedOp.rejected(uidState.getState(), flags);
+                    scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                            mode);
+                    return mode;
+                }
+            }
+            if (DEBUG) {
+                Slog.d(TAG,
+                        "noteOperation: allowing code " + code + " uid " + uid + " package "
+                                + packageName + (attributionTag == null ? ""
+                                : "." + attributionTag) + " flags: "
+                                + AppOpsManager.flagsToString(flags));
+            }
+            scheduleOpNotedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                    AppOpsManager.MODE_ALLOWED);
+            attributedOp.accessed(proxyUid, proxyPackageName, proxyAttributionTag,
+                    uidState.getState(),
+                    flags);
+
+            return AppOpsManager.MODE_ALLOWED;
+        }
+    }
+
+    @Override
+    public boolean isAttributionTagValid(int uid, @NonNull String packageName,
+            @Nullable String attributionTag,
+            @Nullable String proxyPackageName) {
+        try {
+            return verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName)
+                    .isAttributionTagValid;
+        } catch (SecurityException ignored) {
+            // We don't want to throw, this exception will be handled in the (c/n/s)Operation calls
+            // when they need the bypass object.
+            return false;
+        }
+    }
+
+    // TODO moltmann: Allow watching for attribution ops
+    @Override
+    public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) {
+        int watchedUid = Process.INVALID_UID;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                != PackageManager.PERMISSION_GRANTED) {
+            watchedUid = callingUid;
+        }
+        if (ops != null) {
+            Preconditions.checkArrayElementsInRange(ops, 0,
+                    AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops));
+        }
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            SparseArray<ActiveCallback> callbacks = mActiveWatchers.get(callback.asBinder());
+            if (callbacks == null) {
+                callbacks = new SparseArray<>();
+                mActiveWatchers.put(callback.asBinder(), callbacks);
+            }
+            final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid,
+                    callingUid, callingPid);
+            for (int op : ops) {
+                callbacks.put(op, activeCallback);
+            }
+        }
+    }
+
+    @Override
+    public void stopWatchingActive(IAppOpsActiveCallback callback) {
+        if (callback == null) {
+            return;
+        }
+        synchronized (this) {
+            final SparseArray<ActiveCallback> activeCallbacks =
+                    mActiveWatchers.remove(callback.asBinder());
+            if (activeCallbacks == null) {
+                return;
+            }
+            final int callbackCount = activeCallbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                activeCallbacks.valueAt(i).destroy();
+            }
+        }
+    }
+
+    @Override
+    public void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback) {
+        int watchedUid = Process.INVALID_UID;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                != PackageManager.PERMISSION_GRANTED) {
+            watchedUid = callingUid;
+        }
+
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
+        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
+                "Invalid op code in: " + Arrays.toString(ops));
+        Objects.requireNonNull(callback, "Callback cannot be null");
+
+        synchronized (this) {
+            SparseArray<StartedCallback> callbacks = mStartedWatchers.get(callback.asBinder());
+            if (callbacks == null) {
+                callbacks = new SparseArray<>();
+                mStartedWatchers.put(callback.asBinder(), callbacks);
+            }
+
+            final StartedCallback startedCallback = new StartedCallback(callback, watchedUid,
+                    callingUid, callingPid);
+            for (int op : ops) {
+                callbacks.put(op, startedCallback);
+            }
+        }
+    }
+
+    @Override
+    public void stopWatchingStarted(IAppOpsStartedCallback callback) {
+        Objects.requireNonNull(callback, "Callback cannot be null");
+
+        synchronized (this) {
+            final SparseArray<StartedCallback> startedCallbacks =
+                    mStartedWatchers.remove(callback.asBinder());
+            if (startedCallbacks == null) {
+                return;
+            }
+
+            final int callbackCount = startedCallbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                startedCallbacks.valueAt(i).destroy();
+            }
+        }
+    }
+
+    @Override
+    public void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback) {
+        int watchedUid = Process.INVALID_UID;
+        final int callingUid = Binder.getCallingUid();
+        final int callingPid = Binder.getCallingPid();
+        if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                != PackageManager.PERMISSION_GRANTED) {
+            watchedUid = callingUid;
+        }
+        Preconditions.checkArgument(!ArrayUtils.isEmpty(ops), "Ops cannot be null or empty");
+        Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1,
+                "Invalid op code in: " + Arrays.toString(ops));
+        Objects.requireNonNull(callback, "Callback cannot be null");
+        synchronized (this) {
+            SparseArray<NotedCallback> callbacks = mNotedWatchers.get(callback.asBinder());
+            if (callbacks == null) {
+                callbacks = new SparseArray<>();
+                mNotedWatchers.put(callback.asBinder(), callbacks);
+            }
+            final NotedCallback notedCallback = new NotedCallback(callback, watchedUid,
+                    callingUid, callingPid);
+            for (int op : ops) {
+                callbacks.put(op, notedCallback);
+            }
+        }
+    }
+
+    @Override
+    public void stopWatchingNoted(IAppOpsNotedCallback callback) {
+        Objects.requireNonNull(callback, "Callback cannot be null");
+        synchronized (this) {
+            final SparseArray<NotedCallback> notedCallbacks =
+                    mNotedWatchers.remove(callback.asBinder());
+            if (notedCallbacks == null) {
+                return;
+            }
+            final int callbackCount = notedCallbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                notedCallbacks.valueAt(i).destroy();
+            }
+        }
+    }
+
+    @Override
+    public int startOperation(@NonNull IBinder clientId, int code, int uid,
+            @Nullable String packageName, @Nullable String attributionTag,
+            boolean startIfModeDefault, @NonNull String message,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return AppOpsManager.MODE_ERRORED;
+        }
+
+        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return AppOpsManager.MODE_IGNORED;
+        }
+
+        // As a special case for OP_RECORD_AUDIO_HOTWORD, which we use only for attribution
+        // purposes and not as a check, also make sure that the caller is allowed to access
+        // the data gated by OP_RECORD_AUDIO.
+        //
+        // TODO: Revert this change before Android 12.
+        if (code == OP_RECORD_AUDIO_HOTWORD || code == OP_RECEIVE_AMBIENT_TRIGGER_AUDIO) {
+            int result = checkOperation(OP_RECORD_AUDIO, uid, packageName, null, false);
+            if (result != AppOpsManager.MODE_ALLOWED) {
+                return result;
+            }
+        }
+        return startOperationUnchecked(clientId, code, uid, packageName, attributionTag,
+                Process.INVALID_UID, null, null, OP_FLAG_SELF, startIfModeDefault,
+                attributionFlags, attributionChainId, /*dryRun*/ false);
+    }
+
+    private boolean shouldStartForMode(int mode, boolean startIfModeDefault) {
+        return (mode == MODE_ALLOWED || (mode == MODE_DEFAULT && startIfModeDefault));
+    }
+
+    @Override
+    public int startOperationUnchecked(IBinder clientId, int code, int uid,
+            @NonNull String packageName, @Nullable String attributionTag, int proxyUid,
+            String proxyPackageName, @Nullable String proxyAttributionTag, @OpFlags int flags,
+            boolean startIfModeDefault, @AttributionFlags int attributionFlags,
+            int attributionChainId, boolean dryRun) {
+        PackageVerificationResult pvr;
+        try {
+            pvr = verifyAndGetBypass(uid, packageName, attributionTag, proxyPackageName);
+            if (!pvr.isAttributionTagValid) {
+                attributionTag = null;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "startOperation", e);
+            return AppOpsManager.MODE_ERRORED;
+        }
+
+        boolean isRestricted;
+        int startType = START_TYPE_FAILED;
+        synchronized (this) {
+            final Ops ops = getOpsLocked(uid, packageName, attributionTag,
+                    pvr.isAttributionTagValid, pvr.bypass, /* edit */ true);
+            if (ops == null) {
+                if (!dryRun) {
+                    scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
+                            flags, AppOpsManager.MODE_IGNORED, startType, attributionFlags,
+                            attributionChainId);
+                }
+                if (DEBUG) {
+                    Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid
+                            + " package " + packageName + " flags: "
+                            + AppOpsManager.flagsToString(flags));
+                }
+                return AppOpsManager.MODE_ERRORED;
+            }
+            final Op op = getOpLocked(ops, code, uid, true);
+            final AttributedOp attributedOp = op.getOrCreateAttribution(op, attributionTag);
+            final UidState uidState = ops.uidState;
+            isRestricted = isOpRestrictedLocked(uid, code, packageName, attributionTag, pvr.bypass,
+                    false);
+            final int switchCode = AppOpsManager.opToSwitch(code);
+            // If there is a non-default per UID policy (we set UID op mode only if
+            // non-default) it takes over, otherwise use the per package policy.
+            if (uidState.getUidMode(switchCode) != AppOpsManager.opToDefaultMode(switchCode)) {
+                final int uidMode = uidState.evalMode(code, uidState.getUidMode(switchCode));
+                if (!shouldStartForMode(uidMode, startIfModeDefault)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "startOperation: uid reject #" + uidMode + " for code "
+                                + switchCode + " (" + code + ") uid " + uid + " package "
+                                + packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                    }
+                    if (!dryRun) {
+                        attributedOp.rejected(uidState.getState(), flags);
+                        scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
+                                flags, uidMode, startType, attributionFlags, attributionChainId);
+                    }
+                    return uidMode;
+                }
+            } else {
+                final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, uid, true)
+                        : op;
+                final int mode = switchOp.uidState.evalMode(switchOp.op, switchOp.getMode());
+                if (!shouldStartForMode(mode, startIfModeDefault)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "startOperation: reject #" + mode + " for code "
+                                + switchCode + " (" + code + ") uid " + uid + " package "
+                                + packageName + " flags: " + AppOpsManager.flagsToString(flags));
+                    }
+                    if (!dryRun) {
+                        attributedOp.rejected(uidState.getState(), flags);
+                        scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag,
+                                flags, mode, startType, attributionFlags, attributionChainId);
+                    }
+                    return mode;
+                }
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "startOperation: allowing code " + code + " uid " + uid
+                        + " package " + packageName + " restricted: " + isRestricted
+                        + " flags: " + AppOpsManager.flagsToString(flags));
+            }
+            if (!dryRun) {
+                try {
+                    if (isRestricted) {
+                        attributedOp.createPaused(clientId, proxyUid, proxyPackageName,
+                                proxyAttributionTag, uidState.getState(), flags,
+                                attributionFlags, attributionChainId);
+                    } else {
+                        attributedOp.started(clientId, proxyUid, proxyPackageName,
+                                proxyAttributionTag, uidState.getState(), flags,
+                                attributionFlags, attributionChainId);
+                        startType = START_TYPE_STARTED;
+                    }
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+                scheduleOpStartedIfNeededLocked(code, uid, packageName, attributionTag, flags,
+                        isRestricted ? MODE_IGNORED : MODE_ALLOWED, startType, attributionFlags,
+                        attributionChainId);
+            }
+        }
+
+        // Possible bug? The raw mode could have been MODE_DEFAULT to reach here.
+        return isRestricted ? MODE_IGNORED : MODE_ALLOWED;
+    }
+
+    @Override
+    public void finishOperation(IBinder clientId, int code, int uid, String packageName,
+            String attributionTag) {
+        verifyIncomingUid(uid);
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return;
+        }
+
+        String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return;
+        }
+
+        finishOperationUnchecked(clientId, code, uid, resolvedPackageName, attributionTag);
+    }
+
+    @Override
+    public void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
+            String attributionTag) {
+        PackageVerificationResult pvr;
+        try {
+            pvr = verifyAndGetBypass(uid, packageName, attributionTag);
+            if (!pvr.isAttributionTagValid) {
+                attributionTag = null;
+            }
+        } catch (SecurityException e) {
+            Slog.e(TAG, "Cannot finishOperation", e);
+            return;
+        }
+
+        synchronized (this) {
+            Op op = getOpLocked(code, uid, packageName, attributionTag, pvr.isAttributionTagValid,
+                    pvr.bypass, /* edit */ true);
+            if (op == null) {
+                Slog.e(TAG, "Operation not found: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
+                return;
+            }
+            final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+            if (attributedOp == null) {
+                Slog.e(TAG, "Attribution not found: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
+                return;
+            }
+
+            if (attributedOp.isRunning() || attributedOp.isPaused()) {
+                attributedOp.finished(clientId);
+            } else {
+                Slog.e(TAG, "Operation not started: uid=" + uid + " pkg=" + packageName + "("
+                        + attributionTag + ") op=" + AppOpsManager.opToName(code));
+            }
+        }
+    }
+
+    void scheduleOpActiveChangedIfNeededLocked(int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, boolean active,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
+        ArraySet<ActiveCallback> dispatchedCallbacks = null;
+        final int callbackListCount = mActiveWatchers.size();
+        for (int i = 0; i < callbackListCount; i++) {
+            final SparseArray<ActiveCallback> callbacks = mActiveWatchers.valueAt(i);
+            ActiveCallback callback = callbacks.get(code);
+            if (callback != null) {
+                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+                    continue;
+                }
+                if (dispatchedCallbacks == null) {
+                    dispatchedCallbacks = new ArraySet<>();
+                }
+                dispatchedCallbacks.add(callback);
+            }
+        }
+        if (dispatchedCallbacks == null) {
+            return;
+        }
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsServiceImpl::notifyOpActiveChanged,
+                this, dispatchedCallbacks, code, uid, packageName, attributionTag, active,
+                attributionFlags, attributionChainId));
+    }
+
+    private void notifyOpActiveChanged(ArraySet<ActiveCallback> callbacks,
+            int code, int uid, @NonNull String packageName, @Nullable String attributionTag,
+            boolean active, @AttributionFlags int attributionFlags, int attributionChainId) {
+        // There are features watching for mode changes such as window manager
+        // and location manager which are in our process. The callbacks in these
+        // features may require permissions our remote caller does not have.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int callbackCount = callbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final ActiveCallback callback = callbacks.valueAt(i);
+                try {
+                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
+                        continue;
+                    }
+                    callback.mCallback.opActiveChanged(code, uid, packageName, attributionTag,
+                            active, attributionFlags, attributionChainId);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    void scheduleOpStartedIfNeededLocked(int code, int uid, String pkgName,
+            String attributionTag, @OpFlags int flags, @Mode int result,
+            @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
+        ArraySet<StartedCallback> dispatchedCallbacks = null;
+        final int callbackListCount = mStartedWatchers.size();
+        for (int i = 0; i < callbackListCount; i++) {
+            final SparseArray<StartedCallback> callbacks = mStartedWatchers.valueAt(i);
+
+            StartedCallback callback = callbacks.get(code);
+            if (callback != null) {
+                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+                    continue;
+                }
+
+                if (dispatchedCallbacks == null) {
+                    dispatchedCallbacks = new ArraySet<>();
+                }
+                dispatchedCallbacks.add(callback);
+            }
+        }
+
+        if (dispatchedCallbacks == null) {
+            return;
+        }
+
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsServiceImpl::notifyOpStarted,
+                this, dispatchedCallbacks, code, uid, pkgName, attributionTag, flags,
+                result, startedType, attributionFlags, attributionChainId));
+    }
+
+    private void notifyOpStarted(ArraySet<StartedCallback> callbacks,
+            int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
+            @Mode int result, @AppOpsManager.OnOpStartedListener.StartedType int startedType,
+            @AttributionFlags int attributionFlags, int attributionChainId) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int callbackCount = callbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final StartedCallback callback = callbacks.valueAt(i);
+                try {
+                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
+                        continue;
+                    }
+                    callback.mCallback.opStarted(code, uid, packageName, attributionTag, flags,
+                            result, startedType, attributionFlags, attributionChainId);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void scheduleOpNotedIfNeededLocked(int code, int uid, String packageName,
+            String attributionTag, @OpFlags int flags, @Mode int result) {
+        ArraySet<NotedCallback> dispatchedCallbacks = null;
+        final int callbackListCount = mNotedWatchers.size();
+        for (int i = 0; i < callbackListCount; i++) {
+            final SparseArray<NotedCallback> callbacks = mNotedWatchers.valueAt(i);
+            final NotedCallback callback = callbacks.get(code);
+            if (callback != null) {
+                if (callback.mWatchingUid >= 0 && callback.mWatchingUid != uid) {
+                    continue;
+                }
+                if (dispatchedCallbacks == null) {
+                    dispatchedCallbacks = new ArraySet<>();
+                }
+                dispatchedCallbacks.add(callback);
+            }
+        }
+        if (dispatchedCallbacks == null) {
+            return;
+        }
+        mHandler.sendMessage(PooledLambda.obtainMessage(
+                AppOpsServiceImpl::notifyOpChecked,
+                this, dispatchedCallbacks, code, uid, packageName, attributionTag, flags,
+                result));
+    }
+
+    private void notifyOpChecked(ArraySet<NotedCallback> callbacks,
+            int code, int uid, String packageName, String attributionTag, @OpFlags int flags,
+            @Mode int result) {
+        // There are features watching for checks in our process. The callbacks in
+        // these features may require permissions our remote caller does not have.
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final int callbackCount = callbacks.size();
+            for (int i = 0; i < callbackCount; i++) {
+                final NotedCallback callback = callbacks.valueAt(i);
+                try {
+                    if (shouldIgnoreCallback(code, callback.mCallingPid, callback.mCallingUid)) {
+                        continue;
+                    }
+                    callback.mCallback.opNoted(code, uid, packageName, attributionTag, flags,
+                            result);
+                } catch (RemoteException e) {
+                    /* do nothing */
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    private void verifyIncomingUid(int uid) {
+        if (uid == Binder.getCallingUid()) {
+            return;
+        }
+        if (Binder.getCallingPid() == Process.myPid()) {
+            return;
+        }
+        mContext.enforcePermission(android.Manifest.permission.UPDATE_APP_OPS_STATS,
+                Binder.getCallingPid(), Binder.getCallingUid(), null);
+    }
+
+    private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
+        // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
+        // as watcher should not use this to signal if the value is changed.
+        return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
+                watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
+    }
+
+    private void verifyIncomingOp(int op) {
+        if (op >= 0 && op < AppOpsManager._NUM_OP) {
+            // Enforce manage appops permission if it's a restricted read op.
+            if (opRestrictsRead(op)) {
+                mContext.enforcePermission(Manifest.permission.MANAGE_APPOPS,
+                        Binder.getCallingPid(), Binder.getCallingUid(), "verifyIncomingOp");
+            }
+            return;
+        }
+        throw new IllegalArgumentException("Bad operation #" + op);
+    }
+
+    private boolean isIncomingPackageValid(@Nullable String packageName, @UserIdInt int userId) {
+        final int callingUid = Binder.getCallingUid();
+        // Handle the special UIDs that don't have actual packages (audioserver, cameraserver, etc).
+        if (packageName == null || isSpecialPackage(callingUid, packageName)) {
+            return true;
+        }
+
+        // If the package doesn't exist, #verifyAndGetBypass would throw a SecurityException in
+        // the end. Although that exception would be caught and return, we could make it return
+        // early.
+        if (!isPackageExisted(packageName)) {
+            return false;
+        }
+
+        if (getPackageManagerInternal().filterAppAccess(packageName, callingUid, userId)) {
+            Slog.w(TAG, packageName + " not found from " + callingUid);
+            return false;
+        }
+
+        return true;
+    }
+
+    private boolean isSpecialPackage(int callingUid, @Nullable String packageName) {
+        final String resolvedPackage = AppOpsManager.resolvePackageName(callingUid, packageName);
+        return callingUid == Process.SYSTEM_UID
+                || resolveUid(resolvedPackage) != Process.INVALID_UID;
+    }
+
+    private @Nullable UidState getUidStateLocked(int uid, boolean edit) {
+        UidState uidState = mUidStates.get(uid);
+        if (uidState == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState = new UidState(uid);
+            mUidStates.put(uid, uidState);
+        }
+
+        return uidState;
+    }
+
+    @Override
+    public void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible) {
+        synchronized (this) {
+            getUidStateTracker().updateAppWidgetVisibility(uidPackageNames, visible);
+        }
+    }
+
+    /**
+     * @return {@link PackageManagerInternal}
+     */
+    private @NonNull PackageManagerInternal getPackageManagerInternal() {
+        if (mPackageManagerInternal == null) {
+            mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
+        }
+
+        return mPackageManagerInternal;
+    }
+
+    @Override
+    public void verifyPackage(int uid, String packageName) {
+        verifyAndGetBypass(uid, packageName, null);
+    }
+
+    /**
+     * Create a restriction description matching the properties of the package.
+     *
+     * @param pkg The package to create the restriction description for
+     * @return The restriction matching the package
+     */
+    private RestrictionBypass getBypassforPackage(@NonNull AndroidPackage pkg) {
+        return new RestrictionBypass(pkg.getUid() == Process.SYSTEM_UID, pkg.isPrivileged(),
+                mContext.checkPermission(android.Manifest.permission
+                        .EXEMPT_FROM_AUDIO_RECORD_RESTRICTIONS, -1, pkg.getUid())
+                        == PackageManager.PERMISSION_GRANTED);
+    }
+
+    /**
+     * @see #verifyAndGetBypass(int, String, String, String)
+     */
+    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
+            @Nullable String attributionTag) {
+        return verifyAndGetBypass(uid, packageName, attributionTag, null);
+    }
+
+    /**
+     * Verify that package belongs to uid and return the {@link RestrictionBypass bypass
+     * description} for the package, along with a boolean indicating whether the attribution tag is
+     * valid.
+     *
+     * @param uid              The uid the package belongs to
+     * @param packageName      The package the might belong to the uid
+     * @param attributionTag   attribution tag or {@code null} if no need to verify
+     * @param proxyPackageName The proxy package, from which the attribution tag is to be pulled
+     * @return PackageVerificationResult containing {@link RestrictionBypass} and whether the
+     * attribution tag is valid
+     */
+    private @NonNull PackageVerificationResult verifyAndGetBypass(int uid, String packageName,
+            @Nullable String attributionTag, @Nullable String proxyPackageName) {
+        if (uid == Process.ROOT_UID) {
+            // For backwards compatibility, don't check package name for root UID.
+            return new PackageVerificationResult(null,
+                    /* isAttributionTagValid */ true);
+        }
+        if (Process.isSdkSandboxUid(uid)) {
+            // SDK sandbox processes run in their own UID range, but their associated
+            // UID for checks should always be the UID of the package implementing SDK sandbox
+            // service.
+            // TODO: We will need to modify the callers of this function instead, so
+            // modifications and checks against the app ops state are done with the
+            // correct UID.
+            try {
+                final PackageManager pm = mContext.getPackageManager();
+                final String supplementalPackageName = pm.getSdkSandboxPackageName();
+                if (Objects.equals(packageName, supplementalPackageName)) {
+                    uid = pm.getPackageUidAsUser(supplementalPackageName,
+                            PackageManager.PackageInfoFlags.of(0), UserHandle.getUserId(uid));
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                // Shouldn't happen for the supplemental package
+                e.printStackTrace();
+            }
+        }
+
+
+        // Do not check if uid/packageName/attributionTag is already known.
+        synchronized (this) {
+            UidState uidState = mUidStates.get(uid);
+            if (uidState != null && uidState.pkgOps != null) {
+                Ops ops = uidState.pkgOps.get(packageName);
+
+                if (ops != null && (attributionTag == null || ops.knownAttributionTags.contains(
+                        attributionTag)) && ops.bypass != null) {
+                    return new PackageVerificationResult(ops.bypass,
+                            ops.validAttributionTags.contains(attributionTag));
+                }
+            }
+        }
+
+        int callingUid = Binder.getCallingUid();
+
+        // Allow any attribution tag for resolvable uids
+        int pkgUid;
+        if (Objects.equals(packageName, "com.android.shell")) {
+            // Special case for the shell which is a package but should be able
+            // to bypass app attribution tag restrictions.
+            pkgUid = Process.SHELL_UID;
+        } else {
+            pkgUid = resolveUid(packageName);
+        }
+        if (pkgUid != Process.INVALID_UID) {
+            if (pkgUid != UserHandle.getAppId(uid)) {
+                Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
+                        + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
+                String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
+                throw new SecurityException("Specified package \"" + packageName + "\" under uid "
+                        + UserHandle.getAppId(uid) + otherUidMessage);
+            }
+            return new PackageVerificationResult(RestrictionBypass.UNRESTRICTED,
+                    /* isAttributionTagValid */ true);
+        }
+
+        int userId = UserHandle.getUserId(uid);
+        RestrictionBypass bypass = null;
+        boolean isAttributionTagValid = false;
+
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            PackageManagerInternal pmInt = LocalServices.getService(PackageManagerInternal.class);
+            AndroidPackage pkg = pmInt.getPackage(packageName);
+            if (pkg != null) {
+                isAttributionTagValid = isAttributionInPackage(pkg, attributionTag);
+                pkgUid = UserHandle.getUid(userId, UserHandle.getAppId(pkg.getUid()));
+                bypass = getBypassforPackage(pkg);
+            }
+            if (!isAttributionTagValid) {
+                AndroidPackage proxyPkg = proxyPackageName != null
+                        ? pmInt.getPackage(proxyPackageName) : null;
+                // Re-check in proxy.
+                isAttributionTagValid = isAttributionInPackage(proxyPkg, attributionTag);
+                String msg;
+                if (pkg != null && isAttributionTagValid) {
+                    msg = "attributionTag " + attributionTag + " declared in manifest of the proxy"
+                            + " package " + proxyPackageName + ", this is not advised";
+                } else if (pkg != null) {
+                    msg = "attributionTag " + attributionTag + " not declared in manifest of "
+                            + packageName;
+                } else {
+                    msg = "package " + packageName + " not found, can't check for "
+                            + "attributionTag " + attributionTag;
+                }
+
+                try {
+                    if (!mPlatformCompat.isChangeEnabledByPackageName(
+                            SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE, packageName,
+                            userId) || !mPlatformCompat.isChangeEnabledByUid(
+                            SECURITY_EXCEPTION_ON_INVALID_ATTRIBUTION_TAG_CHANGE,
+                            callingUid)) {
+                        // Do not override tags if overriding is not enabled for this package
+                        isAttributionTagValid = true;
+                    }
+                    Slog.e(TAG, msg);
+                } catch (RemoteException neverHappens) {
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+
+        if (pkgUid != uid) {
+            Slog.e(TAG, "Bad call made by uid " + callingUid + ". "
+                    + "Package \"" + packageName + "\" does not belong to uid " + uid + ".");
+            String otherUidMessage = DEBUG ? " but it is really " + pkgUid : " but it is not";
+            throw new SecurityException("Specified package \"" + packageName + "\" under uid " + uid
+                    + otherUidMessage);
+        }
+
+        return new PackageVerificationResult(bypass, isAttributionTagValid);
+    }
+
+    private boolean isAttributionInPackage(@Nullable AndroidPackage pkg,
+            @Nullable String attributionTag) {
+        if (pkg == null) {
+            return false;
+        } else if (attributionTag == null) {
+            return true;
+        }
+        if (pkg.getAttributions() != null) {
+            int numAttributions = pkg.getAttributions().size();
+            for (int i = 0; i < numAttributions; i++) {
+                if (pkg.getAttributions().get(i).getTag().equals(attributionTag)) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    /**
+     * Get (and potentially create) ops.
+     *
+     * @param uid                   The uid the package belongs to
+     * @param packageName           The name of the package
+     * @param attributionTag        attribution tag
+     * @param isAttributionTagValid whether the given attribution tag is valid
+     * @param bypass                When to bypass certain op restrictions (can be null if edit
+        *                              == false)
+     * @param edit                  If an ops does not exist, create the ops?
+     * @return The ops
+     */
+    private Ops getOpsLocked(int uid, String packageName, @Nullable String attributionTag,
+            boolean isAttributionTagValid, @Nullable RestrictionBypass bypass, boolean edit) {
+        UidState uidState = getUidStateLocked(uid, edit);
+        if (uidState == null) {
+            return null;
+        }
+
+        if (uidState.pkgOps == null) {
+            if (!edit) {
+                return null;
+            }
+            uidState.pkgOps = new ArrayMap<>();
+        }
+
+        Ops ops = uidState.pkgOps.get(packageName);
+        if (ops == null) {
+            if (!edit) {
+                return null;
+            }
+            ops = new Ops(packageName, uidState);
+            uidState.pkgOps.put(packageName, ops);
+        }
+
+        if (edit) {
+            if (bypass != null) {
+                ops.bypass = bypass;
+            }
+
+            if (attributionTag != null) {
+                ops.knownAttributionTags.add(attributionTag);
+                if (isAttributionTagValid) {
+                    ops.validAttributionTags.add(attributionTag);
+                } else {
+                    ops.validAttributionTags.remove(attributionTag);
+                }
+            }
+        }
+
+        return ops;
+    }
+
+    @Override
+    public void scheduleWriteLocked() {
+        if (!mWriteScheduled) {
+            mWriteScheduled = true;
+            mHandler.postDelayed(mWriteRunner, WRITE_DELAY);
+        }
+    }
+
+    @Override
+    public void scheduleFastWriteLocked() {
+        if (!mFastWriteScheduled) {
+            mWriteScheduled = true;
+            mFastWriteScheduled = true;
+            mHandler.removeCallbacks(mWriteRunner);
+            mHandler.postDelayed(mWriteRunner, 10 * 1000);
+        }
+    }
+
+    /**
+     * Get the state of an op for a uid.
+     *
+     * @param code                  The code of the op
+     * @param uid                   The uid the of the package
+     * @param packageName           The package name for which to get the state for
+     * @param attributionTag        The attribution tag
+     * @param isAttributionTagValid Whether the given attribution tag is valid
+     * @param bypass                When to bypass certain op restrictions (can be null if edit
+     *                              == false)
+     * @param edit                  Iff {@code true} create the {@link Op} object if not yet created
+     * @return The {@link Op state} of the op
+     */
+    private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, boolean isAttributionTagValid,
+            @Nullable RestrictionBypass bypass, boolean edit) {
+        Ops ops = getOpsLocked(uid, packageName, attributionTag, isAttributionTagValid, bypass,
+                edit);
+        if (ops == null) {
+            return null;
+        }
+        return getOpLocked(ops, code, uid, edit);
+    }
+
+    private Op getOpLocked(Ops ops, int code, int uid, boolean edit) {
+        Op op = ops.get(code);
+        if (op == null) {
+            if (!edit) {
+                return null;
+            }
+            op = new Op(ops.uidState, ops.packageName, code, uid);
+            ops.put(code, op);
+        }
+        if (edit) {
+            scheduleWriteLocked();
+        }
+        return op;
+    }
+
+    private boolean isOpRestrictedDueToSuspend(int code, String packageName, int uid) {
+        if (!ArrayUtils.contains(OPS_RESTRICTED_ON_SUSPEND, code)) {
+            return false;
+        }
+        final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid));
+    }
+
+    private boolean isOpRestrictedLocked(int uid, int code, String packageName,
+            String attributionTag, @Nullable RestrictionBypass appBypass, boolean isCheckOp) {
+        int restrictionSetCount = mOpGlobalRestrictions.size();
+
+        for (int i = 0; i < restrictionSetCount; i++) {
+            ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
+            if (restrictionState.hasRestriction(code)) {
+                return true;
+            }
+        }
+
+        int userHandle = UserHandle.getUserId(uid);
+        restrictionSetCount = mOpUserRestrictions.size();
+
+        for (int i = 0; i < restrictionSetCount; i++) {
+            // For each client, check that the given op is not restricted, or that the given
+            // package is exempt from the restriction.
+            ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
+            if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle,
+                    isCheckOp)) {
+                RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
+                if (opBypass != null) {
+                    // If we are the system, bypass user restrictions for certain codes
+                    synchronized (this) {
+                        if (opBypass.isSystemUid && appBypass != null && appBypass.isSystemUid) {
+                            return false;
+                        }
+                        if (opBypass.isPrivileged && appBypass != null && appBypass.isPrivileged) {
+                            return false;
+                        }
+                        if (opBypass.isRecordAudioRestrictionExcept && appBypass != null
+                                && appBypass.isRecordAudioRestrictionExcept) {
+                            return false;
+                        }
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void readState() {
+        int oldVersion = NO_VERSION;
+        synchronized (mFile) {
+            synchronized (this) {
+                FileInputStream stream;
+                try {
+                    stream = mFile.openRead();
+                } catch (FileNotFoundException e) {
+                    Slog.i(TAG, "No existing app ops " + mFile.getBaseFile() + "; starting empty");
+                    return;
+                }
+                boolean success = false;
+                mUidStates.clear();
+                mAppOpsServiceInterface.clearAllModes();
+                try {
+                    TypedXmlPullParser parser = Xml.resolvePullParser(stream);
+                    int type;
+                    while ((type = parser.next()) != XmlPullParser.START_TAG
+                            && type != XmlPullParser.END_DOCUMENT) {
+                        // Parse next until we reach the start or end
+                    }
+
+                    if (type != XmlPullParser.START_TAG) {
+                        throw new IllegalStateException("no start tag found");
+                    }
+
+                    oldVersion = parser.getAttributeInt(null, "v", NO_VERSION);
+
+                    int outerDepth = parser.getDepth();
+                    while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                            && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                        if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                            continue;
+                        }
+
+                        String tagName = parser.getName();
+                        if (tagName.equals("pkg")) {
+                            readPackage(parser);
+                        } else if (tagName.equals("uid")) {
+                            readUidOps(parser);
+                        } else {
+                            Slog.w(TAG, "Unknown element under <app-ops>: "
+                                    + parser.getName());
+                            XmlUtils.skipCurrentTag(parser);
+                        }
+                    }
+                    success = true;
+                } catch (IllegalStateException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (NullPointerException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (NumberFormatException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (XmlPullParserException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (IOException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } catch (IndexOutOfBoundsException e) {
+                    Slog.w(TAG, "Failed parsing " + e);
+                } finally {
+                    if (!success) {
+                        mUidStates.clear();
+                        mAppOpsServiceInterface.clearAllModes();
+                    }
+                    try {
+                        stream.close();
+                    } catch (IOException e) {
+                    }
+                }
+            }
+        }
+        synchronized (this) {
+            upgradeLocked(oldVersion);
+        }
+    }
+
+    private void upgradeRunAnyInBackgroundLocked() {
+        for (int i = 0; i < mUidStates.size(); i++) {
+            final UidState uidState = mUidStates.valueAt(i);
+            if (uidState == null) {
+                continue;
+            }
+            SparseIntArray opModes = uidState.getNonDefaultUidModes();
+            if (opModes != null) {
+                final int idx = opModes.indexOfKey(AppOpsManager.OP_RUN_IN_BACKGROUND);
+                if (idx >= 0) {
+                    uidState.setUidMode(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND,
+                            opModes.valueAt(idx));
+                }
+            }
+            if (uidState.pkgOps == null) {
+                continue;
+            }
+            boolean changed = false;
+            for (int j = 0; j < uidState.pkgOps.size(); j++) {
+                Ops ops = uidState.pkgOps.valueAt(j);
+                if (ops != null) {
+                    final Op op = ops.get(AppOpsManager.OP_RUN_IN_BACKGROUND);
+                    if (op != null && op.getMode() != AppOpsManager.opToDefaultMode(op.op)) {
+                        final Op copy = new Op(op.uidState, op.packageName,
+                                AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, uidState.uid);
+                        copy.setMode(op.getMode());
+                        ops.put(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, copy);
+                        changed = true;
+                    }
+                }
+            }
+            if (changed) {
+                uidState.evalForegroundOps();
+            }
+        }
+    }
+
+    private void upgradeLocked(int oldVersion) {
+        if (oldVersion >= CURRENT_VERSION) {
+            return;
+        }
+        Slog.d(TAG, "Upgrading app-ops xml from version " + oldVersion + " to " + CURRENT_VERSION);
+        switch (oldVersion) {
+            case NO_VERSION:
+                upgradeRunAnyInBackgroundLocked();
+                // fall through
+            case 1:
+                // for future upgrades
+        }
+        scheduleFastWriteLocked();
+    }
+
+    private void readUidOps(TypedXmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        final int uid = parser.getAttributeInt(null, "n");
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("op")) {
+                final int code = parser.getAttributeInt(null, "n");
+                final int mode = parser.getAttributeInt(null, "m");
+                setUidMode(code, uid, mode, null);
+            } else {
+                Slog.w(TAG, "Unknown element under <uid-ops>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
+    private void readPackage(TypedXmlPullParser parser)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        String pkgName = parser.getAttributeValue(null, "n");
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+
+            String tagName = parser.getName();
+            if (tagName.equals("uid")) {
+                readUid(parser, pkgName);
+            } else {
+                Slog.w(TAG, "Unknown element under <pkg>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+    }
+
+    private void readUid(TypedXmlPullParser parser, String pkgName)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        int uid = parser.getAttributeInt(null, "n");
+        final UidState uidState = getUidStateLocked(uid, true);
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals("op")) {
+                readOp(parser, uidState, pkgName);
+            } else {
+                Slog.w(TAG, "Unknown element under <pkg>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+        uidState.evalForegroundOps();
+    }
+
+    private void readAttributionOp(TypedXmlPullParser parser, @NonNull Op parent,
+            @Nullable String attribution)
+            throws NumberFormatException, IOException, XmlPullParserException {
+        final AttributedOp attributedOp = parent.getOrCreateAttribution(parent, attribution);
+
+        final long key = parser.getAttributeLong(null, "n");
+        final int uidState = extractUidStateFromKey(key);
+        final int opFlags = extractFlagsFromKey(key);
+
+        final long accessTime = parser.getAttributeLong(null, "t", 0);
+        final long rejectTime = parser.getAttributeLong(null, "r", 0);
+        final long accessDuration = parser.getAttributeLong(null, "d", -1);
+        final String proxyPkg = XmlUtils.readStringAttribute(parser, "pp");
+        final int proxyUid = parser.getAttributeInt(null, "pu", Process.INVALID_UID);
+        final String proxyAttributionTag = XmlUtils.readStringAttribute(parser, "pc");
+
+        if (accessTime > 0) {
+            attributedOp.accessed(accessTime, accessDuration, proxyUid, proxyPkg,
+                    proxyAttributionTag, uidState, opFlags);
+        }
+        if (rejectTime > 0) {
+            attributedOp.rejected(rejectTime, uidState, opFlags);
+        }
+    }
+
+    private void readOp(TypedXmlPullParser parser,
+            @NonNull UidState uidState, @NonNull String pkgName)
+            throws NumberFormatException, XmlPullParserException, IOException {
+        int opCode = parser.getAttributeInt(null, "n");
+        Op op = new Op(uidState, pkgName, opCode, uidState.uid);
+
+        final int mode = parser.getAttributeInt(null, "m", AppOpsManager.opToDefaultMode(op.op));
+        op.setMode(mode);
+
+        int outerDepth = parser.getDepth();
+        int type;
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals("st")) {
+                readAttributionOp(parser, op, XmlUtils.readStringAttribute(parser, "id"));
+            } else {
+                Slog.w(TAG, "Unknown element under <op>: "
+                        + parser.getName());
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+
+        if (uidState.pkgOps == null) {
+            uidState.pkgOps = new ArrayMap<>();
+        }
+        Ops ops = uidState.pkgOps.get(pkgName);
+        if (ops == null) {
+            ops = new Ops(pkgName, uidState);
+            uidState.pkgOps.put(pkgName, ops);
+        }
+        ops.put(op.op, op);
+    }
+
+    @Override
+    public void writeState() {
+        synchronized (mFile) {
+            FileOutputStream stream;
+            try {
+                stream = mFile.startWrite();
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to write state: " + e);
+                return;
+            }
+
+            List<AppOpsManager.PackageOps> allOps = getPackagesForOps(null);
+
+            try {
+                TypedXmlSerializer out = Xml.resolveSerializer(stream);
+                out.startDocument(null, true);
+                out.startTag(null, "app-ops");
+                out.attributeInt(null, "v", CURRENT_VERSION);
+
+                SparseArray<SparseIntArray> uidStatesClone;
+                synchronized (this) {
+                    uidStatesClone = new SparseArray<>(mUidStates.size());
+
+                    final int uidStateCount = mUidStates.size();
+                    for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                        UidState uidState = mUidStates.valueAt(uidStateNum);
+                        int uid = mUidStates.keyAt(uidStateNum);
+
+                        SparseIntArray opModes = uidState.getNonDefaultUidModes();
+                        if (opModes != null && opModes.size() > 0) {
+                            uidStatesClone.put(uid, opModes);
+                        }
+                    }
+                }
+
+                final int uidStateCount = uidStatesClone.size();
+                for (int uidStateNum = 0; uidStateNum < uidStateCount; uidStateNum++) {
+                    SparseIntArray opModes = uidStatesClone.valueAt(uidStateNum);
+                    if (opModes != null && opModes.size() > 0) {
+                        out.startTag(null, "uid");
+                        out.attributeInt(null, "n", uidStatesClone.keyAt(uidStateNum));
+                        final int opCount = opModes.size();
+                        for (int opCountNum = 0; opCountNum < opCount; opCountNum++) {
+                            final int op = opModes.keyAt(opCountNum);
+                            final int mode = opModes.valueAt(opCountNum);
+                            out.startTag(null, "op");
+                            out.attributeInt(null, "n", op);
+                            out.attributeInt(null, "m", mode);
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
+                    }
+                }
+
+                if (allOps != null) {
+                    String lastPkg = null;
+                    for (int i = 0; i < allOps.size(); i++) {
+                        AppOpsManager.PackageOps pkg = allOps.get(i);
+                        if (!Objects.equals(pkg.getPackageName(), lastPkg)) {
+                            if (lastPkg != null) {
+                                out.endTag(null, "pkg");
+                            }
+                            lastPkg = pkg.getPackageName();
+                            if (lastPkg != null) {
+                                out.startTag(null, "pkg");
+                                out.attribute(null, "n", lastPkg);
+                            }
+                        }
+                        out.startTag(null, "uid");
+                        out.attributeInt(null, "n", pkg.getUid());
+                        List<AppOpsManager.OpEntry> ops = pkg.getOps();
+                        for (int j = 0; j < ops.size(); j++) {
+                            AppOpsManager.OpEntry op = ops.get(j);
+                            out.startTag(null, "op");
+                            out.attributeInt(null, "n", op.getOp());
+                            if (op.getMode() != AppOpsManager.opToDefaultMode(op.getOp())) {
+                                out.attributeInt(null, "m", op.getMode());
+                            }
+
+                            for (String attributionTag : op.getAttributedOpEntries().keySet()) {
+                                final AttributedOpEntry attribution =
+                                        op.getAttributedOpEntries().get(attributionTag);
+
+                                final ArraySet<Long> keys = attribution.collectKeys();
+
+                                final int keyCount = keys.size();
+                                for (int k = 0; k < keyCount; k++) {
+                                    final long key = keys.valueAt(k);
+
+                                    final int uidState = AppOpsManager.extractUidStateFromKey(key);
+                                    final int flags = AppOpsManager.extractFlagsFromKey(key);
+
+                                    final long accessTime = attribution.getLastAccessTime(uidState,
+                                            uidState, flags);
+                                    final long rejectTime = attribution.getLastRejectTime(uidState,
+                                            uidState, flags);
+                                    final long accessDuration = attribution.getLastDuration(
+                                            uidState, uidState, flags);
+                                    // Proxy information for rejections is not backed up
+                                    final OpEventProxyInfo proxy = attribution.getLastProxyInfo(
+                                            uidState, uidState, flags);
+
+                                    if (accessTime <= 0 && rejectTime <= 0 && accessDuration <= 0
+                                            && proxy == null) {
+                                        continue;
+                                    }
+
+                                    String proxyPkg = null;
+                                    String proxyAttributionTag = null;
+                                    int proxyUid = Process.INVALID_UID;
+                                    if (proxy != null) {
+                                        proxyPkg = proxy.getPackageName();
+                                        proxyAttributionTag = proxy.getAttributionTag();
+                                        proxyUid = proxy.getUid();
+                                    }
+
+                                    out.startTag(null, "st");
+                                    if (attributionTag != null) {
+                                        out.attribute(null, "id", attributionTag);
+                                    }
+                                    out.attributeLong(null, "n", key);
+                                    if (accessTime > 0) {
+                                        out.attributeLong(null, "t", accessTime);
+                                    }
+                                    if (rejectTime > 0) {
+                                        out.attributeLong(null, "r", rejectTime);
+                                    }
+                                    if (accessDuration > 0) {
+                                        out.attributeLong(null, "d", accessDuration);
+                                    }
+                                    if (proxyPkg != null) {
+                                        out.attribute(null, "pp", proxyPkg);
+                                    }
+                                    if (proxyAttributionTag != null) {
+                                        out.attribute(null, "pc", proxyAttributionTag);
+                                    }
+                                    if (proxyUid >= 0) {
+                                        out.attributeInt(null, "pu", proxyUid);
+                                    }
+                                    out.endTag(null, "st");
+                                }
+                            }
+
+                            out.endTag(null, "op");
+                        }
+                        out.endTag(null, "uid");
+                    }
+                    if (lastPkg != null) {
+                        out.endTag(null, "pkg");
+                    }
+                }
+
+                out.endTag(null, "app-ops");
+                out.endDocument();
+                mFile.finishWrite(stream);
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to write state, restoring backup.", e);
+                mFile.failWrite(stream);
+            }
+        }
+        mHistoricalRegistry.writeAndClearDiscreteHistory();
+    }
+
+    private void dumpHelp(PrintWriter pw) {
+        pw.println("AppOps service (appops) dump options:");
+        pw.println("  -h");
+        pw.println("    Print this help text.");
+        pw.println("  --op [OP]");
+        pw.println("    Limit output to data associated with the given app op code.");
+        pw.println("  --mode [MODE]");
+        pw.println("    Limit output to data associated with the given app op mode.");
+        pw.println("  --package [PACKAGE]");
+        pw.println("    Limit output to data associated with the given package name.");
+        pw.println("  --attributionTag [attributionTag]");
+        pw.println("    Limit output to data associated with the given attribution tag.");
+        pw.println("  --include-discrete [n]");
+        pw.println("    Include discrete ops limited to n per dimension. Use zero for no limit.");
+        pw.println("  --watchers");
+        pw.println("    Only output the watcher sections.");
+        pw.println("  --history");
+        pw.println("    Only output history.");
+        pw.println("  --uid-state-changes");
+        pw.println("    Include logs about uid state changes.");
+    }
+
+    private void dumpStatesLocked(@NonNull PrintWriter pw, @Nullable String filterAttributionTag,
+            @HistoricalOpsRequestFilter int filter, long nowElapsed, @NonNull Op op, long now,
+            @NonNull SimpleDateFormat sdf, @NonNull Date date, @NonNull String prefix) {
+        final int numAttributions = op.mAttributions.size();
+        for (int i = 0; i < numAttributions; i++) {
+            if ((filter & FILTER_BY_ATTRIBUTION_TAG) != 0 && !Objects.equals(
+                    op.mAttributions.keyAt(i), filterAttributionTag)) {
+                continue;
+            }
+
+            pw.print(prefix + op.mAttributions.keyAt(i) + "=[\n");
+            dumpStatesLocked(pw, nowElapsed, op, op.mAttributions.keyAt(i), now, sdf, date,
+                    prefix + "  ");
+            pw.print(prefix + "]\n");
+        }
+    }
+
+    private void dumpStatesLocked(@NonNull PrintWriter pw, long nowElapsed, @NonNull Op op,
+            @Nullable String attributionTag, long now, @NonNull SimpleDateFormat sdf,
+            @NonNull Date date, @NonNull String prefix) {
+
+        final AttributedOpEntry entry = op.createSingleAttributionEntryLocked(
+                attributionTag).getAttributedOpEntries().get(attributionTag);
+
+        final ArraySet<Long> keys = entry.collectKeys();
+
+        final int keyCount = keys.size();
+        for (int k = 0; k < keyCount; k++) {
+            final long key = keys.valueAt(k);
+
+            final int uidState = AppOpsManager.extractUidStateFromKey(key);
+            final int flags = AppOpsManager.extractFlagsFromKey(key);
+
+            final long accessTime = entry.getLastAccessTime(uidState, uidState, flags);
+            final long rejectTime = entry.getLastRejectTime(uidState, uidState, flags);
+            final long accessDuration = entry.getLastDuration(uidState, uidState, flags);
+            final OpEventProxyInfo proxy = entry.getLastProxyInfo(uidState, uidState, flags);
+
+            String proxyPkg = null;
+            String proxyAttributionTag = null;
+            int proxyUid = Process.INVALID_UID;
+            if (proxy != null) {
+                proxyPkg = proxy.getPackageName();
+                proxyAttributionTag = proxy.getAttributionTag();
+                proxyUid = proxy.getUid();
+            }
+
+            if (accessTime > 0) {
+                pw.print(prefix);
+                pw.print("Access: ");
+                pw.print(AppOpsManager.keyToString(key));
+                pw.print(" ");
+                date.setTime(accessTime);
+                pw.print(sdf.format(date));
+                pw.print(" (");
+                TimeUtils.formatDuration(accessTime - now, pw);
+                pw.print(")");
+                if (accessDuration > 0) {
+                    pw.print(" duration=");
+                    TimeUtils.formatDuration(accessDuration, pw);
+                }
+                if (proxyUid >= 0) {
+                    pw.print(" proxy[");
+                    pw.print("uid=");
+                    pw.print(proxyUid);
+                    pw.print(", pkg=");
+                    pw.print(proxyPkg);
+                    pw.print(", attributionTag=");
+                    pw.print(proxyAttributionTag);
+                    pw.print("]");
+                }
+                pw.println();
+            }
+
+            if (rejectTime > 0) {
+                pw.print(prefix);
+                pw.print("Reject: ");
+                pw.print(AppOpsManager.keyToString(key));
+                date.setTime(rejectTime);
+                pw.print(sdf.format(date));
+                pw.print(" (");
+                TimeUtils.formatDuration(rejectTime - now, pw);
+                pw.print(")");
+                if (proxyUid >= 0) {
+                    pw.print(" proxy[");
+                    pw.print("uid=");
+                    pw.print(proxyUid);
+                    pw.print(", pkg=");
+                    pw.print(proxyPkg);
+                    pw.print(", attributionTag=");
+                    pw.print(proxyAttributionTag);
+                    pw.print("]");
+                }
+                pw.println();
+            }
+        }
+
+        final AttributedOp attributedOp = op.mAttributions.get(attributionTag);
+        if (attributedOp.isRunning()) {
+            long earliestElapsedTime = Long.MAX_VALUE;
+            long maxNumStarts = 0;
+            int numInProgressEvents = attributedOp.mInProgressEvents.size();
+            for (int i = 0; i < numInProgressEvents; i++) {
+                AttributedOp.InProgressStartOpEvent event =
+                        attributedOp.mInProgressEvents.valueAt(i);
+
+                earliestElapsedTime = Math.min(earliestElapsedTime, event.getStartElapsedTime());
+                maxNumStarts = Math.max(maxNumStarts, event.mNumUnfinishedStarts);
+            }
+
+            pw.print(prefix + "Running start at: ");
+            TimeUtils.formatDuration(nowElapsed - earliestElapsedTime, pw);
+            pw.println();
+
+            if (maxNumStarts > 1) {
+                pw.print(prefix + "startNesting=");
+                pw.println(maxNumStarts);
+            }
+        }
+    }
+
+    @NeverCompile // Avoid size overhead of debugging code.
+    @Override
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)) return;
+
+        int dumpOp = OP_NONE;
+        String dumpPackage = null;
+        String dumpAttributionTag = null;
+        int dumpUid = Process.INVALID_UID;
+        int dumpMode = -1;
+        boolean dumpWatchers = false;
+        // TODO ntmyren: Remove the dumpHistory and dumpFilter
+        boolean dumpHistory = false;
+        boolean includeDiscreteOps = false;
+        boolean dumpUidStateChangeLogs = false;
+        int nDiscreteOps = 10;
+        @HistoricalOpsRequestFilter int dumpFilter = 0;
+        boolean dumpAll = false;
+
+        if (args != null) {
+            for (int i = 0; i < args.length; i++) {
+                String arg = args[i];
+                if ("-h".equals(arg)) {
+                    dumpHelp(pw);
+                    return;
+                } else if ("-a".equals(arg)) {
+                    // dump all data
+                    dumpAll = true;
+                } else if ("--op".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --op option");
+                        return;
+                    }
+                    dumpOp = AppOpsService.Shell.strOpToOp(args[i], pw);
+                    dumpFilter |= FILTER_BY_OP_NAMES;
+                    if (dumpOp < 0) {
+                        return;
+                    }
+                } else if ("--package".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --package option");
+                        return;
+                    }
+                    dumpPackage = args[i];
+                    dumpFilter |= FILTER_BY_PACKAGE_NAME;
+                    try {
+                        dumpUid = AppGlobals.getPackageManager().getPackageUid(dumpPackage,
+                                PackageManager.MATCH_KNOWN_PACKAGES | PackageManager.MATCH_INSTANT,
+                                0);
+                    } catch (RemoteException e) {
+                    }
+                    if (dumpUid < 0) {
+                        pw.println("Unknown package: " + dumpPackage);
+                        return;
+                    }
+                    dumpUid = UserHandle.getAppId(dumpUid);
+                    dumpFilter |= FILTER_BY_UID;
+                } else if ("--attributionTag".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --attributionTag option");
+                        return;
+                    }
+                    dumpAttributionTag = args[i];
+                    dumpFilter |= FILTER_BY_ATTRIBUTION_TAG;
+                } else if ("--mode".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --mode option");
+                        return;
+                    }
+                    dumpMode = AppOpsService.Shell.strModeToMode(args[i], pw);
+                    if (dumpMode < 0) {
+                        return;
+                    }
+                } else if ("--watchers".equals(arg)) {
+                    dumpWatchers = true;
+                } else if ("--include-discrete".equals(arg)) {
+                    i++;
+                    if (i >= args.length) {
+                        pw.println("No argument for --include-discrete option");
+                        return;
+                    }
+                    try {
+                        nDiscreteOps = Integer.valueOf(args[i]);
+                    } catch (NumberFormatException e) {
+                        pw.println("Wrong parameter: " + args[i]);
+                        return;
+                    }
+                    includeDiscreteOps = true;
+                } else if ("--history".equals(arg)) {
+                    dumpHistory = true;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-') {
+                    pw.println("Unknown option: " + arg);
+                    return;
+                } else if ("--uid-state-changes".equals(arg)) {
+                    dumpUidStateChangeLogs = true;
+                } else {
+                    pw.println("Unknown command: " + arg);
+                    return;
+                }
+            }
+        }
+
+        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+        final Date date = new Date();
+        synchronized (this) {
+            pw.println("Current AppOps Service state:");
+            if (!dumpHistory && !dumpWatchers) {
+                mConstants.dump(pw);
+            }
+            pw.println();
+            final long now = System.currentTimeMillis();
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            boolean needSep = false;
+            if (dumpFilter == 0 && dumpMode < 0 && mProfileOwners != null && !dumpWatchers
+                    && !dumpHistory) {
+                pw.println("  Profile owners:");
+                for (int poi = 0; poi < mProfileOwners.size(); poi++) {
+                    pw.print("    User #");
+                    pw.print(mProfileOwners.keyAt(poi));
+                    pw.print(": ");
+                    UserHandle.formatUid(pw, mProfileOwners.valueAt(poi));
+                    pw.println();
+                }
+                pw.println();
+            }
+
+            if (!dumpHistory) {
+                needSep |= mAppOpsServiceInterface.dumpListeners(dumpOp, dumpUid, dumpPackage, pw);
+            }
+
+            if (mModeWatchers.size() > 0 && dumpOp < 0 && !dumpHistory) {
+                boolean printedHeader = false;
+                for (int i = 0; i < mModeWatchers.size(); i++) {
+                    final ModeCallback cb = mModeWatchers.valueAt(i);
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.getWatchingUid())) {
+                        continue;
+                    }
+                    needSep = true;
+                    if (!printedHeader) {
+                        pw.println("  All op mode watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(mModeWatchers.keyAt(i))));
+                    pw.print(": ");
+                    pw.println(cb);
+                }
+            }
+            if (mActiveWatchers.size() > 0 && dumpMode < 0) {
+                needSep = true;
+                boolean printedHeader = false;
+                for (int watcherNum = 0; watcherNum < mActiveWatchers.size(); watcherNum++) {
+                    final SparseArray<ActiveCallback> activeWatchers =
+                            mActiveWatchers.valueAt(watcherNum);
+                    if (activeWatchers.size() <= 0) {
+                        continue;
+                    }
+                    final ActiveCallback cb = activeWatchers.valueAt(0);
+                    if (dumpOp >= 0 && activeWatchers.indexOfKey(dumpOp) < 0) {
+                        continue;
+                    }
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    if (!printedHeader) {
+                        pw.println("  All op active watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(
+                            mActiveWatchers.keyAt(watcherNum))));
+                    pw.println(" ->");
+                    pw.print("        [");
+                    final int opCount = activeWatchers.size();
+                    for (int opNum = 0; opNum < opCount; opNum++) {
+                        if (opNum > 0) {
+                            pw.print(' ');
+                        }
+                        pw.print(AppOpsManager.opToName(activeWatchers.keyAt(opNum)));
+                        if (opNum < opCount - 1) {
+                            pw.print(',');
+                        }
+                    }
+                    pw.println("]");
+                    pw.print("        ");
+                    pw.println(cb);
+                }
+            }
+            if (mStartedWatchers.size() > 0 && dumpMode < 0) {
+                needSep = true;
+                boolean printedHeader = false;
+
+                final int watchersSize = mStartedWatchers.size();
+                for (int watcherNum = 0; watcherNum < watchersSize; watcherNum++) {
+                    final SparseArray<StartedCallback> startedWatchers =
+                            mStartedWatchers.valueAt(watcherNum);
+                    if (startedWatchers.size() <= 0) {
+                        continue;
+                    }
+
+                    final StartedCallback cb = startedWatchers.valueAt(0);
+                    if (dumpOp >= 0 && startedWatchers.indexOfKey(dumpOp) < 0) {
+                        continue;
+                    }
+
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+
+                    if (!printedHeader) {
+                        pw.println("  All op started watchers:");
+                        printedHeader = true;
+                    }
+
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(
+                            mStartedWatchers.keyAt(watcherNum))));
+                    pw.println(" ->");
+
+                    pw.print("        [");
+                    final int opCount = startedWatchers.size();
+                    for (int opNum = 0; opNum < opCount; opNum++) {
+                        if (opNum > 0) {
+                            pw.print(' ');
+                        }
+
+                        pw.print(AppOpsManager.opToName(startedWatchers.keyAt(opNum)));
+                        if (opNum < opCount - 1) {
+                            pw.print(',');
+                        }
+                    }
+                    pw.println("]");
+
+                    pw.print("        ");
+                    pw.println(cb);
+                }
+            }
+            if (mNotedWatchers.size() > 0 && dumpMode < 0) {
+                needSep = true;
+                boolean printedHeader = false;
+                for (int watcherNum = 0; watcherNum < mNotedWatchers.size(); watcherNum++) {
+                    final SparseArray<NotedCallback> notedWatchers =
+                            mNotedWatchers.valueAt(watcherNum);
+                    if (notedWatchers.size() <= 0) {
+                        continue;
+                    }
+                    final NotedCallback cb = notedWatchers.valueAt(0);
+                    if (dumpOp >= 0 && notedWatchers.indexOfKey(dumpOp) < 0) {
+                        continue;
+                    }
+                    if (dumpPackage != null
+                            && dumpUid != UserHandle.getAppId(cb.mWatchingUid)) {
+                        continue;
+                    }
+                    if (!printedHeader) {
+                        pw.println("  All op noted watchers:");
+                        printedHeader = true;
+                    }
+                    pw.print("    ");
+                    pw.print(Integer.toHexString(System.identityHashCode(
+                            mNotedWatchers.keyAt(watcherNum))));
+                    pw.println(" ->");
+                    pw.print("        [");
+                    final int opCount = notedWatchers.size();
+                    for (int opNum = 0; opNum < opCount; opNum++) {
+                        if (opNum > 0) {
+                            pw.print(' ');
+                        }
+                        pw.print(AppOpsManager.opToName(notedWatchers.keyAt(opNum)));
+                        if (opNum < opCount - 1) {
+                            pw.print(',');
+                        }
+                    }
+                    pw.println("]");
+                    pw.print("        ");
+                    pw.println(cb);
+                }
+            }
+            if (needSep) {
+                pw.println();
+            }
+            for (int i = 0; i < mUidStates.size(); i++) {
+                UidState uidState = mUidStates.valueAt(i);
+                final SparseIntArray opModes = uidState.getNonDefaultUidModes();
+                final ArrayMap<String, Ops> pkgOps = uidState.pkgOps;
+
+                if (dumpWatchers || dumpHistory) {
+                    continue;
+                }
+                if (dumpOp >= 0 || dumpPackage != null || dumpMode >= 0) {
+                    boolean hasOp = dumpOp < 0 || (opModes != null
+                            && opModes.indexOfKey(dumpOp) >= 0);
+                    boolean hasPackage = dumpPackage == null || dumpUid == mUidStates.keyAt(i);
+                    boolean hasMode = dumpMode < 0;
+                    if (!hasMode && opModes != null) {
+                        for (int opi = 0; !hasMode && opi < opModes.size(); opi++) {
+                            if (opModes.valueAt(opi) == dumpMode) {
+                                hasMode = true;
+                            }
+                        }
+                    }
+                    if (pkgOps != null) {
+                        for (int pkgi = 0;
+                                (!hasOp || !hasPackage || !hasMode) && pkgi < pkgOps.size();
+                                pkgi++) {
+                            Ops ops = pkgOps.valueAt(pkgi);
+                            if (!hasOp && ops != null && ops.indexOfKey(dumpOp) >= 0) {
+                                hasOp = true;
+                            }
+                            if (!hasMode) {
+                                for (int opi = 0; !hasMode && opi < ops.size(); opi++) {
+                                    if (ops.valueAt(opi).getMode() == dumpMode) {
+                                        hasMode = true;
+                                    }
+                                }
+                            }
+                            if (!hasPackage && dumpPackage.equals(ops.packageName)) {
+                                hasPackage = true;
+                            }
+                        }
+                    }
+                    if (uidState.foregroundOps != null && !hasOp) {
+                        if (uidState.foregroundOps.indexOfKey(dumpOp) > 0) {
+                            hasOp = true;
+                        }
+                    }
+                    if (!hasOp || !hasPackage || !hasMode) {
+                        continue;
+                    }
+                }
+
+                pw.print("  Uid ");
+                UserHandle.formatUid(pw, uidState.uid);
+                pw.println(":");
+                uidState.dump(pw, nowElapsed);
+                if (uidState.foregroundOps != null && (dumpMode < 0
+                        || dumpMode == AppOpsManager.MODE_FOREGROUND)) {
+                    pw.println("    foregroundOps:");
+                    for (int j = 0; j < uidState.foregroundOps.size(); j++) {
+                        if (dumpOp >= 0 && dumpOp != uidState.foregroundOps.keyAt(j)) {
+                            continue;
+                        }
+                        pw.print("      ");
+                        pw.print(AppOpsManager.opToName(uidState.foregroundOps.keyAt(j)));
+                        pw.print(": ");
+                        pw.println(uidState.foregroundOps.valueAt(j) ? "WATCHER" : "SILENT");
+                    }
+                    pw.print("    hasForegroundWatchers=");
+                    pw.println(uidState.hasForegroundWatchers);
+                }
+                needSep = true;
+
+                if (opModes != null) {
+                    final int opModeCount = opModes.size();
+                    for (int j = 0; j < opModeCount; j++) {
+                        final int code = opModes.keyAt(j);
+                        final int mode = opModes.valueAt(j);
+                        if (dumpOp >= 0 && dumpOp != code) {
+                            continue;
+                        }
+                        if (dumpMode >= 0 && dumpMode != mode) {
+                            continue;
+                        }
+                        pw.print("      ");
+                        pw.print(AppOpsManager.opToName(code));
+                        pw.print(": mode=");
+                        pw.println(AppOpsManager.modeToName(mode));
+                    }
+                }
+
+                if (pkgOps == null) {
+                    continue;
+                }
+
+                for (int pkgi = 0; pkgi < pkgOps.size(); pkgi++) {
+                    final Ops ops = pkgOps.valueAt(pkgi);
+                    if (dumpPackage != null && !dumpPackage.equals(ops.packageName)) {
+                        continue;
+                    }
+                    boolean printedPackage = false;
+                    for (int j = 0; j < ops.size(); j++) {
+                        final Op op = ops.valueAt(j);
+                        final int opCode = op.op;
+                        if (dumpOp >= 0 && dumpOp != opCode) {
+                            continue;
+                        }
+                        if (dumpMode >= 0 && dumpMode != op.getMode()) {
+                            continue;
+                        }
+                        if (!printedPackage) {
+                            pw.print("    Package ");
+                            pw.print(ops.packageName);
+                            pw.println(":");
+                            printedPackage = true;
+                        }
+                        pw.print("      ");
+                        pw.print(AppOpsManager.opToName(opCode));
+                        pw.print(" (");
+                        pw.print(AppOpsManager.modeToName(op.getMode()));
+                        final int switchOp = AppOpsManager.opToSwitch(opCode);
+                        if (switchOp != opCode) {
+                            pw.print(" / switch ");
+                            pw.print(AppOpsManager.opToName(switchOp));
+                            final Op switchObj = ops.get(switchOp);
+                            int mode = switchObj == null
+                                    ? AppOpsManager.opToDefaultMode(switchOp) : switchObj.getMode();
+                            pw.print("=");
+                            pw.print(AppOpsManager.modeToName(mode));
+                        }
+                        pw.println("): ");
+                        dumpStatesLocked(pw, dumpAttributionTag, dumpFilter, nowElapsed, op, now,
+                                sdf, date, "        ");
+                    }
+                }
+            }
+            if (needSep) {
+                pw.println();
+            }
+
+            boolean showUserRestrictions = !(dumpMode < 0 && !dumpWatchers && !dumpHistory);
+            mAppOpsRestrictions.dumpRestrictions(pw, dumpOp, dumpPackage, showUserRestrictions);
+
+            if (dumpAll || dumpUidStateChangeLogs) {
+                pw.println();
+                pw.println("Uid State Changes Event Log:");
+                getUidStateTracker().dumpEvents(pw);
+            }
+        }
+
+        // Must not hold the appops lock
+        if (dumpHistory && !dumpWatchers) {
+            mHistoricalRegistry.dump("  ", pw, dumpUid, dumpPackage, dumpAttributionTag, dumpOp,
+                    dumpFilter);
+        }
+        if (includeDiscreteOps) {
+            pw.println("Discrete accesses: ");
+            mHistoricalRegistry.dumpDiscreteData(pw, dumpUid, dumpPackage, dumpAttributionTag,
+                    dumpFilter, dumpOp, sdf, date, "  ", nDiscreteOps);
+        }
+    }
+
+    @Override
+    public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
+        checkSystemUid("setUserRestrictions");
+        Objects.requireNonNull(restrictions);
+        Objects.requireNonNull(token);
+        for (int i = 0; i < AppOpsManager._NUM_OP; i++) {
+            String restriction = AppOpsManager.opToRestriction(i);
+            if (restriction != null) {
+                setUserRestrictionNoCheck(i, restrictions.getBoolean(restriction, false), token,
+                        userHandle, null);
+            }
+        }
+    }
+
+    @Override
+    public void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
+            PackageTagsList excludedPackageTags) {
+        if (Binder.getCallingPid() != Process.myPid()) {
+            mContext.enforcePermission(Manifest.permission.MANAGE_APP_OPS_RESTRICTIONS,
+                    Binder.getCallingPid(), Binder.getCallingUid(), null);
+        }
+        if (userHandle != UserHandle.getCallingUserId()) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .INTERACT_ACROSS_USERS_FULL) != PackageManager.PERMISSION_GRANTED
+                    && mContext.checkCallingOrSelfPermission(Manifest.permission
+                    .INTERACT_ACROSS_USERS) != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Need INTERACT_ACROSS_USERS_FULL or"
+                        + " INTERACT_ACROSS_USERS to interact cross user ");
+            }
+        }
+        verifyIncomingOp(code);
+        Objects.requireNonNull(token);
+        setUserRestrictionNoCheck(code, restricted, token, userHandle, excludedPackageTags);
+    }
+
+    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
+            int userHandle, PackageTagsList excludedPackageTags) {
+        synchronized (AppOpsServiceImpl.this) {
+            ClientUserRestrictionState restrictionState = mOpUserRestrictions.get(token);
+
+            if (restrictionState == null) {
+                try {
+                    restrictionState = new ClientUserRestrictionState(token);
+                } catch (RemoteException e) {
+                    return;
+                }
+                mOpUserRestrictions.put(token, restrictionState);
+            }
+
+            if (restrictionState.setRestriction(code, restricted, excludedPackageTags,
+                    userHandle)) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsServiceImpl::notifyWatchersOfChange, this, code, UID_ANY));
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsServiceImpl::updateStartedOpModeForUser, this, code,
+                        restricted, userHandle));
+            }
+
+            if (restrictionState.isDefault()) {
+                mOpUserRestrictions.remove(token);
+                restrictionState.destroy();
+            }
+        }
+    }
+
+    @Override
+    public void setGlobalRestriction(int code, boolean restricted, IBinder token) {
+        if (Binder.getCallingPid() != Process.myPid()) {
+            throw new SecurityException("Only the system can set global restrictions");
+        }
+
+        synchronized (this) {
+            ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.get(token);
+
+            if (restrictionState == null) {
+                try {
+                    restrictionState = new ClientGlobalRestrictionState(token);
+                } catch (RemoteException e) {
+                    return;
+                }
+                mOpGlobalRestrictions.put(token, restrictionState);
+            }
+
+            if (restrictionState.setRestriction(code, restricted)) {
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsServiceImpl::notifyWatchersOfChange, this, code, UID_ANY));
+                mHandler.sendMessage(PooledLambda.obtainMessage(
+                        AppOpsServiceImpl::updateStartedOpModeForUser, this, code,
+                        restricted, UserHandle.USER_ALL));
+            }
+
+            if (restrictionState.isDefault()) {
+                mOpGlobalRestrictions.remove(token);
+                restrictionState.destroy();
+            }
+        }
+    }
+
+    @Override
+    public int getOpRestrictionCount(int code, UserHandle user, String pkg,
+            String attributionTag) {
+        int number = 0;
+        synchronized (this) {
+            int numRestrictions = mOpUserRestrictions.size();
+            for (int i = 0; i < numRestrictions; i++) {
+                if (mOpUserRestrictions.valueAt(i)
+                        .hasRestriction(code, pkg, attributionTag, user.getIdentifier(),
+                                false)) {
+                    number++;
+                }
+            }
+
+            numRestrictions = mOpGlobalRestrictions.size();
+            for (int i = 0; i < numRestrictions; i++) {
+                if (mOpGlobalRestrictions.valueAt(i).hasRestriction(code)) {
+                    number++;
+                }
+            }
+        }
+
+        return number;
+    }
+
+    private void updateStartedOpModeForUser(int code, boolean restricted, int userId) {
+        synchronized (AppOpsServiceImpl.this) {
+            int numUids = mUidStates.size();
+            for (int uidNum = 0; uidNum < numUids; uidNum++) {
+                int uid = mUidStates.keyAt(uidNum);
+                if (userId != UserHandle.USER_ALL && UserHandle.getUserId(uid) != userId) {
+                    continue;
+                }
+                updateStartedOpModeForUidLocked(code, restricted, uid);
+            }
+        }
+    }
+
+    private void updateStartedOpModeForUidLocked(int code, boolean restricted, int uid) {
+        UidState uidState = mUidStates.get(uid);
+        if (uidState == null || uidState.pkgOps == null) {
+            return;
+        }
+
+        int numPkgOps = uidState.pkgOps.size();
+        for (int pkgNum = 0; pkgNum < numPkgOps; pkgNum++) {
+            Ops ops = uidState.pkgOps.valueAt(pkgNum);
+            Op op = ops != null ? ops.get(code) : null;
+            if (op == null || (op.getMode() != MODE_ALLOWED && op.getMode() != MODE_FOREGROUND)) {
+                continue;
+            }
+            int numAttrTags = op.mAttributions.size();
+            for (int attrNum = 0; attrNum < numAttrTags; attrNum++) {
+                AttributedOp attrOp = op.mAttributions.valueAt(attrNum);
+                if (restricted && attrOp.isRunning()) {
+                    attrOp.pause();
+                } else if (attrOp.isPaused()) {
+                    attrOp.resume();
+                }
+            }
+        }
+    }
+
+    @Override
+    public void notifyWatchersOfChange(int code, int uid) {
+        final ArraySet<OnOpModeChangedListener> modeChangedListenerSet;
+        synchronized (this) {
+            modeChangedListenerSet = mAppOpsServiceInterface.getOpModeChangedListeners(code);
+            if (modeChangedListenerSet == null) {
+                return;
+            }
+        }
+
+        notifyOpChanged(modeChangedListenerSet, code, uid, null);
+    }
+
+    @Override
+    public void removeUser(int userHandle) throws RemoteException {
+        checkSystemUid("removeUser");
+        synchronized (AppOpsServiceImpl.this) {
+            final int tokenCount = mOpUserRestrictions.size();
+            for (int i = tokenCount - 1; i >= 0; i--) {
+                ClientUserRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
+                opRestrictions.removeUser(userHandle);
+            }
+            removeUidsForUserLocked(userHandle);
+        }
+    }
+
+    @Override
+    public boolean isOperationActive(int code, int uid, String packageName) {
+        if (Binder.getCallingUid() != uid) {
+            if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                return false;
+            }
+        }
+        verifyIncomingOp(code);
+        if (!isIncomingPackageValid(packageName, UserHandle.getUserId(uid))) {
+            return false;
+        }
+
+        final String resolvedPackageName = AppOpsManager.resolvePackageName(uid, packageName);
+        if (resolvedPackageName == null) {
+            return false;
+        }
+        // TODO moltmann: Allow to check for attribution op activeness
+        synchronized (AppOpsServiceImpl.this) {
+            Ops pkgOps = getOpsLocked(uid, resolvedPackageName, null, false, null, false);
+            if (pkgOps == null) {
+                return false;
+            }
+
+            Op op = pkgOps.get(code);
+            if (op == null) {
+                return false;
+            }
+
+            return op.isRunning();
+        }
+    }
+
+    @Override
+    public boolean isProxying(int op, @NonNull String proxyPackageName,
+            @NonNull String proxyAttributionTag, int proxiedUid,
+            @NonNull String proxiedPackageName) {
+        Objects.requireNonNull(proxyPackageName);
+        Objects.requireNonNull(proxiedPackageName);
+        final long callingUid = Binder.getCallingUid();
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final List<AppOpsManager.PackageOps> packageOps = getOpsForPackage(proxiedUid,
+                    proxiedPackageName, new int[]{op});
+            if (packageOps == null || packageOps.isEmpty()) {
+                return false;
+            }
+            final List<OpEntry> opEntries = packageOps.get(0).getOps();
+            if (opEntries.isEmpty()) {
+                return false;
+            }
+            final OpEntry opEntry = opEntries.get(0);
+            if (!opEntry.isRunning()) {
+                return false;
+            }
+            final OpEventProxyInfo proxyInfo = opEntry.getLastProxyInfo(
+                    OP_FLAG_TRUSTED_PROXIED | AppOpsManager.OP_FLAG_UNTRUSTED_PROXIED);
+            return proxyInfo != null && callingUid == proxyInfo.getUid()
+                    && proxyPackageName.equals(proxyInfo.getPackageName())
+                    && Objects.equals(proxyAttributionTag, proxyInfo.getAttributionTag());
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
+    public void resetPackageOpsNoHistory(@NonNull String packageName) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "resetPackageOpsNoHistory");
+        synchronized (AppOpsServiceImpl.this) {
+            final int uid = mPackageManagerInternal.getPackageUid(packageName, 0,
+                    UserHandle.getCallingUserId());
+            if (uid == Process.INVALID_UID) {
+                return;
+            }
+            UidState uidState = mUidStates.get(uid);
+            if (uidState == null || uidState.pkgOps == null) {
+                return;
+            }
+            Ops removedOps = uidState.pkgOps.remove(packageName);
+            mAppOpsServiceInterface.removePackage(packageName, UserHandle.getUserId(uid));
+            if (removedOps != null) {
+                scheduleFastWriteLocked();
+            }
+        }
+    }
+
+    @Override
+    public void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
+            long baseSnapshotInterval, int compressionStep) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "setHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.setHistoryParameters(mode, baseSnapshotInterval, compressionStep);
+    }
+
+    @Override
+    public void offsetHistory(long offsetMillis) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "offsetHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.offsetHistory(offsetMillis);
+        mHistoricalRegistry.offsetDiscreteHistory(offsetMillis);
+    }
+
+    @Override
+    public void addHistoricalOps(HistoricalOps ops) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "addHistoricalOps");
+        // Must not hold the appops lock
+        mHistoricalRegistry.addHistoricalOps(ops);
+    }
+
+    @Override
+    public void resetHistoryParameters() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "resetHistoryParameters");
+        // Must not hold the appops lock
+        mHistoricalRegistry.resetHistoryParameters();
+    }
+
+    @Override
+    public void clearHistory() {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "clearHistory");
+        // Must not hold the appops lock
+        mHistoricalRegistry.clearAllHistory();
+    }
+
+    @Override
+    public void rebootHistory(long offlineDurationMillis) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_APPOPS,
+                "rebootHistory");
+
+        Preconditions.checkArgument(offlineDurationMillis >= 0);
+
+        // Must not hold the appops lock
+        mHistoricalRegistry.shutdown();
+
+        if (offlineDurationMillis > 0) {
+            SystemClock.sleep(offlineDurationMillis);
+        }
+
+        mHistoricalRegistry = new HistoricalRegistry(mHistoricalRegistry);
+        mHistoricalRegistry.systemReady(mContext.getContentResolver());
+        mHistoricalRegistry.persistPendingHistory();
+    }
+
+    @GuardedBy("this")
+    private void removeUidsForUserLocked(int userHandle) {
+        for (int i = mUidStates.size() - 1; i >= 0; --i) {
+            final int uid = mUidStates.keyAt(i);
+            if (UserHandle.getUserId(uid) == userHandle) {
+                mUidStates.valueAt(i).clear();
+                mUidStates.removeAt(i);
+            }
+        }
+    }
+
+    private void checkSystemUid(String function) {
+        int uid = Binder.getCallingUid();
+        if (uid != Process.SYSTEM_UID) {
+            throw new SecurityException(function + " must by called by the system");
+        }
+    }
+
+    private static int resolveUid(String packageName) {
+        if (packageName == null) {
+            return Process.INVALID_UID;
+        }
+        switch (packageName) {
+            case "root":
+                return Process.ROOT_UID;
+            case "shell":
+            case "dumpstate":
+                return Process.SHELL_UID;
+            case "media":
+                return Process.MEDIA_UID;
+            case "audioserver":
+                return Process.AUDIOSERVER_UID;
+            case "cameraserver":
+                return Process.CAMERASERVER_UID;
+        }
+        return Process.INVALID_UID;
+    }
+
+    private static String[] getPackagesForUid(int uid) {
+        String[] packageNames = null;
+
+        // Very early during boot the package manager is not yet or not yet fully started. At this
+        // time there are no packages yet.
+        if (AppGlobals.getPackageManager() != null) {
+            try {
+                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
+            } catch (RemoteException e) {
+                /* ignore - local call */
+            }
+        }
+        if (packageNames == null) {
+            return EmptyArray.STRING;
+        }
+        return packageNames;
+    }
+
+    private final class ClientUserRestrictionState implements DeathRecipient {
+        private final IBinder mToken;
+
+        ClientUserRestrictionState(IBinder token)
+                throws RemoteException {
+            token.linkToDeath(this, 0);
+            this.mToken = token;
+        }
+
+        public boolean setRestriction(int code, boolean restricted,
+                PackageTagsList excludedPackageTags, int userId) {
+            return mAppOpsRestrictions.setUserRestriction(mToken, userId, code,
+                    restricted, excludedPackageTags);
+        }
+
+        public boolean hasRestriction(int code, String packageName, String attributionTag,
+                int userId, boolean isCheckOp) {
+            return mAppOpsRestrictions.getUserRestriction(mToken, userId, code, packageName,
+                    attributionTag, isCheckOp);
+        }
+
+        public void removeUser(int userId) {
+            mAppOpsRestrictions.clearUserRestrictions(mToken, userId);
+        }
+
+        public boolean isDefault() {
+            return !mAppOpsRestrictions.hasUserRestrictions(mToken);
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (AppOpsServiceImpl.this) {
+                mAppOpsRestrictions.clearUserRestrictions(mToken);
+                mOpUserRestrictions.remove(mToken);
+                destroy();
+            }
+        }
+
+        public void destroy() {
+            mToken.unlinkToDeath(this, 0);
+        }
+    }
+
+    private final class ClientGlobalRestrictionState implements DeathRecipient {
+        final IBinder mToken;
+
+        ClientGlobalRestrictionState(IBinder token)
+                throws RemoteException {
+            token.linkToDeath(this, 0);
+            this.mToken = token;
+        }
+
+        boolean setRestriction(int code, boolean restricted) {
+            return mAppOpsRestrictions.setGlobalRestriction(mToken, code, restricted);
+        }
+
+        boolean hasRestriction(int code) {
+            return mAppOpsRestrictions.getGlobalRestriction(mToken, code);
+        }
+
+        boolean isDefault() {
+            return !mAppOpsRestrictions.hasGlobalRestrictions(mToken);
+        }
+
+        @Override
+        public void binderDied() {
+            mAppOpsRestrictions.clearGlobalRestrictions(mToken);
+            mOpGlobalRestrictions.remove(mToken);
+            destroy();
+        }
+
+        void destroy() {
+            mToken.unlinkToDeath(this, 0);
+        }
+    }
+
+    @Override
+    public void setDeviceAndProfileOwners(SparseIntArray owners) {
+        synchronized (this) {
+            mProfileOwners = owners;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
index 18f659e..8420fcb 100644
--- a/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
+++ b/services/core/java/com/android/server/appop/AppOpsServiceInterface.java
@@ -13,197 +13,482 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package com.android.server.appop;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppOpsManager.Mode;
-import android.util.ArraySet;
-import android.util.SparseBooleanArray;
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.content.AttributionSource;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PackageTagsList;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.SparseArray;
 import android.util.SparseIntArray;
 
+import com.android.internal.app.IAppOpsActiveCallback;
+import com.android.internal.app.IAppOpsCallback;
+import com.android.internal.app.IAppOpsNotedCallback;
+import com.android.internal.app.IAppOpsStartedCallback;
+
+import dalvik.annotation.optimization.NeverCompile;
+
+import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
- * Interface for accessing and modifying modes for app-ops i.e. package and uid modes.
- * This interface also includes functions for added and removing op mode watchers.
- * In the future this interface will also include op restrictions.
+ *
  */
-public interface AppOpsServiceInterface {
-    /**
-     * Returns a copy of non-default app-ops with op as keys and their modes as values for a uid.
-     * Returns an empty SparseIntArray if nothing is set.
-     * @param uid for which we need the app-ops and their modes.
-     */
-    SparseIntArray getNonDefaultUidModes(int uid);
+public interface AppOpsServiceInterface extends PersistenceScheduler {
 
     /**
-     * Returns the app-op mode for a particular app-op of a uid.
-     * Returns default op mode if the op mode for particular uid and op is not set.
-     * @param uid user id for which we need the mode.
-     * @param op app-op for which we need the mode.
-     * @return mode of the app-op.
-     */
-    int getUidMode(int uid, int op);
-
-    /**
-     * Set the app-op mode for a particular uid and op.
-     * The mode is not set if the mode is the same as the default mode for the op.
-     * @param uid user id for which we want to set the mode.
-     * @param op app-op for which we want to set the mode.
-     * @param mode mode for the app-op.
-     * @return true if op mode is changed.
-     */
-    boolean setUidMode(int uid, int op, @Mode int mode);
-
-    /**
-     * Gets the app-op mode for a particular package.
-     * Returns default op mode if the op mode for the particular package is not set.
-     * @param packageName package name for which we need the op mode.
-     * @param op app-op for which we need the mode.
-     * @param userId user id associated with the package.
-     * @return the mode of the app-op.
-     */
-    int getPackageMode(@NonNull String packageName, int op, @UserIdInt int userId);
-
-    /**
-     * Sets the app-op mode for a particular package.
-     * @param packageName package name for which we need to set the op mode.
-     * @param op app-op for which we need to set the mode.
-     * @param mode the mode of the app-op.
-     * @param userId user id associated with the package.
      *
      */
-    void setPackageMode(@NonNull String packageName, int op, @Mode int mode, @UserIdInt int userId);
+    void systemReady();
 
     /**
-     * Stop tracking any app-op modes for a package.
-     * @param packageName Name of the package for which we want to remove all mode tracking.
-     * @param userId user id associated with the package.
+     *
      */
-    boolean removePackage(@NonNull String packageName,  @UserIdInt int userId);
+    void shutdown();
 
     /**
-     * Stop tracking any app-op modes for this uid.
-     * @param uid user id for which we want to remove all tracking.
+     *
+     * @param uid
+     * @param packageName
      */
-    void removeUid(int uid);
+    void verifyPackage(int uid, String packageName);
 
     /**
-     * Returns true if all uid modes for this uid are
-     * in default state.
-     * @param uid user id
+     *
+     * @param op
+     * @param packageName
+     * @param flags
+     * @param callback
      */
-    boolean areUidModesDefault(int uid);
+    void startWatchingModeWithFlags(int op, String packageName, int flags,
+            IAppOpsCallback callback);
 
     /**
-     * Returns true if all package modes for this package name are
-     * in default state.
-     * @param packageName package name.
-     * @param userId user id associated with the package.
+     *
+     * @param callback
      */
-    boolean arePackageModesDefault(String packageName, @UserIdInt int userId);
+    void stopWatchingMode(IAppOpsCallback callback);
 
     /**
-     * Stop tracking app-op modes for all uid and packages.
+     *
+     * @param ops
+     * @param callback
      */
-    void clearAllModes();
+    void startWatchingActive(int[] ops, IAppOpsActiveCallback callback);
 
     /**
-     * Registers changedListener to listen to op's mode change.
-     * @param changedListener the listener that must be trigger on the op's mode change.
-     * @param op op representing the app-op whose mode change needs to be listened to.
+     *
+     * @param callback
      */
-    void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener, int op);
+    void stopWatchingActive(IAppOpsActiveCallback callback);
 
     /**
-     * Registers changedListener to listen to package's app-op's mode change.
-     * @param changedListener the listener that must be trigger on the mode change.
-     * @param packageName of the package whose app-op's mode change needs to be listened to.
+     *
+     * @param ops
+     * @param callback
      */
-    void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
-            @NonNull String packageName);
+    void startWatchingStarted(int[] ops, @NonNull IAppOpsStartedCallback callback);
 
     /**
-     * Stop the changedListener from triggering on any mode change.
-     * @param changedListener the listener that needs to be removed.
+     *
+     * @param callback
      */
-    void removeListener(@NonNull OnOpModeChangedListener changedListener);
+    void stopWatchingStarted(IAppOpsStartedCallback callback);
 
     /**
-     * Temporary API which will be removed once we can safely untangle the methods that use this.
-     * Returns a set of OnOpModeChangedListener that are listening for op's mode changes.
-     * @param op app-op whose mode change is being listened to.
+     *
+     * @param ops
+     * @param callback
      */
-    ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op);
+    void startWatchingNoted(@NonNull int[] ops, @NonNull IAppOpsNotedCallback callback);
 
     /**
-     * Temporary API which will be removed once we can safely untangle the methods that use this.
-     * Returns a set of OnOpModeChangedListener that are listening for package's op's mode changes.
-     * @param packageName of package whose app-op's mode change is being listened to.
+     *
+     * @param callback
      */
-    ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(@NonNull String packageName);
+    void stopWatchingNoted(IAppOpsNotedCallback callback);
 
     /**
-     * Temporary API which will be removed once we can safely untangle the methods that use this.
-     * Notify that the app-op's mode is changed by triggering the change listener.
-     * @param op App-op whose mode has changed
-     * @param uid user id associated with the app-op (or, if UID_ANY, notifies all users)
+     * @param clientId
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param startIfModeDefault
+     * @param message
+     * @param attributionFlags
+     * @param attributionChainId
+     * @return
      */
-    void notifyWatchersOfChange(int op, int uid);
+    int startOperation(@NonNull IBinder clientId, int code, int uid,
+            @Nullable String packageName, @Nullable String attributionTag,
+            boolean startIfModeDefault, @NonNull String message,
+            @AppOpsManager.AttributionFlags int attributionFlags,
+            int attributionChainId);
+
+
+    int startOperationUnchecked(IBinder clientId, int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, int proxyUid, String proxyPackageName,
+            @Nullable String proxyAttributionTag, @AppOpsManager.OpFlags int flags,
+            boolean startIfModeDefault, @AppOpsManager.AttributionFlags int attributionFlags,
+            int attributionChainId, boolean dryRun);
 
     /**
-     * Temporary API which will be removed once we can safely untangle the methods that use this.
-     * Notify that the app-op's mode is changed by triggering the change listener.
-     * @param changedListener the change listener.
-     * @param op App-op whose mode has changed
-     * @param uid user id associated with the app-op
-     * @param packageName package name that is associated with the app-op
+     *
+     * @param clientId
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
      */
-    void notifyOpChanged(@NonNull OnOpModeChangedListener changedListener, int op, int uid,
-            @Nullable String packageName);
+    void finishOperation(IBinder clientId, int code, int uid, String packageName,
+            String attributionTag);
 
     /**
-     * Temporary API which will be removed once we can safely untangle the methods that use this.
-     * Notify that the app-op's mode is changed to all packages associated with the uid by
-     * triggering the appropriate change listener.
-     * @param op App-op whose mode has changed
-     * @param uid user id associated with the app-op
-     * @param onlyForeground true if only watchers that
-     * @param callbackToIgnore callback that should be ignored.
+     *
+     * @param clientId
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
      */
-    void notifyOpChangedForAllPkgsInUid(int op, int uid, boolean onlyForeground,
-            @Nullable OnOpModeChangedListener callbackToIgnore);
+    void finishOperationUnchecked(IBinder clientId, int code, int uid, String packageName,
+            String attributionTag);
 
     /**
-     * TODO: Move hasForegroundWatchers and foregroundOps into this.
-     * Go over the list of app-ops for the uid and mark app-ops with MODE_FOREGROUND in
-     * foregroundOps.
-     * @param uid for which the app-op's mode needs to be marked.
-     * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
-     * @return  foregroundOps.
+     *
+     * @param uidPackageNames
+     * @param visible
      */
-    SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps);
+    void updateAppWidgetVisibility(SparseArray<String> uidPackageNames, boolean visible);
 
     /**
-     * Go over the list of app-ops for the package name and mark app-ops with MODE_FOREGROUND in
-     * foregroundOps.
-     * @param packageName for which the app-op's mode needs to be marked.
-     * @param foregroundOps boolean array where app-ops that have MODE_FOREGROUND are marked true.
-     * @param userId user id associated with the package.
-     * @return foregroundOps.
+     *
      */
-    SparseBooleanArray evalForegroundPackageOps(String packageName,
-            SparseBooleanArray foregroundOps, @UserIdInt int userId);
+    void readState();
 
     /**
-     * Dump op mode and package mode listeners and their details.
-     * @param dumpOp if -1 then op mode listeners for all app-ops are dumped. If it's set to an
-     *               app-op, only the watchers for that app-op are dumped.
-     * @param dumpUid uid for which we want to dump op mode watchers.
-     * @param dumpPackage if not null and if dumpOp is -1, dumps watchers for the package name.
-     * @param printWriter writer to dump to.
+     *
      */
-    boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage, PrintWriter printWriter);
+    void writeState();
+
+    /**
+     *
+     * @param uid
+     * @param packageName
+     */
+    void packageRemoved(int uid, String packageName);
+
+    /**
+     *
+     * @param uid
+     */
+    void uidRemoved(int uid);
+
+    /**
+     *
+     * @param uid
+     * @param procState
+     * @param capability
+     */
+    void updateUidProcState(int uid, int procState,
+            @ActivityManager.ProcessCapability int capability);
+
+    /**
+     *
+     * @param ops
+     * @return
+     */
+    List<AppOpsManager.PackageOps> getPackagesForOps(int[] ops);
+
+    /**
+     *
+     * @param uid
+     * @param packageName
+     * @param ops
+     * @return
+     */
+    List<AppOpsManager.PackageOps> getOpsForPackage(int uid, String packageName,
+            int[] ops);
+
+    /**
+     *
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param opNames
+     * @param dataType
+     * @param filter
+     * @param beginTimeMillis
+     * @param endTimeMillis
+     * @param flags
+     * @param callback
+     */
+    void getHistoricalOps(int uid, String packageName, String attributionTag,
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback);
+
+    /**
+     *
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param opNames
+     * @param dataType
+     * @param filter
+     * @param beginTimeMillis
+     * @param endTimeMillis
+     * @param flags
+     * @param callback
+     */
+    void getHistoricalOpsFromDiskRaw(int uid, String packageName, String attributionTag,
+            List<String> opNames, int dataType, int filter, long beginTimeMillis,
+            long endTimeMillis, int flags, RemoteCallback callback);
+
+    /**
+     *
+     */
+    void reloadNonHistoricalState();
+
+    /**
+     *
+     * @param uid
+     * @param ops
+     * @return
+     */
+    List<AppOpsManager.PackageOps> getUidOps(int uid, int[] ops);
+
+    /**
+     *
+     * @param owners
+     */
+    void setDeviceAndProfileOwners(SparseIntArray owners);
+
+    // used in audio restriction calls, might just copy the logic to avoid having this call.
+    /**
+     *
+     * @param callingPid
+     * @param callingUid
+     * @param targetUid
+     */
+    void enforceManageAppOpsModes(int callingPid, int callingUid, int targetUid);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param mode
+     * @param permissionPolicyCallback
+     */
+    void setUidMode(int code, int uid, int mode,
+            @Nullable IAppOpsCallback permissionPolicyCallback);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param mode
+     * @param permissionPolicyCallback
+     */
+    void setMode(int code, int uid, @NonNull String packageName, int mode,
+            @Nullable IAppOpsCallback permissionPolicyCallback);
+
+    /**
+     *
+     * @param reqUserId
+     * @param reqPackageName
+     */
+    void resetAllModes(int reqUserId, String reqPackageName);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param raw
+     * @return
+     */
+    int checkOperation(int code, int uid, String packageName,
+            @Nullable String attributionTag, boolean raw);
+
+    /**
+     *
+     * @param uid
+     * @param packageName
+     * @return
+     */
+    int checkPackage(int uid, String packageName);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param message
+     * @return
+     */
+    int noteOperation(int code, int uid, @Nullable String packageName,
+            @Nullable String attributionTag, @Nullable String message);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param packageName
+     * @param attributionTag
+     * @param proxyUid
+     * @param proxyPackageName
+     * @param proxyAttributionTag
+     * @param flags
+     * @return
+     */
+    @AppOpsManager.Mode
+    int noteOperationUnchecked(int code, int uid, @NonNull String packageName,
+            @Nullable String attributionTag, int proxyUid, String proxyPackageName,
+            @Nullable String proxyAttributionTag, @AppOpsManager.OpFlags int flags);
+
+    boolean isAttributionTagValid(int uid, @NonNull String packageName,
+            @Nullable String attributionTag, @Nullable String proxyPackageName);
+
+    /**
+     *
+     * @param fd
+     * @param pw
+     * @param args
+     */
+    @NeverCompile
+        // Avoid size overhead of debugging code.
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args);
+
+    /**
+     *
+     * @param restrictions
+     * @param token
+     * @param userHandle
+     */
+    void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle);
+
+    /**
+     *
+     * @param code
+     * @param restricted
+     * @param token
+     * @param userHandle
+     * @param excludedPackageTags
+     */
+    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle,
+            PackageTagsList excludedPackageTags);
+
+    /**
+     *
+     * @param code
+     * @param restricted
+     * @param token
+     */
+    void setGlobalRestriction(int code, boolean restricted, IBinder token);
+
+    /**
+     *
+     * @param code
+     * @param user
+     * @param pkg
+     * @param attributionTag
+     * @return
+     */
+    int getOpRestrictionCount(int code, UserHandle user, String pkg,
+            String attributionTag);
+
+    /**
+     *
+     * @param code
+     * @param uid
+     */
+    // added to interface for audio restriction stuff
+    void notifyWatchersOfChange(int code, int uid);
+
+    /**
+     *
+     * @param userHandle
+     * @throws RemoteException
+     */
+    void removeUser(int userHandle) throws RemoteException;
+
+    /**
+     *
+     * @param code
+     * @param uid
+     * @param packageName
+     * @return
+     */
+    boolean isOperationActive(int code, int uid, String packageName);
+
+    /**
+     *
+     * @param op
+     * @param proxyPackageName
+     * @param proxyAttributionTag
+     * @param proxiedUid
+     * @param proxiedPackageName
+     * @return
+     */
+    // TODO this one might not need to be in the interface
+    boolean isProxying(int op, @NonNull String proxyPackageName,
+            @NonNull String proxyAttributionTag, int proxiedUid,
+            @NonNull String proxiedPackageName);
+
+    /**
+     *
+     * @param packageName
+     */
+    void resetPackageOpsNoHistory(@NonNull String packageName);
+
+    /**
+     *
+     * @param mode
+     * @param baseSnapshotInterval
+     * @param compressionStep
+     */
+    void setHistoryParameters(@AppOpsManager.HistoricalMode int mode,
+            long baseSnapshotInterval, int compressionStep);
+
+    /**
+     *
+     * @param offsetMillis
+     */
+    void offsetHistory(long offsetMillis);
+
+    /**
+     *
+     * @param ops
+     */
+    void addHistoricalOps(AppOpsManager.HistoricalOps ops);
+
+    /**
+     *
+     */
+    void resetHistoryParameters();
+
+    /**
+     *
+     */
+    void clearHistory();
+
+    /**
+     *
+     * @param offlineDurationMillis
+     */
+    void rebootHistory(long offlineDurationMillis);
 }
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index 5114bd5..c1434e4 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -59,7 +59,7 @@
     private final DelayableExecutor mExecutor;
     private final Clock mClock;
     private ActivityManagerInternal mActivityManagerInternal;
-    private AppOpsService.Constants mConstants;
+    private AppOpsServiceImpl.Constants mConstants;
 
     private SparseIntArray mUidStates = new SparseIntArray();
     private SparseIntArray mPendingUidStates = new SparseIntArray();
@@ -85,7 +85,7 @@
 
     AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
             Handler handler, Executor lockingExecutor, Clock clock,
-            AppOpsService.Constants constants) {
+            AppOpsServiceImpl.Constants constants) {
 
         this(activityManagerInternal, new DelayableExecutor() {
             @Override
@@ -102,7 +102,7 @@
 
     @VisibleForTesting
     AppOpsUidStateTrackerImpl(ActivityManagerInternal activityManagerInternal,
-            DelayableExecutor executor, Clock clock, AppOpsService.Constants constants,
+            DelayableExecutor executor, Clock clock, AppOpsServiceImpl.Constants constants,
             Thread executorThread) {
         mActivityManagerInternal = activityManagerInternal;
         mExecutor = executor;
diff --git a/services/core/java/com/android/server/appop/AttributedOp.java b/services/core/java/com/android/server/appop/AttributedOp.java
index dcc36bc..7970269 100644
--- a/services/core/java/com/android/server/appop/AttributedOp.java
+++ b/services/core/java/com/android/server/appop/AttributedOp.java
@@ -40,9 +40,9 @@
 import java.util.NoSuchElementException;
 
 final class AttributedOp {
-    private final @NonNull AppOpsService mAppOpsService;
+    private final @NonNull AppOpsServiceImpl mAppOpsService;
     public final @Nullable String tag;
-    public final @NonNull AppOpsService.Op parent;
+    public final @NonNull AppOpsServiceImpl.Op parent;
 
     /**
      * Last successful accesses (noteOp + finished startOp) for each uidState/opFlag combination
@@ -80,8 +80,8 @@
     // @GuardedBy("mAppOpsService")
     @Nullable ArrayMap<IBinder, InProgressStartOpEvent> mPausedInProgressEvents;
 
-    AttributedOp(@NonNull AppOpsService appOpsService, @Nullable String tag,
-            @NonNull AppOpsService.Op parent) {
+    AttributedOp(@NonNull AppOpsServiceImpl appOpsService, @Nullable String tag,
+                 @NonNull AppOpsServiceImpl.Op parent) {
         mAppOpsService = appOpsService;
         this.tag = tag;
         this.parent = parent;
@@ -131,8 +131,8 @@
 
         AppOpsManager.OpEventProxyInfo proxyInfo = null;
         if (proxyUid != Process.INVALID_UID) {
-            proxyInfo = mAppOpsService.mOpEventProxyInfoPool.acquire(proxyUid, proxyPackageName,
-                    proxyAttributionTag);
+            proxyInfo = mAppOpsService.mOpEventProxyInfoPool.acquire(proxyUid,
+                    proxyPackageName, proxyAttributionTag);
         }
 
         AppOpsManager.NoteOpEvent existingEvent = mAccessEvents.get(key);
@@ -238,7 +238,7 @@
         if (event == null) {
             event = mAppOpsService.mInProgressStartOpEventPool.acquire(startTime,
                     SystemClock.elapsedRealtime(), clientId, tag,
-                    PooledLambda.obtainRunnable(AppOpsService::onClientDeath, this, clientId),
+                    PooledLambda.obtainRunnable(AppOpsServiceImpl::onClientDeath, this, clientId),
                     proxyUid, proxyPackageName, proxyAttributionTag, uidState, flags,
                     attributionFlags, attributionChainId);
             events.put(clientId, event);
@@ -251,9 +251,9 @@
         event.mNumUnfinishedStarts++;
 
         if (isStarted) {
-            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
-                    parent.packageName, tag, uidState, flags, startTime, attributionFlags,
-                    attributionChainId);
+            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op,
+                    parent.uid, parent.packageName, tag, uidState, flags, startTime,
+                    attributionFlags, attributionChainId);
         }
     }
 
@@ -309,8 +309,8 @@
             mAccessEvents.put(makeKey(event.getUidState(), event.getFlags()),
                     finishedEvent);
 
-            mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op, parent.uid,
-                    parent.packageName, tag, event.getUidState(),
+            mAppOpsService.mHistoricalRegistry.increaseOpAccessDuration(parent.op,
+                    parent.uid, parent.packageName, tag, event.getUidState(),
                     event.getFlags(), finishedEvent.getNoteTime(), finishedEvent.getDuration(),
                     event.getAttributionFlags(), event.getAttributionChainId());
 
@@ -334,13 +334,13 @@
     @SuppressWarnings("GuardedBy") // Lock is held on mAppOpsService
     private void finishPossiblyPaused(@NonNull IBinder clientId, boolean isPausing) {
         if (!isPaused()) {
-            Slog.wtf(AppOpsService.TAG, "No ops running or paused");
+            Slog.wtf(AppOpsServiceImpl.TAG, "No ops running or paused");
             return;
         }
 
         int indexOfToken = mPausedInProgressEvents.indexOfKey(clientId);
         if (indexOfToken < 0) {
-            Slog.wtf(AppOpsService.TAG, "No op running or paused for the client");
+            Slog.wtf(AppOpsServiceImpl.TAG, "No op running or paused for the client");
             return;
         } else if (isPausing) {
             // already paused
@@ -416,9 +416,9 @@
             mInProgressEvents.put(event.getClientId(), event);
             event.setStartElapsedTime(SystemClock.elapsedRealtime());
             event.setStartTime(startTime);
-            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op, parent.uid,
-                    parent.packageName, tag, event.getUidState(), event.getFlags(), startTime,
-                    event.getAttributionFlags(), event.getAttributionChainId());
+            mAppOpsService.mHistoricalRegistry.incrementOpAccessedCount(parent.op,
+                    parent.uid, parent.packageName, tag, event.getUidState(), event.getFlags(),
+                    startTime, event.getAttributionFlags(), event.getAttributionChainId());
             if (shouldSendActive) {
                 mAppOpsService.scheduleOpActiveChangedIfNeededLocked(parent.op, parent.uid,
                         parent.packageName, tag, true, event.getAttributionFlags(),
@@ -503,8 +503,8 @@
                         newEvent.mNumUnfinishedStarts += numPreviousUnfinishedStarts - 1;
                     }
                 } catch (RemoteException e) {
-                    if (AppOpsService.DEBUG) {
-                        Slog.e(AppOpsService.TAG,
+                    if (AppOpsServiceImpl.DEBUG) {
+                        Slog.e(AppOpsServiceImpl.TAG,
                                 "Cannot switch to new uidState " + newState);
                     }
                 }
@@ -555,8 +555,8 @@
             ArrayMap<IBinder, InProgressStartOpEvent> ignoredEvents =
                     opToAdd.isRunning()
                             ? opToAdd.mInProgressEvents : opToAdd.mPausedInProgressEvents;
-            Slog.w(AppOpsService.TAG, "Ignoring " + ignoredEvents.size() + " app-ops, running: "
-                    + opToAdd.isRunning());
+            Slog.w(AppOpsServiceImpl.TAG, "Ignoring " + ignoredEvents.size()
+                    + " app-ops, running: " + opToAdd.isRunning());
 
             int numInProgressEvents = ignoredEvents.size();
             for (int i = 0; i < numInProgressEvents; i++) {
@@ -668,16 +668,22 @@
         /**
          * Create a new {@link InProgressStartOpEvent}.
          *
-         * @param startTime          The time {@link #startOperation} was called
-         * @param startElapsedTime   The elapsed time when {@link #startOperation} was called
-         * @param clientId           The client id of the caller of {@link #startOperation}
+         * @param startTime          The time {@link AppOpCheckingServiceInterface#startOperation}
+         *                          was called
+         * @param startElapsedTime   The elapsed time whe
+         *                          {@link AppOpCheckingServiceInterface#startOperation} was called
+         * @param clientId           The client id of the caller of
+         *                          {@link AppOpCheckingServiceInterface#startOperation}
          * @param attributionTag     The attribution tag for the operation.
          * @param onDeath            The code to execute on client death
-         * @param uidState           The uidstate of the app {@link #startOperation} was called for
+         * @param uidState           The uidstate of the app
+         *                          {@link AppOpCheckingServiceInterface#startOperation} was called
+         *                          for
          * @param attributionFlags   the attribution flags for this operation.
          * @param attributionChainId the unique id of the attribution chain this op is a part of.
-         * @param proxy              The proxy information, if {@link #startProxyOperation} was
-         *                           called
+         * @param proxy              The proxy information, if
+         *                          {@link AppOpCheckingServiceInterface#startProxyOperation} was
+         *                          called
          * @param flags              The trusted/nontrusted/self flags.
          * @throws RemoteException If the client is dying
          */
@@ -718,15 +724,21 @@
         /**
          * Reinit existing object with new state.
          *
-         * @param startTime          The time {@link #startOperation} was called
-         * @param startElapsedTime   The elapsed time when {@link #startOperation} was called
-         * @param clientId           The client id of the caller of {@link #startOperation}
+         * @param startTime          The time {@link AppOpCheckingServiceInterface#startOperation}
+         *                          was called
+         * @param startElapsedTime   The elapsed time when
+         *                          {@link AppOpCheckingServiceInterface#startOperation} was called
+         * @param clientId           The client id of the caller of
+         *                          {@link AppOpCheckingServiceInterface#startOperation}
          * @param attributionTag     The attribution tag for this operation.
          * @param onDeath            The code to execute on client death
-         * @param uidState           The uidstate of the app {@link #startOperation} was called for
+         * @param uidState           The uidstate of the app
+         *                          {@link AppOpCheckingServiceInterface#startOperation} was called
+         *                          for
          * @param flags              The flags relating to the proxy
-         * @param proxy              The proxy information, if {@link #startProxyOperation}
-         *                           was called
+         * @param proxy              The proxy information, if
+         *                          {@link AppOpCheckingServiceInterface#startProxyOperation was
+         *                          called
          * @param attributionFlags   the attribution flags for this operation.
          * @param attributionChainId the unique id of the attribution chain this op is a part of.
          * @param proxyPool          The pool to release
diff --git a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java b/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
deleted file mode 100644
index f6fff35..0000000
--- a/services/core/java/com/android/server/appop/LegacyAppOpsServiceInterfaceImpl.java
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.appop;
-
-import static android.app.AppOpsManager.OP_NONE;
-import static android.app.AppOpsManager.WATCH_FOREGROUND_CHANGES;
-import static android.app.AppOpsManager.opRestrictsRead;
-
-import static com.android.server.appop.AppOpsService.ModeCallback.ALL_OPS;
-
-import android.Manifest;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UserIdInt;
-import android.app.AppGlobals;
-import android.app.AppOpsManager;
-import android.app.AppOpsManager.Mode;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.os.Binder;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-import android.util.SparseBooleanArray;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.function.pooled.PooledLambda;
-
-import libcore.util.EmptyArray;
-
-import java.io.PrintWriter;
-import java.util.Collections;
-import java.util.Objects;
-
-
-/**
- * Legacy implementation for App-ops service's app-op mode (uid and package) storage and access.
- * In the future this class will also include mode callbacks and op restrictions.
- */
-public class LegacyAppOpsServiceInterfaceImpl implements AppOpsServiceInterface {
-
-    static final String TAG = "LegacyAppOpsServiceInterfaceImpl";
-
-    // Must be the same object that the AppOpsService is using for locking.
-    final Object mLock;
-    final Handler mHandler;
-    final Context mContext;
-    final SparseArray<int[]> mSwitchedOps;
-
-    @GuardedBy("mLock")
-    @VisibleForTesting
-    final SparseArray<SparseIntArray> mUidModes = new SparseArray<>();
-
-    @GuardedBy("mLock")
-    final SparseArray<ArrayMap<String, SparseIntArray>> mUserPackageModes = new SparseArray<>();
-
-    final SparseArray<ArraySet<OnOpModeChangedListener>> mOpModeWatchers = new SparseArray<>();
-    final ArrayMap<String, ArraySet<OnOpModeChangedListener>> mPackageModeWatchers =
-            new ArrayMap<>();
-
-    final PersistenceScheduler mPersistenceScheduler;
-
-
-    // Constant meaning that any UID should be matched when dispatching callbacks
-    private static final int UID_ANY = -2;
-
-
-    LegacyAppOpsServiceInterfaceImpl(PersistenceScheduler persistenceScheduler,
-            @NonNull Object lock, Handler handler, Context context,
-            SparseArray<int[]> switchedOps) {
-        this.mPersistenceScheduler = persistenceScheduler;
-        this.mLock = lock;
-        this.mHandler = handler;
-        this.mContext = context;
-        this.mSwitchedOps = switchedOps;
-    }
-
-    @Override
-    public SparseIntArray getNonDefaultUidModes(int uid) {
-        synchronized (mLock) {
-            SparseIntArray opModes = mUidModes.get(uid, null);
-            if (opModes == null) {
-                return new SparseIntArray();
-            }
-            return opModes.clone();
-        }
-    }
-
-    @Override
-    public int getUidMode(int uid, int op) {
-        synchronized (mLock) {
-            SparseIntArray opModes = mUidModes.get(uid, null);
-            if (opModes == null) {
-                return AppOpsManager.opToDefaultMode(op);
-            }
-            return opModes.get(op, AppOpsManager.opToDefaultMode(op));
-        }
-    }
-
-    @Override
-    public boolean setUidMode(int uid, int op, int mode) {
-        final int defaultMode = AppOpsManager.opToDefaultMode(op);
-        synchronized (mLock) {
-            SparseIntArray opModes = mUidModes.get(uid, null);
-            if (opModes == null) {
-                if (mode != defaultMode) {
-                    opModes = new SparseIntArray();
-                    mUidModes.put(uid, opModes);
-                    opModes.put(op, mode);
-                    mPersistenceScheduler.scheduleWriteLocked();
-                }
-            } else {
-                if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) {
-                    return false;
-                }
-                if (mode == defaultMode) {
-                    opModes.delete(op);
-                    if (opModes.size() <= 0) {
-                        opModes = null;
-                        mUidModes.delete(uid);
-                    }
-                } else {
-                    opModes.put(op, mode);
-                }
-                mPersistenceScheduler.scheduleWriteLocked();
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public int getPackageMode(String packageName, int op, @UserIdInt int userId) {
-        synchronized (mLock) {
-            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
-            if (packageModes == null) {
-                return AppOpsManager.opToDefaultMode(op);
-            }
-            SparseIntArray opModes = packageModes.getOrDefault(packageName, null);
-            if (opModes == null) {
-                return AppOpsManager.opToDefaultMode(op);
-            }
-            return opModes.get(op, AppOpsManager.opToDefaultMode(op));
-        }
-    }
-
-    @Override
-    public void setPackageMode(String packageName, int op, @Mode int mode, @UserIdInt int userId) {
-        final int defaultMode = AppOpsManager.opToDefaultMode(op);
-        synchronized (mLock) {
-            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
-            if (packageModes == null) {
-                packageModes = new ArrayMap<>();
-                mUserPackageModes.put(userId, packageModes);
-            }
-            SparseIntArray opModes = packageModes.get(packageName);
-            if (opModes == null) {
-                if (mode != defaultMode) {
-                    opModes = new SparseIntArray();
-                    packageModes.put(packageName, opModes);
-                    opModes.put(op, mode);
-                    mPersistenceScheduler.scheduleWriteLocked();
-                }
-            } else {
-                if (opModes.indexOfKey(op) >= 0 && opModes.get(op) == mode) {
-                    return;
-                }
-                if (mode == defaultMode) {
-                    opModes.delete(op);
-                    if (opModes.size() <= 0) {
-                        opModes = null;
-                        packageModes.remove(packageName);
-                    }
-                } else {
-                    opModes.put(op, mode);
-                }
-                mPersistenceScheduler.scheduleWriteLocked();
-            }
-        }
-    }
-
-    @Override
-    public void removeUid(int uid) {
-        synchronized (mLock) {
-            SparseIntArray opModes = mUidModes.get(uid);
-            if (opModes == null) {
-                return;
-            }
-            mUidModes.remove(uid);
-            mPersistenceScheduler.scheduleFastWriteLocked();
-        }
-    }
-
-    @Override
-    public boolean areUidModesDefault(int uid) {
-        synchronized (mLock) {
-            SparseIntArray opModes = mUidModes.get(uid);
-            return (opModes == null || opModes.size() <= 0);
-        }
-    }
-
-    @Override
-    public boolean arePackageModesDefault(String packageMode, @UserIdInt int userId) {
-        synchronized (mLock) {
-            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
-            if (packageModes == null) {
-                return true;
-            }
-            SparseIntArray opModes = packageModes.get(packageMode);
-            return (opModes == null || opModes.size() <= 0);
-        }
-    }
-
-    @Override
-    public boolean removePackage(String packageName, @UserIdInt int userId) {
-        synchronized (mLock) {
-            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
-            if (packageModes == null) {
-                return false;
-            }
-            SparseIntArray ops = packageModes.remove(packageName);
-            if (ops != null) {
-                mPersistenceScheduler.scheduleFastWriteLocked();
-                return true;
-            }
-            return false;
-        }
-    }
-
-    @Override
-    public void clearAllModes() {
-        synchronized (mLock) {
-            mUidModes.clear();
-            mUserPackageModes.clear();
-        }
-    }
-
-    @Override
-    public void startWatchingOpModeChanged(@NonNull OnOpModeChangedListener changedListener,
-            int op) {
-        Objects.requireNonNull(changedListener);
-        synchronized (mLock) {
-            ArraySet<OnOpModeChangedListener> modeWatcherSet = mOpModeWatchers.get(op);
-            if (modeWatcherSet == null) {
-                modeWatcherSet = new ArraySet<>();
-                mOpModeWatchers.put(op, modeWatcherSet);
-            }
-            modeWatcherSet.add(changedListener);
-        }
-    }
-
-    @Override
-    public void startWatchingPackageModeChanged(@NonNull OnOpModeChangedListener changedListener,
-            @NonNull String packageName) {
-        Objects.requireNonNull(changedListener);
-        Objects.requireNonNull(packageName);
-        synchronized (mLock) {
-            ArraySet<OnOpModeChangedListener> modeWatcherSet =
-                    mPackageModeWatchers.get(packageName);
-            if (modeWatcherSet == null) {
-                modeWatcherSet = new ArraySet<>();
-                mPackageModeWatchers.put(packageName, modeWatcherSet);
-            }
-            modeWatcherSet.add(changedListener);
-        }
-    }
-
-    @Override
-    public void removeListener(@NonNull OnOpModeChangedListener changedListener) {
-        Objects.requireNonNull(changedListener);
-
-        synchronized (mLock) {
-            for (int i = mOpModeWatchers.size() - 1; i >= 0; i--) {
-                ArraySet<OnOpModeChangedListener> cbs = mOpModeWatchers.valueAt(i);
-                cbs.remove(changedListener);
-                if (cbs.size() <= 0) {
-                    mOpModeWatchers.removeAt(i);
-                }
-            }
-
-            for (int i = mPackageModeWatchers.size() - 1; i >= 0; i--) {
-                ArraySet<OnOpModeChangedListener> cbs = mPackageModeWatchers.valueAt(i);
-                cbs.remove(changedListener);
-                if (cbs.size() <= 0) {
-                    mPackageModeWatchers.removeAt(i);
-                }
-            }
-        }
-    }
-
-    @Override
-    public ArraySet<OnOpModeChangedListener> getOpModeChangedListeners(int op) {
-        synchronized (mLock) {
-            ArraySet<OnOpModeChangedListener> modeChangedListenersSet = mOpModeWatchers.get(op);
-            if (modeChangedListenersSet == null) {
-                return new ArraySet<>();
-            }
-            return new ArraySet<>(modeChangedListenersSet);
-        }
-    }
-
-    @Override
-    public ArraySet<OnOpModeChangedListener> getPackageModeChangedListeners(
-            @NonNull String packageName) {
-        Objects.requireNonNull(packageName);
-
-        synchronized (mLock) {
-            ArraySet<OnOpModeChangedListener> modeChangedListenersSet =
-                    mPackageModeWatchers.get(packageName);
-            if (modeChangedListenersSet == null) {
-                return new ArraySet<>();
-            }
-            return new ArraySet<>(modeChangedListenersSet);
-        }
-    }
-
-    @Override
-    public void notifyWatchersOfChange(int code, int uid) {
-        ArraySet<OnOpModeChangedListener> listenerSet = getOpModeChangedListeners(code);
-        if (listenerSet == null) {
-            return;
-        }
-        for (int i = 0; i < listenerSet.size(); i++) {
-            final OnOpModeChangedListener listener = listenerSet.valueAt(i);
-            notifyOpChanged(listener, code, uid, null);
-        }
-    }
-
-    @Override
-    public void notifyOpChanged(@NonNull OnOpModeChangedListener onModeChangedListener, int code,
-            int uid, @Nullable String packageName) {
-        Objects.requireNonNull(onModeChangedListener);
-
-        if (uid != UID_ANY && onModeChangedListener.getWatchingUid() >= 0
-                && onModeChangedListener.getWatchingUid() != uid) {
-            return;
-        }
-
-        // See CALL_BACK_ON_CHANGED_LISTENER_WITH_SWITCHED_OP_CHANGE
-        int[] switchedCodes;
-        if (onModeChangedListener.getWatchedOpCode() == ALL_OPS) {
-            switchedCodes = mSwitchedOps.get(code);
-        } else if (onModeChangedListener.getWatchedOpCode() == OP_NONE) {
-            switchedCodes = new int[]{code};
-        } else {
-            switchedCodes = new int[]{onModeChangedListener.getWatchedOpCode()};
-        }
-
-        for (int switchedCode : switchedCodes) {
-            // There are features watching for mode changes such as window manager
-            // and location manager which are in our process. The callbacks in these
-            // features may require permissions our remote caller does not have.
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                if (shouldIgnoreCallback(switchedCode, onModeChangedListener.getCallingPid(),
-                        onModeChangedListener.getCallingUid())) {
-                    continue;
-                }
-                onModeChangedListener.onOpModeChanged(switchedCode, uid, packageName);
-            } catch (RemoteException e) {
-                /* ignore */
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-    }
-
-    private boolean shouldIgnoreCallback(int op, int watcherPid, int watcherUid) {
-        // If it's a restricted read op, ignore it if watcher doesn't have manage ops permission,
-        // as watcher should not use this to signal if the value is changed.
-        return opRestrictsRead(op) && mContext.checkPermission(Manifest.permission.MANAGE_APPOPS,
-                watcherPid, watcherUid) != PackageManager.PERMISSION_GRANTED;
-    }
-
-    @Override
-    public void notifyOpChangedForAllPkgsInUid(int code, int uid, boolean onlyForeground,
-            @Nullable OnOpModeChangedListener callbackToIgnore) {
-        String[] uidPackageNames = getPackagesForUid(uid);
-        ArrayMap<OnOpModeChangedListener, ArraySet<String>> callbackSpecs = null;
-
-        synchronized (mLock) {
-            ArraySet<OnOpModeChangedListener> callbacks = mOpModeWatchers.get(code);
-            if (callbacks != null) {
-                final int callbackCount = callbacks.size();
-                for (int i = 0; i < callbackCount; i++) {
-                    OnOpModeChangedListener callback = callbacks.valueAt(i);
-
-                    if (onlyForeground && (callback.getFlags()
-                            & WATCH_FOREGROUND_CHANGES) == 0) {
-                        continue;
-                    }
-
-                    ArraySet<String> changedPackages = new ArraySet<>();
-                    Collections.addAll(changedPackages, uidPackageNames);
-                    if (callbackSpecs == null) {
-                        callbackSpecs = new ArrayMap<>();
-                    }
-                    callbackSpecs.put(callback, changedPackages);
-                }
-            }
-
-            for (String uidPackageName : uidPackageNames) {
-                callbacks = mPackageModeWatchers.get(uidPackageName);
-                if (callbacks != null) {
-                    if (callbackSpecs == null) {
-                        callbackSpecs = new ArrayMap<>();
-                    }
-                    final int callbackCount = callbacks.size();
-                    for (int i = 0; i < callbackCount; i++) {
-                        OnOpModeChangedListener callback = callbacks.valueAt(i);
-
-                        if (onlyForeground && (callback.getFlags()
-                                & WATCH_FOREGROUND_CHANGES) == 0) {
-                            continue;
-                        }
-
-                        ArraySet<String> changedPackages = callbackSpecs.get(callback);
-                        if (changedPackages == null) {
-                            changedPackages = new ArraySet<>();
-                            callbackSpecs.put(callback, changedPackages);
-                        }
-                        changedPackages.add(uidPackageName);
-                    }
-                }
-            }
-
-            if (callbackSpecs != null && callbackToIgnore != null) {
-                callbackSpecs.remove(callbackToIgnore);
-            }
-        }
-
-        if (callbackSpecs == null) {
-            return;
-        }
-
-        for (int i = 0; i < callbackSpecs.size(); i++) {
-            final OnOpModeChangedListener callback = callbackSpecs.keyAt(i);
-            final ArraySet<String> reportedPackageNames = callbackSpecs.valueAt(i);
-            if (reportedPackageNames == null) {
-                mHandler.sendMessage(PooledLambda.obtainMessage(
-                        LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
-                        this, callback, code, uid, (String) null));
-
-            } else {
-                final int reportedPackageCount = reportedPackageNames.size();
-                for (int j = 0; j < reportedPackageCount; j++) {
-                    final String reportedPackageName = reportedPackageNames.valueAt(j);
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            LegacyAppOpsServiceInterfaceImpl::notifyOpChanged,
-                            this, callback, code, uid, reportedPackageName));
-                }
-            }
-        }
-    }
-
-    private static String[] getPackagesForUid(int uid) {
-        String[] packageNames = null;
-
-        // Very early during boot the package manager is not yet or not yet fully started. At this
-        // time there are no packages yet.
-        if (AppGlobals.getPackageManager() != null) {
-            try {
-                packageNames = AppGlobals.getPackageManager().getPackagesForUid(uid);
-            } catch (RemoteException e) {
-                /* ignore - local call */
-            }
-        }
-        if (packageNames == null) {
-            return EmptyArray.STRING;
-        }
-        return packageNames;
-    }
-
-    @Override
-    public SparseBooleanArray evalForegroundUidOps(int uid, SparseBooleanArray foregroundOps) {
-        synchronized (mLock) {
-            return evalForegroundOps(mUidModes.get(uid), foregroundOps);
-        }
-    }
-
-    @Override
-    public SparseBooleanArray evalForegroundPackageOps(String packageName,
-            SparseBooleanArray foregroundOps, @UserIdInt int userId) {
-        synchronized (mLock) {
-            ArrayMap<String, SparseIntArray> packageModes = mUserPackageModes.get(userId, null);
-            return evalForegroundOps(packageModes == null ? null : packageModes.get(packageName),
-                    foregroundOps);
-        }
-    }
-
-    private SparseBooleanArray evalForegroundOps(SparseIntArray opModes,
-            SparseBooleanArray foregroundOps) {
-        SparseBooleanArray tempForegroundOps = foregroundOps;
-        if (opModes != null) {
-            for (int i = opModes.size() - 1; i >= 0; i--) {
-                if (opModes.valueAt(i) == AppOpsManager.MODE_FOREGROUND) {
-                    if (tempForegroundOps == null) {
-                        tempForegroundOps = new SparseBooleanArray();
-                    }
-                    evalForegroundWatchers(opModes.keyAt(i), tempForegroundOps);
-                }
-            }
-        }
-        return tempForegroundOps;
-    }
-
-    private void evalForegroundWatchers(int op, SparseBooleanArray foregroundOps) {
-        boolean curValue = foregroundOps.get(op, false);
-        ArraySet<OnOpModeChangedListener> listenerSet = mOpModeWatchers.get(op);
-        if (listenerSet != null) {
-            for (int cbi = listenerSet.size() - 1; !curValue && cbi >= 0; cbi--) {
-                if ((listenerSet.valueAt(cbi).getFlags()
-                        & AppOpsManager.WATCH_FOREGROUND_CHANGES) != 0) {
-                    curValue = true;
-                }
-            }
-        }
-        foregroundOps.put(op, curValue);
-    }
-
-    @Override
-    public boolean dumpListeners(int dumpOp, int dumpUid, String dumpPackage,
-            PrintWriter printWriter) {
-        boolean needSep = false;
-        if (mOpModeWatchers.size() > 0) {
-            boolean printedHeader = false;
-            for (int i = 0; i < mOpModeWatchers.size(); i++) {
-                if (dumpOp >= 0 && dumpOp != mOpModeWatchers.keyAt(i)) {
-                    continue;
-                }
-                boolean printedOpHeader = false;
-                ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
-                        mOpModeWatchers.valueAt(i);
-                for (int j = 0; j < modeChangedListenerSet.size(); j++) {
-                    final OnOpModeChangedListener listener = modeChangedListenerSet.valueAt(j);
-                    if (dumpPackage != null
-                            && dumpUid != UserHandle.getAppId(listener.getWatchingUid())) {
-                        continue;
-                    }
-                    needSep = true;
-                    if (!printedHeader) {
-                        printWriter.println("  Op mode watchers:");
-                        printedHeader = true;
-                    }
-                    if (!printedOpHeader) {
-                        printWriter.print("    Op ");
-                        printWriter.print(AppOpsManager.opToName(mOpModeWatchers.keyAt(i)));
-                        printWriter.println(":");
-                        printedOpHeader = true;
-                    }
-                    printWriter.print("      #"); printWriter.print(j); printWriter.print(": ");
-                    printWriter.println(listener.toString());
-                }
-            }
-        }
-
-        if (mPackageModeWatchers.size() > 0 && dumpOp < 0) {
-            boolean printedHeader = false;
-            for (int i = 0; i < mPackageModeWatchers.size(); i++) {
-                if (dumpPackage != null
-                        && !dumpPackage.equals(mPackageModeWatchers.keyAt(i))) {
-                    continue;
-                }
-                needSep = true;
-                if (!printedHeader) {
-                    printWriter.println("  Package mode watchers:");
-                    printedHeader = true;
-                }
-                printWriter.print("    Pkg "); printWriter.print(mPackageModeWatchers.keyAt(i));
-                printWriter.println(":");
-                ArraySet<OnOpModeChangedListener> modeChangedListenerSet =
-                        mPackageModeWatchers.valueAt(i);
-
-                for (int j = 0; j < modeChangedListenerSet.size(); j++) {
-                    printWriter.print("      #"); printWriter.print(j); printWriter.print(": ");
-                    printWriter.println(modeChangedListenerSet.valueAt(j).toString());
-                }
-            }
-        }
-        return needSep;
-    }
-
-}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 3231240..8aa898e 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5863,6 +5863,9 @@
     };
 
     private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
+        if (!device.isSink()) {
+            return false;
+        }
         for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
             if (device.getType() == type) {
                 return true;
@@ -5897,7 +5900,11 @@
                 throw new IllegalArgumentException("invalid portID " + portId);
             }
             if (!isValidCommunicationDevice(device)) {
-                throw new IllegalArgumentException("invalid device type " + device.getType());
+                if (!device.isSink()) {
+                    throw new IllegalArgumentException("device must have sink role");
+                } else {
+                    throw new IllegalArgumentException("invalid device type: " + device.getType());
+                }
             }
         }
         final String eventSource = new StringBuilder()
@@ -7092,9 +7099,10 @@
 
     private @AudioManager.DeviceVolumeBehavior
             int getDeviceVolumeBehaviorInt(@NonNull AudioDeviceAttributes device) {
-        // translate Java device type to native device type (for the devices masks for full / fixed)
-        final int audioSystemDeviceOut = AudioDeviceInfo.convertDeviceTypeToInternalDevice(
-                device.getType());
+        // Get the internal type set by the AudioDeviceAttributes constructor which is always more
+        // exact (avoids double conversions) than a conversion from SDK type via
+        // AudioDeviceInfo.convertDeviceTypeToInternalDevice()
+        final int audioSystemDeviceOut = device.getInternalType();
 
         int setDeviceVolumeBehavior = retrieveStoredDeviceVolumeBehavior(audioSystemDeviceOut);
         if (setDeviceVolumeBehavior != AudioManager.DEVICE_VOLUME_BEHAVIOR_UNSET) {
@@ -7180,6 +7188,24 @@
                         state == CONNECTION_STATE_CONNECTED ? "connected" : "disconnected")
                 .record();
         mDeviceBroker.setWiredDeviceConnectionState(attributes, state, caller);
+        // The Dynamic Soundbar mode feature introduces dynamic presence for an HDMI Audio System
+        // Client. For example, the device can start with the Audio System Client unavailable.
+        // When the feature is activated the client becomes available, therefore Audio Service
+        // requests a new HDMI Audio System Client instance when the ARC status is changed.
+        if (attributes.getInternalType() == AudioSystem.DEVICE_IN_HDMI_ARC) {
+            updateHdmiAudioSystemClient();
+        }
+    }
+
+    /**
+     * Replace the current HDMI Audio System Client.
+     * See {@link #setWiredDeviceConnectionState(AudioDeviceAttributes, int, String)}.
+     */
+    private void updateHdmiAudioSystemClient() {
+        Slog.d(TAG, "Hdmi Audio System Client is updated");
+        synchronized (mHdmiClientLock) {
+            mHdmiAudioSystemClient = mHdmiManager.getAudioSystemClient();
+        }
     }
 
     /** @see AudioManager#setTestDeviceConnectionState(AudioDeviceAttributes, boolean) */
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index d39d2d1..1b20e43 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -18,9 +18,9 @@
 
 import android.app.IWallpaperManager;
 import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupHelper;
-import android.app.backup.BackupManager;
 import android.app.backup.FullBackup;
 import android.app.backup.FullBackupDataOutput;
 import android.app.backup.WallpaperBackupHelper;
@@ -89,8 +89,8 @@
     private int mUserId = UserHandle.USER_SYSTEM;
 
     @Override
-    public void onCreate(UserHandle user, @BackupManager.OperationType int operationType) {
-        super.onCreate(user, operationType);
+    public void onCreate(UserHandle user, @BackupDestination int backupDestination) {
+        super.onCreate(user, backupDestination);
 
         mUserId = user.getIdentifier();
 
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 2f147c4..cb409fe 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -278,13 +278,6 @@
                 return -1;
             }
 
-            if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
-                // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
-                // ever be invoked when the user is encrypted or lockdown.
-                Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown");
-                return -1;
-            }
-
             final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
             if (provider == null) {
                 Slog.w(TAG, "Null provider for detectFace");
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 1c57151..229393d 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -421,13 +421,6 @@
                 return -1;
             }
 
-            if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
-                // If this happens, something in KeyguardUpdateMonitor is wrong. This should only
-                // ever be invoked when the user is encrypted or lockdown.
-                Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
-                return -1;
-            }
-
             final Pair<Integer, ServiceProvider> provider = mRegistry.getSingleProvider();
             if (provider == null) {
                 Slog.w(TAG, "Null provider for detectFingerprint");
diff --git a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
index a8e4034..408fba1 100644
--- a/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
+++ b/services/core/java/com/android/server/broadcastradio/IRadioServiceHidlImpl.java
@@ -27,6 +27,7 @@
 import android.util.Log;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.broadcastradio.hal2.AnnouncementAggregator;
 
@@ -51,15 +52,17 @@
     private final Object mLock = new Object();
 
     private final BroadcastRadioService mService;
+
+    @GuardedBy("mLock")
     private final List<RadioManager.ModuleProperties> mV1Modules;
 
     IRadioServiceHidlImpl(BroadcastRadioService service) {
         mService = Objects.requireNonNull(service, "broadcast radio service cannot be null");
-        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService(mLock);
+        mHal1 = new com.android.server.broadcastradio.hal1.BroadcastRadioService();
         mV1Modules = mHal1.loadModules();
         OptionalInt max = mV1Modules.stream().mapToInt(RadioManager.ModuleProperties::getId).max();
         mHal2 = new com.android.server.broadcastradio.hal2.BroadcastRadioService(
-                max.isPresent() ? max.getAsInt() + 1 : 0, mLock);
+                max.isPresent() ? max.getAsInt() + 1 : 0);
     }
 
     @VisibleForTesting
@@ -78,9 +81,11 @@
     public List<RadioManager.ModuleProperties> listModules() {
         mService.enforcePolicyAccess();
         Collection<RadioManager.ModuleProperties> v2Modules = mHal2.listModules();
-        List<RadioManager.ModuleProperties> modules = new ArrayList<>(
-                mV1Modules.size() + v2Modules.size());
-        modules.addAll(mV1Modules);
+        List<RadioManager.ModuleProperties> modules;
+        synchronized (mLock) {
+            modules = new ArrayList<>(mV1Modules.size() + v2Modules.size());
+            modules.addAll(mV1Modules);
+        }
         modules.addAll(v2Modules);
         return modules;
     }
@@ -131,7 +136,9 @@
         radioPw.printf("HAL1: %s\n", mHal1);
 
         radioPw.increaseIndent();
-        radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
+        synchronized (mLock) {
+            radioPw.printf("Modules of HAL1: %s\n", mV1Modules);
+        }
         radioPw.decreaseIndent();
 
         radioPw.printf("HAL2:\n");
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
index 1d71121..03acf72 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/BroadcastRadioServiceImpl.java
@@ -77,7 +77,7 @@
                 }
 
                 RadioModule radioModule =
-                        RadioModule.tryLoadingModule(moduleId, name, newBinder, mLock);
+                        RadioModule.tryLoadingModule(moduleId, name, newBinder);
                 if (radioModule == null) {
                     Slogf.w(TAG, "No module %s with id %d (HAL AIDL)", name, moduleId);
                     return;
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
index eb9dafb..e956a9c 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/RadioModule.java
@@ -55,7 +55,7 @@
 
     private final IBroadcastRadio mService;
 
-    private final Object mLock;
+    private final Object mLock = new Object();
     private final Handler mHandler;
     private final RadioLogger mLogger;
     private final RadioManager.ModuleProperties mProperties;
@@ -165,18 +165,15 @@
     };
 
     @VisibleForTesting
-    RadioModule(IBroadcastRadio service,
-            RadioManager.ModuleProperties properties, Object lock) {
+    RadioModule(IBroadcastRadio service, RadioManager.ModuleProperties properties) {
         mProperties = Objects.requireNonNull(properties, "properties cannot be null");
         mService = Objects.requireNonNull(service, "service cannot be null");
-        mLock = Objects.requireNonNull(lock, "lock cannot be null");
         mHandler = new Handler(Looper.getMainLooper());
         mLogger = new RadioLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE);
     }
 
     @Nullable
-    static RadioModule tryLoadingModule(int moduleId, String moduleName,
-            IBinder serviceBinder, Object lock) {
+    static RadioModule tryLoadingModule(int moduleId, String moduleName, IBinder serviceBinder) {
         try {
             Slogf.i(TAG, "Try loading module for module id = %d, module name = %s",
                     moduleId, moduleName);
@@ -206,7 +203,7 @@
             RadioManager.ModuleProperties prop = ConversionUtils.propertiesFromHalProperties(
                     moduleId, moduleName, service.getProperties(), amfmConfig, dabConfig);
 
-            return new RadioModule(service, prop, lock);
+            return new RadioModule(service, prop);
         } catch (RemoteException ex) {
             Slogf.e(TAG, ex, "Failed to load module %s", moduleName);
             return null;
@@ -222,9 +219,7 @@
     }
 
     void setInternalHalCallback() throws RemoteException {
-        synchronized (mLock) {
-            mService.setTunerCallback(mHalTunerCallback);
-        }
+        mService.setTunerCallback(mHalTunerCallback);
     }
 
     TunerSession openSession(android.hardware.radio.ITunerCallback userCb)
@@ -234,7 +229,7 @@
         Boolean antennaConnected;
         RadioManager.ProgramInfo currentProgramInfo;
         synchronized (mLock) {
-            tunerSession = new TunerSession(this, mService, userCb, mLock);
+            tunerSession = new TunerSession(this, mService, userCb);
             mAidlTunerSessions.add(tunerSession);
             antennaConnected = mAntennaConnected;
             currentProgramInfo = mCurrentProgramInfo;
@@ -356,14 +351,14 @@
             // Otherwise, update the HAL's filter, and AIDL clients will be updated when
             // mHalTunerCallback.onProgramListUpdated() is called.
             mUnionOfAidlProgramFilters = newFilter;
-            try {
-                mService.startProgramListUpdates(
-                        ConversionUtils.filterToHalProgramFilter(newFilter));
-            } catch (RuntimeException ex) {
-                throw ConversionUtils.throwOnError(ex, /* action= */ "Start Program ListUpdates");
-            } catch (RemoteException ex) {
-                Slogf.e(TAG, ex, "mHalTunerSession.startProgramListUpdates() failed");
-            }
+        }
+        try {
+            mService.startProgramListUpdates(
+                    ConversionUtils.filterToHalProgramFilter(newFilter));
+        } catch (RuntimeException ex) {
+            throw ConversionUtils.throwOnError(ex, /* action= */ "Start Program ListUpdates");
+        } catch (RemoteException ex) {
+            Slogf.e(TAG, ex, "mHalTunerSession.startProgramListUpdates() failed");
         }
     }
 
@@ -453,12 +448,10 @@
             }
         };
 
-        synchronized (mLock) {
-            try {
-                hwCloseHandle[0] = mService.registerAnnouncementListener(hwListener, enabledList);
-            } catch (RuntimeException ex) {
-                throw ConversionUtils.throwOnError(ex, /* action= */ "AnnouncementListener");
-            }
+        try {
+            hwCloseHandle[0] = mService.registerAnnouncementListener(hwListener, enabledList);
+        } catch (RuntimeException ex) {
+            throw ConversionUtils.throwOnError(ex, /* action= */ "AnnouncementListener");
         }
 
         return new android.hardware.radio.ICloseHandle.Stub() {
@@ -478,12 +471,10 @@
         if (id == 0) throw new IllegalArgumentException("Image ID is missing");
 
         byte[] rawImage;
-        synchronized (mLock) {
-            try {
-                rawImage = mService.getImage(id);
-            } catch (RemoteException ex) {
-                throw ex.rethrowFromSystemServer();
-            }
+        try {
+            rawImage = mService.getImage(id);
+        } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
 
         if (rawImage == null || rawImage.length == 0) return null;
diff --git a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
index d33633c..1ce4044 100644
--- a/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/aidl/TunerSession.java
@@ -42,7 +42,7 @@
     private static final String TAG = "BcRadioAidlSrv.session";
     private static final int TUNER_EVENT_LOGGER_QUEUE_SIZE = 25;
 
-    private final Object mLock;
+    private final Object mLock = new Object();
 
     private final RadioLogger mLogger;
     private final RadioModule mModule;
@@ -61,12 +61,10 @@
     private RadioManager.BandConfig mPlaceHolderConfig;
 
     TunerSession(RadioModule radioModule, IBroadcastRadio service,
-            android.hardware.radio.ITunerCallback callback,
-            Object lock) {
+            android.hardware.radio.ITunerCallback callback) {
         mModule = Objects.requireNonNull(radioModule, "radioModule cannot be null");
         mService = Objects.requireNonNull(service, "service cannot be null");
         mCallback = Objects.requireNonNull(callback, "callback cannot be null");
-        mLock = Objects.requireNonNull(lock, "lock cannot be null");
         mLogger = new RadioLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
     }
 
@@ -91,17 +89,19 @@
             mLogger.logRadioEvent("Close tuner session on error %d", error);
         }
         synchronized (mLock) {
-            if (mIsClosed) return;
-            if (error != null) {
-                try {
-                    mCallback.onError(error);
-                } catch (RemoteException ex) {
-                    Slogf.w(TAG, ex, "mCallback.onError(%s) failed", error);
-                }
+            if (mIsClosed) {
+                return;
             }
             mIsClosed = true;
-            mModule.onTunerSessionClosed(this);
         }
+        if (error != null) {
+            try {
+                mCallback.onError(error);
+            } catch (RemoteException ex) {
+                Slogf.w(TAG, ex, "mCallback.onError(%s) failed", error);
+            }
+        }
+        mModule.onTunerSessionClosed(this);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
index e50c6e8..fb42c94 100644
--- a/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal1/BroadcastRadioService.java
@@ -36,7 +36,7 @@
      */
     private final long mNativeContext = nativeInit();
 
-    private final Object mLock;
+    private final Object mLock = new Object();
 
     @Override
     protected void finalize() throws Throwable {
@@ -50,14 +50,6 @@
     private native Tuner nativeOpenTuner(long nativeContext, int moduleId,
             RadioManager.BandConfig config, boolean withAudio, ITunerCallback callback);
 
-    /**
-     * Constructor. should pass
-     * {@code com.android.server.broadcastradio.BroadcastRadioService#mLock} for lock.
-     */
-    public BroadcastRadioService(Object lock) {
-        mLock = lock;
-    }
-
     public @NonNull List<RadioManager.ModuleProperties> loadModules() {
         synchronized (mLock) {
             return Objects.requireNonNull(nativeLoadModules(mNativeContext));
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
index 3d69627..984bf51 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
@@ -43,13 +43,16 @@
 import java.util.Objects;
 import java.util.stream.Collectors;
 
-public class BroadcastRadioService {
+/**
+ * Broadcast radio service using BroadcastRadio HIDL 2.0 HAL
+ */
+public final class BroadcastRadioService {
     private static final String TAG = "BcRadio2Srv";
 
-    private final Object mLock;
+    private final Object mLock = new Object();
 
     @GuardedBy("mLock")
-    private int mNextModuleId = 0;
+    private int mNextModuleId;
 
     @GuardedBy("mLock")
     private final Map<String, Integer> mServiceNameToModuleIdMap = new HashMap<>();
@@ -72,7 +75,7 @@
                     moduleId = mNextModuleId;
                 }
 
-                RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName, mLock);
+                RadioModule module = RadioModule.tryLoadingModule(moduleId, serviceName);
                 if (module == null) {
                     return;
                 }
@@ -120,9 +123,8 @@
         }
     };
 
-    public BroadcastRadioService(int nextModuleId, Object lock) {
+    public BroadcastRadioService(int nextModuleId) {
         mNextModuleId = nextModuleId;
-        mLock = lock;
         try {
             IServiceManager manager = IServiceManager.getService();
             if (manager == null) {
@@ -136,9 +138,8 @@
     }
 
     @VisibleForTesting
-    BroadcastRadioService(int nextModuleId, Object lock, IServiceManager manager) {
+    BroadcastRadioService(int nextModuleId, IServiceManager manager) {
         mNextModuleId = nextModuleId;
-        mLock = lock;
         Objects.requireNonNull(manager, "Service manager cannot be null");
         try {
             manager.registerForNotifications(IBroadcastRadio.kInterfaceName, "", mServiceListener);
@@ -180,7 +181,7 @@
             throw new IllegalArgumentException("Non-audio sessions not supported with HAL 2.0");
         }
 
-        RadioModule module = null;
+        RadioModule module;
         synchronized (mLock) {
             module = mModules.get(moduleId);
             if (module == null) {
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
index cf1b504..0ea5f0f 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/RadioModule.java
@@ -60,7 +60,7 @@
     @NonNull private final IBroadcastRadio mService;
     @NonNull private final RadioManager.ModuleProperties mProperties;
 
-    private final Object mLock;
+    private final Object mLock = new Object();
     @NonNull private final Handler mHandler;
     @NonNull private final RadioEventLogger mEventLogger;
 
@@ -75,7 +75,7 @@
     private RadioManager.ProgramInfo mCurrentProgramInfo = null;
 
     @GuardedBy("mLock")
-    private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(null);
+    private final ProgramInfoCache mProgramInfoCache = new ProgramInfoCache(/* filter= */ null);
 
     @GuardedBy("mLock")
     private android.hardware.radio.ProgramList.Filter mUnionOfAidlProgramFilters = null;
@@ -84,47 +84,59 @@
     private final ITunerCallback mHalTunerCallback = new ITunerCallback.Stub() {
         @Override
         public void onTuneFailed(int result, ProgramSelector programSelector) {
-            lockAndFireLater(() -> {
+            fireLater(() -> {
                 android.hardware.radio.ProgramSelector csel =
                         Convert.programSelectorFromHal(programSelector);
-                fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+                synchronized (mLock) {
+                    fanoutAidlCallbackLocked(cb -> cb.onTuneFailed(result, csel));
+                }
             });
         }
 
         @Override
         public void onCurrentProgramInfoChanged(ProgramInfo halProgramInfo) {
-            lockAndFireLater(() -> {
-                mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
-                fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(mCurrentProgramInfo));
+            fireLater(() -> {
+                synchronized (mLock) {
+                    mCurrentProgramInfo = Convert.programInfoFromHal(halProgramInfo);
+                    RadioManager.ProgramInfo currentProgramInfo = mCurrentProgramInfo;
+                    fanoutAidlCallbackLocked(cb -> cb.onCurrentProgramInfoChanged(
+                            currentProgramInfo));
+                }
             });
         }
 
         @Override
         public void onProgramListUpdated(ProgramListChunk programListChunk) {
-            lockAndFireLater(() -> {
+            fireLater(() -> {
                 android.hardware.radio.ProgramList.Chunk chunk =
                         Convert.programListChunkFromHal(programListChunk);
-                mProgramInfoCache.filterAndApplyChunk(chunk);
+                synchronized (mLock) {
+                    mProgramInfoCache.filterAndApplyChunk(chunk);
 
-                for (TunerSession tunerSession : mAidlTunerSessions) {
-                    tunerSession.onMergedProgramListUpdateFromHal(chunk);
+                    for (TunerSession tunerSession : mAidlTunerSessions) {
+                        tunerSession.onMergedProgramListUpdateFromHal(chunk);
+                    }
                 }
             });
         }
 
         @Override
         public void onAntennaStateChange(boolean connected) {
-            lockAndFireLater(() -> {
-                mAntennaConnected = connected;
-                fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
+            fireLater(() -> {
+                synchronized (mLock) {
+                    mAntennaConnected = connected;
+                    fanoutAidlCallbackLocked(cb -> cb.onAntennaState(connected));
+                }
             });
         }
 
         @Override
         public void onParametersUpdated(ArrayList<VendorKeyValue> parameters) {
-            lockAndFireLater(() -> {
+            fireLater(() -> {
                 Map<String, String> cparam = Convert.vendorInfoFromHal(parameters);
-                fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+                synchronized (mLock) {
+                    fanoutAidlCallbackLocked(cb -> cb.onParametersUpdated(cparam));
+                }
             });
         }
     };
@@ -135,17 +147,15 @@
 
     @VisibleForTesting
     RadioModule(@NonNull IBroadcastRadio service,
-            @NonNull RadioManager.ModuleProperties properties, @NonNull Object lock) {
+            @NonNull RadioManager.ModuleProperties properties) {
         mProperties = Objects.requireNonNull(properties);
         mService = Objects.requireNonNull(service);
-        mLock = Objects.requireNonNull(lock);
         mHandler = new Handler(Looper.getMainLooper());
         mEventLogger = new RadioEventLogger(TAG, RADIO_EVENT_LOGGER_QUEUE_SIZE);
     }
 
     @Nullable
-    static RadioModule tryLoadingModule(int idx, @NonNull String fqName,
-            Object lock) {
+    static RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
         try {
             Slog.i(TAG, "Try loading module for idx " + idx + ", fqName " + fqName);
             IBroadcastRadio service = IBroadcastRadio.getService(fqName);
@@ -167,7 +177,7 @@
             RadioManager.ModuleProperties prop = Convert.propertiesFromHal(idx, fqName,
                     service.getProperties(), amfmConfig.value, dabConfig.value);
 
-            return new RadioModule(service, prop, lock);
+            return new RadioModule(service, prop);
         } catch (RemoteException ex) {
             Slog.e(TAG, "Failed to load module " + fqName, ex);
             return null;
@@ -196,8 +206,7 @@
                 });
                 mHalTunerSession = Objects.requireNonNull(hwSession.value);
             }
-            TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb,
-                    mLock);
+            TunerSession tunerSession = new TunerSession(this, mHalTunerSession, userCb);
             mAidlTunerSessions.add(tunerSession);
 
             // Propagate state to new client. Note: These callbacks are invoked while holding mLock
@@ -229,6 +238,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     @Nullable
     private android.hardware.radio.ProgramList.Filter
             buildUnionOfTunerSessionFiltersLocked() {
@@ -281,6 +291,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void onTunerSessionProgramListFilterChangedLocked(@Nullable TunerSession session) {
         android.hardware.radio.ProgramList.Filter newFilter =
                 buildUnionOfTunerSessionFiltersLocked();
@@ -325,6 +336,7 @@
         }
     }
 
+    @GuardedBy("mLock")
     private void onTunerSessionsClosedLocked(TunerSession... tunerSessions) {
         for (TunerSession tunerSession : tunerSessions) {
             mAidlTunerSessions.remove(tunerSession);
@@ -342,12 +354,8 @@
     }
 
     // add to mHandler queue, but ensure the runnable holds mLock when it gets executed
-    private void lockAndFireLater(Runnable r) {
-        mHandler.post(() -> {
-            synchronized (mLock) {
-                r.run();
-            }
-        });
+    private void fireLater(Runnable r) {
+        mHandler.post(() -> r.run());
     }
 
     interface AidlCallbackRunnable {
@@ -356,9 +364,14 @@
 
     // Invokes runnable with each TunerSession currently open.
     void fanoutAidlCallback(AidlCallbackRunnable runnable) {
-        lockAndFireLater(() -> fanoutAidlCallbackLocked(runnable));
+        fireLater(() -> {
+            synchronized (mLock) {
+                fanoutAidlCallbackLocked(runnable);
+            }
+        });
     }
 
+    @GuardedBy("mLock")
     private void fanoutAidlCallbackLocked(AidlCallbackRunnable runnable) {
         List<TunerSession> deadSessions = null;
         for (TunerSession tunerSession : mAidlTunerSessions) {
@@ -399,12 +412,10 @@
             }
         };
 
-        synchronized (mLock) {
-            mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHnd) -> {
-                halResult.value = result;
-                hwCloseHandle.value = closeHnd;
-            });
-        }
+        mService.registerAnnouncementListener(enabledList, hwListener, (result, closeHandle) -> {
+            halResult.value = result;
+            hwCloseHandle.value = closeHandle;
+        });
         Convert.throwOnError("addAnnouncementListener", halResult.value);
 
         return new android.hardware.radio.ICloseHandle.Stub() {
@@ -424,12 +435,10 @@
         if (id == 0) throw new IllegalArgumentException("Image ID is missing");
 
         byte[] rawImage;
-        synchronized (mLock) {
-            List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
-            rawImage = new byte[rawList.size()];
-            for (int i = 0; i < rawList.size(); i++) {
-                rawImage[i] = rawList.get(i);
-            }
+        List<Byte> rawList = Utils.maybeRethrow(() -> mService.getImage(id));
+        rawImage = new byte[rawList.size()];
+        for (int i = 0; i < rawList.size(); i++) {
+            rawImage[i] = rawList.get(i);
         }
 
         if (rawImage == null || rawImage.length == 0) return null;
@@ -440,17 +449,17 @@
     void dumpInfo(IndentingPrintWriter pw) {
         pw.printf("RadioModule\n");
         pw.increaseIndent();
+        pw.printf("BroadcastRadioService: %s\n", mService);
+        pw.printf("Properties: %s\n", mProperties);
         synchronized (mLock) {
-            pw.printf("BroadcastRadioService: %s\n", mService);
-            pw.printf("Properties: %s\n", mProperties);
-            pw.printf("HIDL2.0 HAL TunerSession: %s\n", mHalTunerSession);
+            pw.printf("HIDL 2.0 HAL TunerSession: %s\n", mHalTunerSession);
             pw.printf("Is antenna connected? ");
             if (mAntennaConnected == null) {
                 pw.printf("null\n");
             } else {
                 pw.printf("%s\n", mAntennaConnected ? "Yes" : "No");
             }
-            pw.printf("current ProgramInfo: %s\n", mCurrentProgramInfo);
+            pw.printf("Current ProgramInfo: %s\n", mCurrentProgramInfo);
             pw.printf("ProgramInfoCache: %s\n", mProgramInfoCache);
             pw.printf("Union of AIDL ProgramFilters: %s\n", mUnionOfAidlProgramFilters);
             pw.printf("AIDL TunerSessions:\n");
diff --git a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
index 12211ee..7afee27 100644
--- a/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
+++ b/services/core/java/com/android/server/broadcastradio/hal2/TunerSession.java
@@ -33,6 +33,7 @@
 import android.util.MutableInt;
 import android.util.Slog;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.server.broadcastradio.RadioServiceUserController;
 import com.android.server.utils.Slogf;
 
@@ -46,26 +47,28 @@
     private static final String kAudioDeviceName = "Radio tuner source";
     private static final int TUNER_EVENT_LOGGER_QUEUE_SIZE = 25;
 
-    private final Object mLock;
+    private final Object mLock = new Object();
     @NonNull private final RadioEventLogger mEventLogger;
 
     private final RadioModule mModule;
     private final ITunerSession mHwSession;
     final android.hardware.radio.ITunerCallback mCallback;
+
+    @GuardedBy("mLock")
     private boolean mIsClosed = false;
+    @GuardedBy("mLock")
     private boolean mIsMuted = false;
+    @GuardedBy("mLock")
     private ProgramInfoCache mProgramInfoCache = null;
 
     // necessary only for older APIs compatibility
     private RadioManager.BandConfig mDummyConfig = null;
 
     TunerSession(@NonNull RadioModule module, @NonNull ITunerSession hwSession,
-            @NonNull android.hardware.radio.ITunerCallback callback,
-            @NonNull Object lock) {
+            @NonNull android.hardware.radio.ITunerCallback callback) {
         mModule = Objects.requireNonNull(module);
         mHwSession = Objects.requireNonNull(hwSession);
         mCallback = Objects.requireNonNull(callback);
-        mLock = Objects.requireNonNull(lock);
         mEventLogger = new RadioEventLogger(TAG, TUNER_EVENT_LOGGER_QUEUE_SIZE);
     }
 
@@ -86,23 +89,26 @@
         mEventLogger.logRadioEvent("Close on error %d", error);
         synchronized (mLock) {
             if (mIsClosed) return;
-            if (error != null) {
-                try {
-                    mCallback.onError(error);
-                } catch (RemoteException ex) {
-                    Slog.w(TAG, "mCallback.onError() failed: ", ex);
-                }
-            }
             mIsClosed = true;
-            mModule.onTunerSessionClosed(this);
         }
+        if (error != null) {
+            try {
+                mCallback.onError(error);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "mCallback.onError() failed: ", ex);
+            }
+        }
+        mModule.onTunerSessionClosed(this);
     }
 
     @Override
     public boolean isClosed() {
-        return mIsClosed;
+        synchronized (mLock) {
+            return mIsClosed;
+        }
     }
 
+    @GuardedBy("mLock")
     private void checkNotClosedLocked() {
         if (mIsClosed) {
             throw new IllegalStateException("Tuner is closed, no further operations are allowed");
@@ -118,9 +124,9 @@
         synchronized (mLock) {
             checkNotClosedLocked();
             mDummyConfig = Objects.requireNonNull(config);
-            Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.0");
-            mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
         }
+        Slog.i(TAG, "Ignoring setConfiguration - not applicable for broadcastradio HAL 2.0");
+        mModule.fanoutAidlCallback(cb -> cb.onConfigurationChanged(config));
     }
 
     @Override
@@ -137,8 +143,8 @@
             checkNotClosedLocked();
             if (mIsMuted == mute) return;
             mIsMuted = mute;
-            Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
         }
+        Slog.w(TAG, "Mute via RadioService is not implemented - please handle it via app");
     }
 
     @Override
@@ -383,8 +389,8 @@
     void dumpInfo(IndentingPrintWriter pw) {
         pw.printf("TunerSession\n");
         pw.increaseIndent();
+        pw.printf("HIDL HAL Session: %s\n", mHwSession);
         synchronized (mLock) {
-            pw.printf("HIDL HAL Session: %s\n", mHwSession);
             pw.printf("Is session closed? %s\n", mIsClosed ? "Yes" : "No");
             pw.printf("Is muted? %s\n", mIsMuted ? "Yes" : "No");
             pw.printf("ProgramInfoCache: %s\n", mProgramInfoCache);
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index b882c47..e16ca0b 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -551,6 +551,15 @@
                     lensFacing, ignoreResizableAndSdkCheck);
         }
 
+        /**
+         * Placeholder method to fetch the system state for autoframing.
+         * TODO: b/260617354
+         */
+        @Override
+        public int getAutoframingOverride(String packageName) {
+            return CaptureRequest.CONTROL_AUTOFRAMING_OFF;
+        }
+
         @Override
         public void pingForUserUpdate() {
             if (Binder.getCallingUid() != Process.CAMERASERVER_UID) {
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index eb81e70..dcc98e1 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -27,6 +27,7 @@
 import android.accounts.AccountManagerInternal;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SuppressLint;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
@@ -65,6 +66,7 @@
 import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
 import android.net.NetworkInfo;
@@ -88,6 +90,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.WorkSource;
+import android.provider.ContactsContract;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.text.format.TimeMigrationUtils;
@@ -99,6 +102,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
@@ -498,7 +502,7 @@
             }
             mJobScheduler = (JobScheduler) mContext.getSystemService(
                     Context.JOB_SCHEDULER_SERVICE);
-            mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
+            mJobSchedulerInternal = getJobSchedulerInternal();
             // Get all persisted syncs from JobScheduler
             List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
 
@@ -536,6 +540,11 @@
         }
     }
 
+    @VisibleForTesting
+    protected JobSchedulerInternal getJobSchedulerInternal() {
+        return LocalServices.getService(JobSchedulerInternal.class);
+    }
+
     /**
      * @return whether the device most likely has some periodic syncs.
      */
@@ -645,7 +654,7 @@
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mAccountManager = (AccountManager) mContext.getSystemService(Context.ACCOUNT_SERVICE);
-        mAccountManagerInternal = LocalServices.getService(AccountManagerInternal.class);
+        mAccountManagerInternal = getAccountManagerInternal();
         mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
         mAmi = LocalServices.getService(ActivityManagerInternal.class);
 
@@ -719,6 +728,11 @@
         mLogger.log("Sync manager initialized: " + Build.FINGERPRINT);
     }
 
+    @VisibleForTesting
+    protected AccountManagerInternal getAccountManagerInternal() {
+        return LocalServices.getService(AccountManagerInternal.class);
+    }
+
     public void onStartUser(int userId) {
         // Log on the handler to avoid slowing down device boot.
         mSyncHandler.post(() -> mLogger.log("onStartUser: user=", userId));
@@ -800,9 +814,44 @@
         return mSyncStorageEngine;
     }
 
+    @SuppressLint("AndroidFrameworkRequiresPermission")
+    private boolean areContactWritesEnabledForUser(UserInfo userInfo) {
+        final UserManager um = UserManager.get(mContext);
+        try {
+            final UserProperties userProperties = um.getUserProperties(userInfo.getUserHandle());
+            return !userProperties.getUseParentsContacts();
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Trying to fetch user properties for non-existing/partial user "
+                    + userInfo.getUserHandle());
+            return false;
+        }
+    }
+
+    /**
+     * Check if account sync should be disabled for the given user and provider.
+     * @param userInfo
+     * @param providerName
+     * @return true if sync for the account corresponding to the given user and provider should be
+     * disabled, false otherwise. Also returns false if either of the inputs are null.
+     */
+    @VisibleForTesting
+    protected boolean shouldDisableSyncForUser(UserInfo userInfo, String providerName) {
+        if (userInfo == null || providerName == null) return false;
+        return providerName.equals(ContactsContract.AUTHORITY)
+                && !areContactWritesEnabledForUser(userInfo);
+    }
+
     private int getIsSyncable(Account account, int userId, String providerName) {
         int isSyncable = mSyncStorageEngine.getIsSyncable(account, userId, providerName);
-        UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
+        final UserManager um = UserManager.get(mContext);
+        UserInfo userInfo = um.getUserInfo(userId);
+
+        // Check if the provider is allowed to sync data from linked accounts for the user
+        if (shouldDisableSyncForUser(userInfo, providerName)) {
+            Log.w(TAG, "Account sync is disabled for account: " + account
+                    + " userId: " + userId + " provider: " + providerName);
+            return AuthorityInfo.NOT_SYNCABLE;
+        }
 
         // If it's not a restricted user, return isSyncable.
         if (userInfo == null || !userInfo.isRestricted()) return isSyncable;
diff --git a/services/core/java/com/android/server/cpu/CpuAvailabilityInfo.java b/services/core/java/com/android/server/cpu/CpuAvailabilityInfo.java
new file mode 100644
index 0000000..06b45bf
--- /dev/null
+++ b/services/core/java/com/android/server/cpu/CpuAvailabilityInfo.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_ALL;
+import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_BACKGROUND;
+
+import com.android.internal.util.Preconditions;
+
+/** CPU availability information. */
+public final class CpuAvailabilityInfo {
+    /** Constant to indicate missing CPU availability percent. */
+    public static final int MISSING_CPU_AVAILABILITY_PERCENT = -1;
+
+    /**
+     * The CPUSET whose availability info is recorded in this object.
+     *
+     * <p>The contained value is one of the CPUSET_* constants from the
+     * {@link CpuAvailabilityMonitoringConfig}.
+     */
+    @CpuAvailabilityMonitoringConfig.Cpuset
+    public final int cpuset;
+
+    /** The latest average CPU availability percent. */
+    public final int latestAvgAvailabilityPercent;
+
+    /** The past N-second average CPU availability percent. */
+    public final int pastNSecAvgAvailabilityPercent;
+
+    /** The duration over which the {@link pastNSecAvgAvailabilityPercent} was calculated. */
+    public final int avgAvailabilityDurationSec;
+
+    @Override
+    public String toString() {
+        return "CpuAvailabilityInfo{" + "cpuset=" + cpuset + ", latestAvgAvailabilityPercent="
+                + latestAvgAvailabilityPercent + ", pastNSecAvgAvailabilityPercent="
+                + pastNSecAvgAvailabilityPercent + ", avgAvailabilityDurationSec="
+                + avgAvailabilityDurationSec + '}';
+    }
+
+    CpuAvailabilityInfo(int cpuset, int latestAvgAvailabilityPercent,
+            int pastNSecAvgAvailabilityPercent, int avgAvailabilityDurationSec) {
+        this.cpuset = Preconditions.checkArgumentInRange(cpuset, CPUSET_ALL, CPUSET_BACKGROUND,
+                "cpuset");
+        this.latestAvgAvailabilityPercent = latestAvgAvailabilityPercent;
+        this.pastNSecAvgAvailabilityPercent = pastNSecAvgAvailabilityPercent;
+        this.avgAvailabilityDurationSec = avgAvailabilityDurationSec;
+    }
+}
diff --git a/services/core/java/com/android/server/cpu/CpuAvailabilityMonitoringConfig.java b/services/core/java/com/android/server/cpu/CpuAvailabilityMonitoringConfig.java
new file mode 100644
index 0000000..a3c4c9e
--- /dev/null
+++ b/services/core/java/com/android/server/cpu/CpuAvailabilityMonitoringConfig.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import android.annotation.IntDef;
+import android.util.IntArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** CPU availability monitoring config. */
+public final class CpuAvailabilityMonitoringConfig {
+    /** Constant to monitor all cpusets. */
+    public static final int CPUSET_ALL = 1;
+
+    /** Constant to monitor background cpusets. */
+    public static final int CPUSET_BACKGROUND = 2;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"CPUSET_"}, value = {
+            CPUSET_ALL,
+            CPUSET_BACKGROUND
+    })
+    public @interface Cpuset {
+    }
+
+    /**
+     * The CPUSET to monitor.
+     *
+     * <p>The value must be one of the {@code CPUSET_*} constants.
+     */
+    @Cpuset
+    public final int cpuset;
+
+    /**
+     * CPU availability percent thresholds.
+     *
+     * <p>CPU availability change notifications are sent when the latest or last N seconds average
+     * CPU availability percent crosses any of these thresholds since the last notification.
+     */
+    private final IntArray mThresholds;
+
+    public IntArray getThresholds() {
+        return mThresholds;
+    }
+
+    /**
+     * Builder for the construction of {@link CpuAvailabilityMonitoringConfig} objects.
+     *
+     * <p>The builder must contain at least one threshold before calling {@link build}.
+     */
+    public static final class Builder {
+        private final int mCpuset;
+        private final IntArray mThresholds = new IntArray();
+
+        public Builder(int cpuset, int... thresholds) {
+            mCpuset = cpuset;
+            for (int threshold : thresholds) {
+                addThreshold(threshold);
+            }
+        }
+
+        /** Adds the given threshold to the builder object. */
+        public Builder addThreshold(int threshold) {
+            if (mThresholds.indexOf(threshold) == -1) {
+                mThresholds.add(threshold);
+            }
+            return this;
+        }
+
+        /** Returns the {@link CpuAvailabilityMonitoringConfig} object. */
+        public CpuAvailabilityMonitoringConfig build() {
+            return new CpuAvailabilityMonitoringConfig(this);
+        }
+    }
+
+    @Override
+    public String toString() {
+        return "CpuAvailabilityMonitoringConfig{cpuset=" + cpuset + ", mThresholds=" + mThresholds
+                + ')';
+    }
+
+    private CpuAvailabilityMonitoringConfig(Builder builder) {
+        if (builder.mCpuset != CPUSET_ALL && builder.mCpuset != CPUSET_BACKGROUND) {
+            throw new IllegalStateException("Cpuset must be either CPUSET_ALL (" + CPUSET_ALL
+                    + ") or CPUSET_BACKGROUND (" + CPUSET_BACKGROUND + "). Builder contains "
+                    + builder.mCpuset);
+        }
+        if (builder.mThresholds.size() == 0) {
+            throw new IllegalStateException("Must provide at least one threshold");
+        }
+        this.cpuset = builder.mCpuset;
+        this.mThresholds = builder.mThresholds.clone();
+    }
+}
diff --git a/services/core/java/com/android/server/cpu/CpuInfoReader.java b/services/core/java/com/android/server/cpu/CpuInfoReader.java
new file mode 100644
index 0000000..680829d
--- /dev/null
+++ b/services/core/java/com/android/server/cpu/CpuInfoReader.java
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.utils.Slogf;
+
+import java.io.File;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.file.Files;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** Reader to read CPU information from proc and sys fs files exposed by the Kernel. */
+public final class CpuInfoReader {
+    static final String TAG = CpuInfoReader.class.getSimpleName();
+    static final int FLAG_CPUSET_CATEGORY_TOP_APP = 1 << 0;
+    static final int FLAG_CPUSET_CATEGORY_BACKGROUND = 1 << 1;
+
+    private static final String CPUFREQ_DIR_PATH = "/sys/devices/system/cpu/cpufreq";
+    private static final String POLICY_DIR_PREFIX = "policy";
+    private static final String RELATED_CPUS_FILE = "related_cpus";
+    private static final String MAX_CPUFREQ_FILE = "cpuinfo_max_freq";
+    private static final String MAX_SCALING_FREQ_FILE = "scaling_max_freq";
+    private static final String CPUSET_DIR_PATH = "/dev/cpuset";
+    private static final String CPUSET_TOP_APP_DIR = "top-app";
+    private static final String CPUSET_BACKGROUND_DIR = "background";
+    private static final String CPUS_FILE = "cpus";
+    private static final String PROC_STAT_FILE_PATH = "/proc/stat";
+    private static final Pattern PROC_STAT_PATTERN =
+            Pattern.compile("cpu(?<core>[0-9]+)\\s(?<userClockTicks>[0-9]+)\\s"
+                    + "(?<niceClockTicks>[0-9]+)\\s(?<sysClockTicks>[0-9]+)\\s"
+                    + "(?<idleClockTicks>[0-9]+)\\s(?<iowaitClockTicks>[0-9]+)\\s"
+                    + "(?<irqClockTicks>[0-9]+)\\s(?<softirqClockTicks>[0-9]+)\\s"
+                    + "(?<stealClockTicks>[0-9]+)\\s(?<guestClockTicks>[0-9]+)\\s"
+                    + "(?<guestNiceClockTicks>[0-9]+)");
+    private static final long MILLIS_PER_JIFFY = 1000L / Os.sysconf(OsConstants._SC_CLK_TCK);
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = {"FLAG_CPUSET_CATEGORY_"}, flag = true, value = {
+            FLAG_CPUSET_CATEGORY_TOP_APP,
+            FLAG_CPUSET_CATEGORY_BACKGROUND
+    })
+    private @interface CpusetCategory{}
+
+    private final File mCpusetDir;
+    private final File mCpuFreqDir;
+    private final File mProcStatFile;
+    private final SparseIntArray mCpusetCategoriesByCpus = new SparseIntArray();
+    private final SparseArray<Long> mMaxCpuFrequenciesByCpus = new SparseArray<>();
+
+    private File[] mCpuFreqPolicyDirs;
+    private SparseArray<CpuUsageStats> mCumulativeCpuUsageStats = new SparseArray<>();
+    private boolean mIsEnabled;
+
+    public CpuInfoReader() {
+        this(new File(CPUSET_DIR_PATH), new File(CPUFREQ_DIR_PATH), new File(PROC_STAT_FILE_PATH));
+    }
+
+    @VisibleForTesting
+    CpuInfoReader(File cpusetDir, File cpuFreqDir, File procStatFile) {
+        mCpusetDir = cpusetDir;
+        mCpuFreqDir = cpuFreqDir;
+        mProcStatFile = procStatFile;
+    }
+
+    /** Inits CpuInfoReader and returns a boolean to indicate whether the reader is enabled. */
+    public boolean init() {
+        mCpuFreqPolicyDirs = mCpuFreqDir.listFiles(
+                file -> file.isDirectory() && file.getName().startsWith(POLICY_DIR_PREFIX));
+        if (mCpuFreqPolicyDirs == null || mCpuFreqPolicyDirs.length == 0) {
+            Slogf.w(TAG, "Missing CPU frequency policy directories at %s",
+                    mCpuFreqDir.getAbsolutePath());
+            return false;
+        }
+        if (!mProcStatFile.exists()) {
+            Slogf.e(TAG, "Missing proc stat file at %s", mProcStatFile.getAbsolutePath());
+            return false;
+        }
+        readCpusetCategories();
+        if (mCpusetCategoriesByCpus.size() == 0) {
+            Slogf.e(TAG, "Failed to read cpuset information read from %s",
+                    mCpusetDir.getAbsolutePath());
+            return false;
+        }
+        readMaxCpuFrequencies();
+        if (mMaxCpuFrequenciesByCpus.size() == 0) {
+            Slogf.e(TAG, "Failed to read max CPU frequencies from policy directories at %s",
+                    mCpuFreqDir.getAbsolutePath());
+            return false;
+        }
+        mIsEnabled = true;
+        return true;
+    }
+
+    /** Reads CPU information from proc and sys fs files exposed by the Kernel. */
+    public List<CpuInfo> readCpuInfos() {
+        if (!mIsEnabled) {
+            return Collections.emptyList();
+        }
+        SparseArray<CpuUsageStats> latestCpuUsageStats = readLatestCpuUsageStats();
+        if (latestCpuUsageStats == null) {
+            Slogf.e(TAG, "Failed to read latest CPU usage stats");
+            return Collections.emptyList();
+        }
+        // TODO(b/217422127): Read current CPU frequencies and populate the CpuInfo.
+        return Collections.emptyList();
+    }
+
+    private void readCpusetCategories() {
+        File[] cpusetDirs = mCpusetDir.listFiles(File::isDirectory);
+        if (cpusetDirs == null) {
+            Slogf.e(TAG, "Missing cpuset directories at %s", mCpusetDir.getAbsolutePath());
+            return;
+        }
+        for (int i = 0; i < cpusetDirs.length; i++) {
+            File dir = cpusetDirs[i];
+            @CpusetCategory int cpusetCategory;
+            switch (dir.getName()) {
+                case CPUSET_TOP_APP_DIR:
+                    cpusetCategory = FLAG_CPUSET_CATEGORY_TOP_APP;
+                    break;
+                case CPUSET_BACKGROUND_DIR:
+                    cpusetCategory = FLAG_CPUSET_CATEGORY_BACKGROUND;
+                    break;
+                default:
+                    continue;
+            }
+            File cpuCoresFile = new File(dir.getPath(), CPUS_FILE);
+            List<Integer> cpuCores = readCpuCores(cpuCoresFile);
+            if (cpuCores.isEmpty()) {
+                Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
+                continue;
+            }
+            for (int j = 0; j < cpuCores.size(); j++) {
+                int categories = mCpusetCategoriesByCpus.get(cpuCores.get(j));
+                categories |= cpusetCategory;
+                mCpusetCategoriesByCpus.append(cpuCores.get(j), categories);
+            }
+        }
+    }
+
+    private void readMaxCpuFrequencies() {
+        for (int i = 0; i < mCpuFreqPolicyDirs.length; i++) {
+            File policyDir = mCpuFreqPolicyDirs[i];
+            long maxCpuFreqKHz = readMaxCpuFrequency(policyDir);
+            if (maxCpuFreqKHz == 0) {
+                Slogf.w(TAG, "Invalid max CPU frequency read from %s", policyDir.getAbsolutePath());
+                continue;
+            }
+            File cpuCoresFile = new File(policyDir, RELATED_CPUS_FILE);
+            List<Integer> cpuCores = readCpuCores(cpuCoresFile);
+            if (cpuCores.isEmpty()) {
+                Slogf.e(TAG, "Failed to read CPU cores from %s", cpuCoresFile.getAbsolutePath());
+                continue;
+            }
+            for (int j = 0; j < cpuCores.size(); j++) {
+                mMaxCpuFrequenciesByCpus.append(cpuCores.get(j), maxCpuFreqKHz);
+            }
+        }
+    }
+
+    private long readMaxCpuFrequency(File policyDir) {
+        long curCpuFreqKHz = readCpuFreqKHz(new File(policyDir, MAX_CPUFREQ_FILE));
+        return curCpuFreqKHz > 0 ? curCpuFreqKHz
+                : readCpuFreqKHz(new File(policyDir, MAX_SCALING_FREQ_FILE));
+    }
+
+    private static long readCpuFreqKHz(File file) {
+        if (!file.exists()) {
+            Slogf.e(TAG, "CPU frequency file %s doesn't exist", file.getAbsolutePath());
+            return 0;
+        }
+        try {
+            List<String> lines = Files.readAllLines(file.toPath());
+            if (!lines.isEmpty()) {
+                long frequency = Long.parseLong(lines.get(0).trim());
+                return frequency > 0 ? frequency : 0;
+            }
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "Failed to read integer content from file: %s", file.getAbsolutePath());
+        }
+        return 0;
+    }
+
+    /**
+     * Reads the list of CPU cores from the given file.
+     *
+     * Reads CPU cores represented in one of the below formats.
+     * <ul>
+     * <li> Single core id. Eg: 1
+     * <li> Core id range. Eg: 1-4
+     * <li> Comma separated values. Eg: 1, 3-5, 7
+     * </ul>
+     */
+    private static List<Integer> readCpuCores(File file) {
+        if (!file.exists()) {
+            Slogf.e(TAG, "Failed to read CPU cores as the file '%s' doesn't exist",
+                    file.getAbsolutePath());
+            return Collections.emptyList();
+        }
+        try {
+            List<String> lines = Files.readAllLines(file.toPath());
+            List<Integer> cpuCores = new ArrayList<>();
+            for (int i = 0; i < lines.size(); i++) {
+                String[] pairs = lines.get(i).trim().split(",");
+                for (int j = 0; j < pairs.length; j++) {
+                    String[] minMaxPairs = pairs[j].split("-");
+                    if (minMaxPairs.length >= 2) {
+                        int min = Integer.parseInt(minMaxPairs[0]);
+                        int max = Integer.parseInt(minMaxPairs[1]);
+                        if (min > max) {
+                            continue;
+                        }
+                        for (int id = min; id <= max; id++) {
+                            cpuCores.add(id);
+                        }
+                    } else if (minMaxPairs.length == 1) {
+                        cpuCores.add(Integer.parseInt(minMaxPairs[0]));
+                    } else {
+                        Slogf.w(TAG, "Invalid CPU core range format %s", pairs[j]);
+                    }
+                }
+            }
+            return cpuCores;
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "Failed to read CPU cores from %s", file.getAbsolutePath());
+        }
+        return Collections.emptyList();
+    }
+
+    @Nullable
+    private SparseArray<CpuUsageStats> readLatestCpuUsageStats() {
+        SparseArray<CpuUsageStats> cumulativeCpuUsageStats = readCumulativeCpuUsageStats();
+        if (cumulativeCpuUsageStats.size() == 0) {
+            Slogf.e(TAG, "Failed to read cumulative CPU usage stats");
+            return null;
+        }
+        SparseArray<CpuUsageStats> deltaCpuUsageStats = new SparseArray();
+        for (int i = 0; i < cumulativeCpuUsageStats.size(); i++) {
+            int cpu = cumulativeCpuUsageStats.keyAt(i);
+            CpuUsageStats newStats = cumulativeCpuUsageStats.valueAt(i);
+            CpuUsageStats oldStats = mCumulativeCpuUsageStats.get(cpu);
+            deltaCpuUsageStats.append(cpu, oldStats == null ? newStats : newStats.delta(oldStats));
+        }
+        mCumulativeCpuUsageStats = cumulativeCpuUsageStats;
+        return deltaCpuUsageStats;
+    }
+
+    private SparseArray<CpuUsageStats> readCumulativeCpuUsageStats() {
+        SparseArray<CpuUsageStats> cpuUsageStats = new SparseArray<>();
+        try {
+            List<String> lines = Files.readAllLines(mProcStatFile.toPath());
+            for (int i = 0; i < lines.size(); i++) {
+                Matcher m = PROC_STAT_PATTERN.matcher(lines.get(i).trim());
+                if (!m.find()) {
+                    continue;
+                }
+                cpuUsageStats.append(Integer.parseInt(Objects.requireNonNull(m.group("core"))),
+                        new CpuUsageStats(jiffyStrToMillis(m.group("userClockTicks")),
+                                jiffyStrToMillis(m.group("niceClockTicks")),
+                                jiffyStrToMillis(m.group("sysClockTicks")),
+                                jiffyStrToMillis(m.group("idleClockTicks")),
+                                jiffyStrToMillis(m.group("iowaitClockTicks")),
+                                jiffyStrToMillis(m.group("irqClockTicks")),
+                                jiffyStrToMillis(m.group("softirqClockTicks")),
+                                jiffyStrToMillis(m.group("stealClockTicks")),
+                                jiffyStrToMillis(m.group("guestClockTicks")),
+                                jiffyStrToMillis(m.group("guestNiceClockTicks"))));
+            }
+        } catch (Exception e) {
+            Slogf.e(TAG, e, "Failed to read cpu usage stats from %s",
+                    mProcStatFile.getAbsolutePath());
+        }
+        return cpuUsageStats;
+    }
+
+    private static long jiffyStrToMillis(String jiffyStr) {
+        return Long.parseLong(Objects.requireNonNull(jiffyStr)) * MILLIS_PER_JIFFY;
+    }
+
+    /** Contains information for each CPU core on the system. */
+    public static final class CpuInfo {
+        public final int cpuCore;
+        public final @CpusetCategory int cpusetCategories;
+        public final long curCpuFreqKHz;
+        public final long maxCpuFreqKHz;
+        public final CpuUsageStats latestCpuUsageStats;
+
+        CpuInfo(int cpuCore, @CpusetCategory int cpusetCategories, long curCpuFreqKHz,
+                long maxCpuFreqKHz, CpuUsageStats latestCpuUsageStats) {
+            this.cpuCore = cpuCore;
+            this.cpusetCategories = cpusetCategories;
+            this.curCpuFreqKHz = curCpuFreqKHz;
+            this.maxCpuFreqKHz = maxCpuFreqKHz;
+            this.latestCpuUsageStats = latestCpuUsageStats;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("CpuInfo{ cpuCore = ").append(cpuCore)
+                    .append(", cpusetCategories = ").append(cpusetCategories)
+                    .append(", curCpuFreqKHz = ").append(curCpuFreqKHz)
+                    .append(", maxCpuFreqKHz = ").append(maxCpuFreqKHz)
+                    .append(", latestCpuUsageStats = ").append(latestCpuUsageStats)
+                    .append(" }").toString();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof CpuInfo)) {
+                return false;
+            }
+            CpuInfo other = (CpuInfo) obj;
+            return cpuCore == other.cpuCore && cpusetCategories == other.cpusetCategories
+                    && curCpuFreqKHz == other.curCpuFreqKHz
+                    && maxCpuFreqKHz == other.maxCpuFreqKHz
+                    && latestCpuUsageStats.equals(other.latestCpuUsageStats);
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(cpuCore, cpusetCategories, curCpuFreqKHz, maxCpuFreqKHz,
+                    latestCpuUsageStats);
+        }
+    }
+
+    /** CPU time spent in different modes. */
+    public static final class CpuUsageStats {
+        public final long userTimeMillis;
+        public final long niceTimeMillis;
+        public final long systemTimeMillis;
+        public final long idleTimeMillis;
+        public final long iowaitTimeMillis;
+        public final long irqTimeMillis;
+        public final long softirqTimeMillis;
+        public final long stealTimeMillis;
+        public final long guestTimeMillis;
+        public final long guestNiceTimeMillis;
+
+        public CpuUsageStats(long userTimeMillis, long niceTimeMillis, long systemTimeMillis,
+                long idleTimeMillis, long iowaitTimeMillis, long irqTimeMillis,
+                long softirqTimeMillis, long stealTimeMillis, long guestTimeMillis,
+                long guestNiceTimeMillis) {
+            this.userTimeMillis = userTimeMillis;
+            this.niceTimeMillis = niceTimeMillis;
+            this.systemTimeMillis = systemTimeMillis;
+            this.idleTimeMillis = idleTimeMillis;
+            this.iowaitTimeMillis = iowaitTimeMillis;
+            this.irqTimeMillis = irqTimeMillis;
+            this.softirqTimeMillis = softirqTimeMillis;
+            this.stealTimeMillis = stealTimeMillis;
+            this.guestTimeMillis = guestTimeMillis;
+            this.guestNiceTimeMillis = guestNiceTimeMillis;
+        }
+
+        public long getTotalTime() {
+            return userTimeMillis + niceTimeMillis + systemTimeMillis + idleTimeMillis
+                    + iowaitTimeMillis + irqTimeMillis + softirqTimeMillis + stealTimeMillis
+                    + guestTimeMillis + guestNiceTimeMillis;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder("CpuUsageStats{ userTimeMillis = ")
+                    .append(userTimeMillis)
+                    .append(", niceTimeMillis = ").append(niceTimeMillis)
+                    .append(", systemTimeMillis = ").append(systemTimeMillis)
+                    .append(", idleTimeMillis = ").append(idleTimeMillis)
+                    .append(", iowaitTimeMillis = ").append(iowaitTimeMillis)
+                    .append(", irqTimeMillis = ").append(irqTimeMillis)
+                    .append(", softirqTimeMillis = ").append(softirqTimeMillis)
+                    .append(", stealTimeMillis = ").append(stealTimeMillis)
+                    .append(", guestTimeMillis = ").append(guestTimeMillis)
+                    .append(", guestNiceTimeMillis = ").append(guestNiceTimeMillis)
+                    .append(" }").toString();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (this == obj) {
+                return true;
+            }
+            if (!(obj instanceof CpuUsageStats)) {
+                return false;
+            }
+            CpuUsageStats other = (CpuUsageStats) obj;
+            return userTimeMillis == other.userTimeMillis && niceTimeMillis == other.niceTimeMillis
+                    && systemTimeMillis == other.systemTimeMillis
+                    && idleTimeMillis == other.idleTimeMillis
+                    && iowaitTimeMillis == other.iowaitTimeMillis
+                    && irqTimeMillis == other.irqTimeMillis
+                    && softirqTimeMillis == other.softirqTimeMillis
+                    && stealTimeMillis == other.stealTimeMillis
+                    && guestTimeMillis == other.guestTimeMillis
+                    && guestNiceTimeMillis == other.guestNiceTimeMillis;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(userTimeMillis, niceTimeMillis, systemTimeMillis, idleTimeMillis,
+                    iowaitTimeMillis, irqTimeMillis, softirqTimeMillis, stealTimeMillis,
+                    guestTimeMillis,
+                    guestNiceTimeMillis);
+        }
+
+        CpuUsageStats delta(CpuUsageStats rhs) {
+            return new CpuUsageStats(diff(userTimeMillis, rhs.userTimeMillis),
+                    diff(niceTimeMillis, rhs.niceTimeMillis),
+                    diff(systemTimeMillis, rhs.systemTimeMillis),
+                    diff(idleTimeMillis, rhs.idleTimeMillis),
+                    diff(iowaitTimeMillis, rhs.iowaitTimeMillis),
+                    diff(irqTimeMillis, rhs.irqTimeMillis),
+                    diff(softirqTimeMillis, rhs.softirqTimeMillis),
+                    diff(stealTimeMillis, rhs.stealTimeMillis),
+                    diff(guestTimeMillis, rhs.guestTimeMillis),
+                    diff(guestNiceTimeMillis, rhs.guestNiceTimeMillis));
+        }
+
+        private static long diff(long lhs, long rhs) {
+            return lhs > rhs ? lhs - rhs : 0;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorInternal.java b/services/core/java/com/android/server/cpu/CpuMonitorInternal.java
new file mode 100644
index 0000000..849a20b
--- /dev/null
+++ b/services/core/java/com/android/server/cpu/CpuMonitorInternal.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import android.annotation.CallbackExecutor;
+
+import java.util.concurrent.Executor;
+
+/** CpuMonitorInternal hosts internal APIs to monitor CPU. */
+public abstract class CpuMonitorInternal {
+    /** Callback to get CPU availability change notifications. */
+    public interface CpuAvailabilityCallback {
+        /**
+         * Called when the CPU availability crosses the provided thresholds.
+         *
+         * <p>Called when the latest or past N-second (which will be specified in the
+         * {@link CpuAvailabilityInfo}) average CPU availability percent has crossed
+         * (either goes above or drop below) the {@link CpuAvailabilityMonitoringConfig#thresholds}
+         * since the last notification. Also called when a callback is added to the service.
+         *
+         * <p>The callback is called at the executor which is specified in
+         * {@link addCpuAvailabilityCallback} or at the service handler thread.
+         *
+         * @param info CPU availability information.
+         */
+        void onAvailabilityChanged(CpuAvailabilityInfo info);
+
+        /**
+         * Called when the CPU monitoring interval changes.
+         *
+         * <p>Also called when a callback is added to the service.
+         *
+         * @param intervalMilliseconds CPU monitoring interval in milliseconds.
+         */
+        void onMonitoringIntervalChanged(long intervalMilliseconds);
+    }
+
+    /**
+     * Adds the {@link CpuAvailabilityCallback} for the caller.
+     *
+     * <p>When the callback is added, the callback will be called to notify the current CPU
+     * availability and monitoring interval.
+     *
+     * <p>When the client needs to update the {@link config} for a previously added callback,
+     * the client has to remove the callback and add the callback with a new {@link config}.
+     *
+     * @param executor Executor to execute the callback. If an executor is not provided,
+     *                 the callback will be executed on the service handler thread.
+     * @param config CPU availability monitoring config.
+     * @param callback Callback implementing {@link CpuAvailabilityCallback}
+     * interface.
+     *
+     * @throws IllegalStateException if {@code callback} is already added.
+     */
+    public abstract void addCpuAvailabilityCallback(@CallbackExecutor Executor executor,
+            CpuAvailabilityMonitoringConfig config, CpuAvailabilityCallback callback);
+
+    /**
+     * Removes the {@link CpuAvailabilityCallback} for the caller.
+     *
+     * @param callback Callback implementing {@link CpuAvailabilityCallback}
+     * interface.
+     *
+     * @throws IllegalArgumentException if {@code callback} is not previously added.
+     */
+    public abstract void removeCpuAvailabilityCallback(CpuAvailabilityCallback callback);
+}
diff --git a/services/core/java/com/android/server/cpu/CpuMonitorService.java b/services/core/java/com/android/server/cpu/CpuMonitorService.java
new file mode 100644
index 0000000..b0dfb84
--- /dev/null
+++ b/services/core/java/com/android/server/cpu/CpuMonitorService.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_CRITICAL;
+
+import android.content.Context;
+import android.os.Binder;
+import android.util.ArrayMap;
+import android.util.IndentingPrintWriter;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.DumpUtils;
+import com.android.server.SystemService;
+import com.android.server.utils.PriorityDump;
+import com.android.server.utils.Slogf;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/** Service to monitor CPU availability and usage. */
+public final class CpuMonitorService extends SystemService {
+    static final String TAG = CpuMonitorService.class.getSimpleName();
+    static final boolean DEBUG = Slogf.isLoggable(TAG, Log.DEBUG);
+    // TODO(b/242722241): Make this a resource overlay property.
+    //  Maintain 3 monitoring intervals:
+    //  * One to poll very frequently when mCpuAvailabilityCallbackInfoByCallbacks are available and
+    //    CPU availability is above a threshold (such as at least 10% of CPU is available).
+    //  * One to poll less frequently when mCpuAvailabilityCallbackInfoByCallbacks are available
+    //    and CPU availability is below a threshold (such as less than 10% of CPU is available).
+    //  * One to poll very less frequently when no callbacks are available and the build is either
+    //    user-debug or eng. This will be useful for debugging in development environment.
+    static final int DEFAULT_CPU_MONITORING_INTERVAL_MILLISECONDS = 5_000;
+
+    private final Context mContext;
+    private final Object mLock = new Object();
+    @GuardedBy("mLock")
+    private final ArrayMap<CpuMonitorInternal.CpuAvailabilityCallback, CpuAvailabilityCallbackInfo>
+            mCpuAvailabilityCallbackInfoByCallbacks = new ArrayMap<>();
+    @GuardedBy("mLock")
+    private long mMonitoringIntervalMilliseconds = DEFAULT_CPU_MONITORING_INTERVAL_MILLISECONDS;
+
+    private final CpuMonitorInternal mLocalService = new CpuMonitorInternal() {
+        @Override
+        public void addCpuAvailabilityCallback(Executor executor,
+                CpuAvailabilityMonitoringConfig config, CpuAvailabilityCallback callback) {
+            Objects.requireNonNull(callback, "Callback must be non-null");
+            Objects.requireNonNull(config, "Config must be non-null");
+            synchronized (mLock) {
+                if (mCpuAvailabilityCallbackInfoByCallbacks.containsKey(callback)) {
+                    Slogf.i(TAG, "Overwriting the existing CpuAvailabilityCallback %s",
+                            mCpuAvailabilityCallbackInfoByCallbacks.get(callback));
+                    // TODO(b/242722241): Overwrite any internal cache (will be added in future CLs)
+                    //  that maps callbacks based on the CPU availability thresholds.
+                }
+                CpuAvailabilityCallbackInfo info = new CpuAvailabilityCallbackInfo(config,
+                        executor);
+                mCpuAvailabilityCallbackInfoByCallbacks.put(callback, info);
+                if (DEBUG) {
+                    Slogf.d(TAG, "Added a CPU availability callback: %s", info);
+                }
+            }
+            // TODO(b/242722241):
+            //  * On the executor or on the handler thread, call the callback with the latest CPU
+            //    availability info and monitoring interval.
+            //  * Monitor the CPU stats more frequently when the first callback is added.
+        }
+
+        @Override
+        public void removeCpuAvailabilityCallback(CpuAvailabilityCallback callback) {
+            synchronized (mLock) {
+                if (!mCpuAvailabilityCallbackInfoByCallbacks.containsKey(callback)) {
+                    Slogf.i(TAG, "CpuAvailabilityCallback was not previously added."
+                            + " Ignoring the remove request");
+                    return;
+                }
+                CpuAvailabilityCallbackInfo info =
+                        mCpuAvailabilityCallbackInfoByCallbacks.remove(callback);
+                if (DEBUG) {
+                    Slogf.d(TAG, "Removed a CPU availability callback: %s", info);
+                }
+            }
+            // TODO(b/242722241): Increase CPU monitoring interval when all callbacks are removed.
+        }
+    };
+
+    public CpuMonitorService(Context context) {
+        super(context);
+        mContext = context;
+    }
+
+    @Override
+    public void onStart() {
+        publishLocalService(CpuMonitorInternal.class, mLocalService);
+        publishBinderService("cpu_monitor", new CpuMonitorBinder(), /* allowIsolated= */ false,
+                DUMP_FLAG_PRIORITY_CRITICAL);
+    }
+
+    private void doDump(IndentingPrintWriter writer) {
+        writer.printf("*%s*\n", getClass().getSimpleName());
+        writer.increaseIndent();
+        synchronized (mLock) {
+            writer.printf("CPU monitoring interval: %d ms\n", mMonitoringIntervalMilliseconds);
+            if (!mCpuAvailabilityCallbackInfoByCallbacks.isEmpty()) {
+                writer.println("CPU availability change callbacks:");
+                writer.increaseIndent();
+                for (int i = 0; i < mCpuAvailabilityCallbackInfoByCallbacks.size(); i++) {
+                    writer.printf("%s: %s\n", mCpuAvailabilityCallbackInfoByCallbacks.keyAt(i),
+                            mCpuAvailabilityCallbackInfoByCallbacks.valueAt(i));
+                }
+                writer.decreaseIndent();
+            }
+        }
+        // TODO(b/242722241): Print the recent past CPU stats.
+        writer.decreaseIndent();
+    }
+
+    private static final class CpuAvailabilityCallbackInfo {
+        public final CpuAvailabilityMonitoringConfig config;
+        public final Executor executor;
+
+        CpuAvailabilityCallbackInfo(CpuAvailabilityMonitoringConfig config,
+                Executor executor) {
+            this.config = config;
+            this.executor = executor;
+        }
+
+        @Override
+        public String toString() {
+            return "CpuAvailabilityCallbackInfo{" + "config=" + config + ", mExecutor=" + executor
+                    + '}';
+        }
+    }
+
+    private final class CpuMonitorBinder extends Binder {
+        private final PriorityDump.PriorityDumper mPriorityDumper =
+                new PriorityDump.PriorityDumper() {
+                    @Override
+                    public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args,
+                            boolean asProto) {
+                        if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, pw)
+                                || asProto) {
+                            return;
+                        }
+                        try (IndentingPrintWriter ipw = new IndentingPrintWriter(pw)) {
+                            doDump(ipw);
+                        }
+                    }
+                };
+
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            PriorityDump.dump(mPriorityDumper, fd, pw, args);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 7b60421..197c64e 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -483,8 +483,7 @@
 
     private static boolean isInteractivePolicy(int policy) {
         return policy == DisplayPowerRequest.POLICY_BRIGHT
-                || policy == DisplayPowerRequest.POLICY_DIM
-                || policy == DisplayPowerRequest.POLICY_VR;
+                || policy == DisplayPowerRequest.POLICY_DIM;
     }
 
     private boolean setScreenBrightnessByUser(float brightness) {
@@ -603,6 +602,14 @@
         mAmbientBrightnessThresholdsIdle.dump(pw);
     }
 
+    public float[] getLastSensorValues() {
+        return mAmbientLightRingBuffer.getAllLuxValues();
+    }
+
+    public long[] getLastSensorTimestamps() {
+        return mAmbientLightRingBuffer.getAllTimestamps();
+    }
+
     private String configStateToString(int state) {
         switch (state) {
         case AUTO_BRIGHTNESS_ENABLED:
@@ -1232,10 +1239,42 @@
             return mRingLux[offsetOf(index)];
         }
 
+        public float[] getAllLuxValues() {
+            float[] values = new float[mCount];
+            if (mCount == 0) {
+                return values;
+            }
+
+            if (mStart < mEnd) {
+                System.arraycopy(mRingLux, mStart, values, 0, mCount);
+            } else {
+                System.arraycopy(mRingLux, mStart, values, 0, mCapacity - mStart);
+                System.arraycopy(mRingLux, 0, values, mCapacity - mStart, mEnd);
+            }
+
+            return values;
+        }
+
         public long getTime(int index) {
             return mRingTime[offsetOf(index)];
         }
 
+        public long[] getAllTimestamps() {
+            long[] values = new long[mCount];
+            if (mCount == 0) {
+                return values;
+            }
+
+            if (mStart < mEnd) {
+                System.arraycopy(mRingTime, mStart, values, 0, mCount);
+            } else {
+                System.arraycopy(mRingTime, mStart, values, 0, mCapacity - mStart);
+                System.arraycopy(mRingTime, 0, values, mCapacity - mStart, mEnd);
+            }
+
+            return values;
+        }
+
         public void push(long time, float lux) {
             int next = mEnd;
             if (mCount == mCapacity) {
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index df4c471..6e1640d 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -79,10 +79,8 @@
 import java.io.OutputStream;
 import java.io.PrintWriter;
 import java.text.SimpleDateFormat;
-import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.Deque;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -101,8 +99,6 @@
     private static final int MAX_EVENTS = 100;
     // Discard events when reading or writing that are older than this.
     private static final long MAX_EVENT_AGE = TimeUnit.DAYS.toMillis(30);
-    // Time over which we keep lux sensor readings.
-    private static final long LUX_EVENT_HORIZON = TimeUnit.SECONDS.toNanos(10);
 
     private static final String TAG_EVENTS = "events";
     private static final String TAG_EVENT = "event";
@@ -174,8 +170,6 @@
     // Lock held while collecting data related to brightness changes.
     private final Object mDataCollectionLock = new Object();
     @GuardedBy("mDataCollectionLock")
-    private Deque<LightData> mLastSensorReadings = new ArrayDeque<>();
-    @GuardedBy("mDataCollectionLock")
     private float mLastBatteryLevel = Float.NaN;
     @GuardedBy("mDataCollectionLock")
     private float mLastBrightness = -1;
@@ -327,7 +321,8 @@
      */
     public void notifyBrightnessChanged(float brightness, boolean userInitiated,
             float powerBrightnessFactor, boolean isUserSetBrightness,
-            boolean isDefaultBrightnessConfig, String uniqueDisplayId) {
+            boolean isDefaultBrightnessConfig, String uniqueDisplayId, float[] luxValues,
+            long[] luxTimestamps) {
         if (DEBUG) {
             Slog.d(TAG, String.format("notifyBrightnessChanged(brightness=%f, userInitiated=%b)",
                         brightness, userInitiated));
@@ -335,7 +330,7 @@
         Message m = mBgHandler.obtainMessage(MSG_BRIGHTNESS_CHANGED,
                 userInitiated ? 1 : 0, 0 /*unused*/, new BrightnessChangeValues(brightness,
                         powerBrightnessFactor, isUserSetBrightness, isDefaultBrightnessConfig,
-                        mInjector.currentTimeMillis(), uniqueDisplayId));
+                        mInjector.currentTimeMillis(), uniqueDisplayId, luxValues, luxTimestamps));
         m.sendToTarget();
     }
 
@@ -349,7 +344,8 @@
 
     private void handleBrightnessChanged(float brightness, boolean userInitiated,
             float powerBrightnessFactor, boolean isUserSetBrightness,
-            boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId) {
+            boolean isDefaultBrightnessConfig, long timestamp, String uniqueDisplayId,
+            float[] luxValues, long[] luxTimestamps) {
         BrightnessChangeEvent.Builder builder;
 
         synchronized (mDataCollectionLock) {
@@ -376,28 +372,22 @@
             builder.setIsDefaultBrightnessConfig(isDefaultBrightnessConfig);
             builder.setUniqueDisplayId(uniqueDisplayId);
 
-            final int readingCount = mLastSensorReadings.size();
-            if (readingCount == 0) {
+            if (luxValues.length == 0) {
                 // No sensor data so ignore this.
                 return;
             }
 
-            float[] luxValues = new float[readingCount];
-            long[] luxTimestamps = new long[readingCount];
+            long[] luxTimestampsMillis = new long[luxTimestamps.length];
 
-            int pos = 0;
-
-            // Convert sensor timestamp in elapsed time nanos to current time millis.
+            // Convert lux timestamp in elapsed time to current time.
             long currentTimeMillis = mInjector.currentTimeMillis();
             long elapsedTimeNanos = mInjector.elapsedRealtimeNanos();
-            for (LightData reading : mLastSensorReadings) {
-                luxValues[pos] = reading.lux;
-                luxTimestamps[pos] = currentTimeMillis -
-                        TimeUnit.NANOSECONDS.toMillis(elapsedTimeNanos - reading.timestamp);
-                ++pos;
+            for (int i = 0; i < luxTimestamps.length; i++) {
+                luxTimestampsMillis[i] = currentTimeMillis - (TimeUnit.NANOSECONDS.toMillis(
+                        elapsedTimeNanos) - luxTimestamps[i]);
             }
             builder.setLuxValues(luxValues);
-            builder.setLuxTimestamps(luxTimestamps);
+            builder.setLuxTimestamps(luxTimestampsMillis);
 
             builder.setBatteryLevel(mLastBatteryLevel);
             builder.setLastBrightness(previousBrightness);
@@ -452,9 +442,6 @@
         if (mLightSensor != lightSensor) {
             mLightSensor = lightSensor;
             stopSensorListener();
-            synchronized (mDataCollectionLock) {
-                mLastSensorReadings.clear();
-            }
             // Attempt to restart the sensor listener. It will check to see if it should be running
             // so there is no need to also check here.
             startSensorListener();
@@ -798,12 +785,6 @@
             pw.println("  mLightSensor=" + mLightSensor);
             pw.println("  mLastBatteryLevel=" + mLastBatteryLevel);
             pw.println("  mLastBrightness=" + mLastBrightness);
-            pw.println("  mLastSensorReadings.size=" + mLastSensorReadings.size());
-            if (!mLastSensorReadings.isEmpty()) {
-                pw.println("  mLastSensorReadings time span "
-                        + mLastSensorReadings.peekFirst().timestamp + "->"
-                        + mLastSensorReadings.peekLast().timestamp);
-            }
         }
         synchronized (mEventsLock) {
             pw.println("  mEventsDirty=" + mEventsDirty);
@@ -919,43 +900,6 @@
         return ParceledListSlice.emptyList();
     }
 
-    // Not allowed to keep the SensorEvent so used to copy the data we care about.
-    private static class LightData {
-        public float lux;
-        // Time in elapsedRealtimeNanos
-        public long timestamp;
-    }
-
-    private void recordSensorEvent(SensorEvent event) {
-        long horizon = mInjector.elapsedRealtimeNanos() - LUX_EVENT_HORIZON;
-        synchronized (mDataCollectionLock) {
-            if (DEBUG) {
-                Slog.v(TAG, "Sensor event " + event);
-            }
-            if (!mLastSensorReadings.isEmpty()
-                    && event.timestamp < mLastSensorReadings.getLast().timestamp) {
-                // Ignore event that came out of order.
-                return;
-            }
-            LightData data = null;
-            while (!mLastSensorReadings.isEmpty()
-                    && mLastSensorReadings.getFirst().timestamp < horizon) {
-                // Remove data that has fallen out of the window.
-                data = mLastSensorReadings.removeFirst();
-            }
-            // We put back the last one we removed so we know how long
-            // the first sensor reading was valid for.
-            if (data != null) {
-                mLastSensorReadings.addFirst(data);
-            }
-
-            data = new LightData();
-            data.timestamp = event.timestamp;
-            data.lux = event.values[0];
-            mLastSensorReadings.addLast(data);
-        }
-    }
-
     private void recordAmbientBrightnessStats(SensorEvent event) {
         mAmbientBrightnessStatsTracker.add(mCurrentUserId, event.values[0]);
     }
@@ -969,7 +913,6 @@
     private final class SensorListener implements SensorEventListener {
         @Override
         public void onSensorChanged(SensorEvent event) {
-            recordSensorEvent(event);
             recordAmbientBrightnessStats(event);
         }
 
@@ -1056,7 +999,7 @@
                     handleBrightnessChanged(values.brightness, userInitiatedChange,
                             values.powerBrightnessFactor, values.isUserSetBrightness,
                             values.isDefaultBrightnessConfig, values.timestamp,
-                            values.uniqueDisplayId);
+                            values.uniqueDisplayId, values.luxValues, values.luxTimestamps);
                     break;
                 case MSG_START_SENSOR_LISTENER:
                     startSensorListener();
@@ -1092,16 +1035,20 @@
         public final boolean isDefaultBrightnessConfig;
         public final long timestamp;
         public final String uniqueDisplayId;
+        public final float[] luxValues;
+        public final long[] luxTimestamps;
 
         BrightnessChangeValues(float brightness, float powerBrightnessFactor,
                 boolean isUserSetBrightness, boolean isDefaultBrightnessConfig,
-                long timestamp, String uniqueDisplayId) {
+                long timestamp, String uniqueDisplayId, float[] luxValues, long[] luxTimestamps) {
             this.brightness = brightness;
             this.powerBrightnessFactor = powerBrightnessFactor;
             this.isUserSetBrightness = isUserSetBrightness;
             this.isDefaultBrightnessConfig = isDefaultBrightnessConfig;
             this.timestamp = timestamp;
             this.uniqueDisplayId = uniqueDisplayId;
+            this.luxValues = luxValues;
+            this.luxTimestamps = luxTimestamps;
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
index 9dd2f84..fc6403d 100644
--- a/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
+++ b/services/core/java/com/android/server/display/DeviceStateToLayoutMap.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import android.annotation.NonNull;
 import android.hardware.devicestate.DeviceStateManager;
 import android.os.Environment;
 import android.util.IndentingPrintWriter;
@@ -23,8 +24,10 @@
 import android.util.SparseArray;
 import android.view.DisplayAddress;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.display.config.layout.Layouts;
 import com.android.server.display.config.layout.XmlParser;
+import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -48,13 +51,28 @@
 
     public static final int STATE_DEFAULT = DeviceStateManager.INVALID_DEVICE_STATE;
 
+    // Direction of the display relative to the default display, whilst in this state
+    private static final int POSITION_UNKNOWN = Layout.Display.POSITION_UNKNOWN;
+    private static final int POSITION_FRONT = Layout.Display.POSITION_FRONT;
+    private static final int POSITION_REAR = Layout.Display.POSITION_REAR;
+
+    private static final String FRONT_STRING = "front";
+    private static final String REAR_STRING = "rear";
+
     private static final String CONFIG_FILE_PATH =
             "etc/displayconfig/display_layout_configuration.xml";
 
     private final SparseArray<Layout> mLayoutMap = new SparseArray<>();
+    private final DisplayIdProducer mIdProducer;
 
-    DeviceStateToLayoutMap() {
-        loadLayoutsFromConfig();
+    DeviceStateToLayoutMap(DisplayIdProducer idProducer) {
+        this(idProducer, Environment.buildPath(
+                Environment.getVendorDirectory(), CONFIG_FILE_PATH));
+    }
+
+    DeviceStateToLayoutMap(DisplayIdProducer idProducer, File configFile) {
+        mIdProducer = idProducer;
+        loadLayoutsFromConfig(configFile);
         createLayout(STATE_DEFAULT);
     }
 
@@ -76,24 +94,11 @@
         return layout;
     }
 
-    private Layout createLayout(int state) {
-        if (mLayoutMap.contains(state)) {
-            Slog.e(TAG, "Attempted to create a second layout for state " + state);
-            return null;
-        }
-
-        final Layout layout = new Layout();
-        mLayoutMap.append(state, layout);
-        return layout;
-    }
-
     /**
      * Reads display-layout-configuration files to get the layouts to use for this device.
      */
-    private void loadLayoutsFromConfig() {
-        final File configFile = Environment.buildPath(
-                Environment.getVendorDirectory(), CONFIG_FILE_PATH);
-
+    @VisibleForTesting
+    void loadLayoutsFromConfig(@NonNull File configFile) {
         if (!configFile.exists()) {
             return;
         }
@@ -109,10 +114,19 @@
                 final int state = l.getState().intValue();
                 final Layout layout = createLayout(state);
                 for (com.android.server.display.config.layout.Display d: l.getDisplay()) {
-                    layout.createDisplayLocked(
+                    Layout.Display display = layout.createDisplayLocked(
                             DisplayAddress.fromPhysicalDisplayId(d.getAddress().longValue()),
                             d.isDefaultDisplay(),
-                            d.isEnabled());
+                            d.isEnabled(),
+                            mIdProducer);
+
+                    if (FRONT_STRING.equals(d.getPosition())) {
+                        display.setPosition(POSITION_FRONT);
+                    } else if (REAR_STRING.equals(d.getPosition())) {
+                        display.setPosition(POSITION_REAR);
+                    } else {
+                        display.setPosition(POSITION_UNKNOWN);
+                    }
                 }
             }
         } catch (IOException | DatatypeConfigurationException | XmlPullParserException e) {
@@ -120,4 +134,15 @@
                     + configFile, e);
         }
     }
+
+    private Layout createLayout(int state) {
+        if (mLayoutMap.contains(state)) {
+            Slog.e(TAG, "Attempted to create a second layout for state " + state);
+            return null;
+        }
+
+        final Layout layout = new Layout();
+        mLayoutMap.append(state, layout);
+        return layout;
+    }
 }
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 1fc15122..4f1df3f 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -120,13 +120,14 @@
     }
 
     public static Display.Mode createMode(int width, int height, float refreshRate) {
-        return createMode(width, height, refreshRate, new float[0]);
+        return createMode(width, height, refreshRate, new float[0], new int[0]);
     }
 
     public static Display.Mode createMode(int width, int height, float refreshRate,
-            float[] alternativeRefreshRates) {
+            float[] alternativeRefreshRates,
+            @Display.HdrCapabilities.HdrType int[] supportedHdrTypes) {
         return new Display.Mode(NEXT_DISPLAY_MODE_ID.getAndIncrement(), width, height, refreshRate,
-                alternativeRefreshRates);
+                alternativeRefreshRates, supportedHdrTypes);
     }
 
     public interface Listener {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 523a2dc..c1e9526 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -1941,8 +1941,8 @@
     }
 
     private void setProxSensorUnspecified() {
-        mProximitySensor.name = "";
-        mProximitySensor.type = "";
+        mProximitySensor.name = null;
+        mProximitySensor.type = null;
     }
 
     private void loadProxSensorFromDdc(DisplayConfiguration config) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index 84dfe86..ddb9243 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -23,6 +23,7 @@
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
 import android.view.RoundedCorners;
 import android.view.Surface;
 
@@ -144,7 +145,7 @@
     /**
      * Flag: Indicates that the display should always be unlocked. Only valid on virtual displays
      * that aren't in the default display group.
-     * @see #FLAG_OWN_DISPLAY_GROUP
+     * @see #FLAG_OWN_DISPLAY_GROUP and #FLAG_DEVICE_DISPLAY_GROUP
      * @hide
      */
     public static final int FLAG_ALWAYS_UNLOCKED = 1 << 15;
@@ -158,6 +159,27 @@
     public static final int FLAG_TOUCH_FEEDBACK_DISABLED = 1 << 16;
 
     /**
+     * Flag: Indicates that the display maintains its own focus and touch mode.
+     *
+     * This flag is similar to {@link com.android.internal.R.bool.config_perDisplayFocusEnabled} in
+     * behavior, but only applies to the specific display instead of system-wide to all displays.
+     *
+     * Note: The display must be trusted in order to have its own focus.
+     *
+     * @see #FLAG_TRUSTED
+     * @hide
+     */
+    public static final int FLAG_OWN_FOCUS = 1 << 17;
+
+    /**
+     * Flag: indicates that the display should not be a part of the default {@link DisplayGroup} and
+     * instead be part of a {@link DisplayGroup} associated with the Virtual Device.
+     *
+     * @hide
+     */
+    public static final int FLAG_DEVICE_DISPLAY_GROUP = 1 << 18;
+
+    /**
      * Touch attachment: Display does not receive touch.
      */
     public static final int TOUCH_NONE = 0;
@@ -303,6 +325,11 @@
     public RoundedCorners roundedCorners;
 
     /**
+     * The {@link RoundedCorners} if present or {@code null} otherwise.
+     */
+    public DisplayShape displayShape;
+
+    /**
      * The touch attachment, per {@link DisplayViewport#touch}.
      */
     public int touch;
@@ -438,7 +465,8 @@
                 || !BrightnessSynchronizer.floatEquals(brightnessDefault,
                 other.brightnessDefault)
                 || !Objects.equals(roundedCorners, other.roundedCorners)
-                || installOrientation != other.installOrientation) {
+                || installOrientation != other.installOrientation
+                || !Objects.equals(displayShape, other.displayShape)) {
             diff |= DIFF_OTHER;
         }
         return diff;
@@ -484,6 +512,7 @@
         brightnessDefault = other.brightnessDefault;
         roundedCorners = other.roundedCorners;
         installOrientation = other.installOrientation;
+        displayShape = other.displayShape;
     }
 
     // For debugging purposes
@@ -533,6 +562,9 @@
         }
         sb.append(flagsToString(flags));
         sb.append(", installOrientation ").append(installOrientation);
+        if (displayShape != null) {
+            sb.append(", displayShape ").append(displayShape);
+        }
         sb.append("}");
         return sb.toString();
     }
@@ -584,9 +616,30 @@
         if ((flags & FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD) != 0) {
             msg.append(", FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD");
         }
+        if ((flags & FLAG_DESTROY_CONTENT_ON_REMOVAL) != 0) {
+            msg.append(", FLAG_DESTROY_CONTENT_ON_REMOVAL");
+        }
         if ((flags & FLAG_MASK_DISPLAY_CUTOUT) != 0) {
             msg.append(", FLAG_MASK_DISPLAY_CUTOUT");
         }
+        if ((flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0) {
+            msg.append(", FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS");
+        }
+        if ((flags & FLAG_TRUSTED) != 0) {
+            msg.append(", FLAG_TRUSTED");
+        }
+        if ((flags & FLAG_OWN_DISPLAY_GROUP) != 0) {
+            msg.append(", FLAG_OWN_DISPLAY_GROUP");
+        }
+        if ((flags & FLAG_ALWAYS_UNLOCKED) != 0) {
+            msg.append(", FLAG_ALWAYS_UNLOCKED");
+        }
+        if ((flags & FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
+            msg.append(", FLAG_TOUCH_FEEDBACK_DISABLED");
+        }
+        if ((flags & FLAG_OWN_FOCUS) != 0) {
+            msg.append(", FLAG_OWN_FOCUS");
+        }
         return msg.toString();
     }
 }
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 05cd67f..0d1aca8 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -25,6 +25,7 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
@@ -105,7 +106,6 @@
 import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
-import android.sysprop.DisplayProperties;
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.EventLog;
@@ -451,8 +451,6 @@
         }
     };
 
-    private final boolean mAllowNonNativeRefreshRateOverride;
-
     private final BrightnessSynchronizer mBrightnessSynchronizer;
 
     /**
@@ -506,7 +504,6 @@
         ColorSpace[] colorSpaces = SurfaceControl.getCompositionColorSpaces();
         mWideColorSpace = colorSpaces[1];
         mOverlayProperties = SurfaceControl.getOverlaySupport();
-        mAllowNonNativeRefreshRateOverride = mInjector.getAllowNonNativeRefreshRateOverride();
         mSystemReady = false;
     }
 
@@ -930,24 +927,21 @@
             }
         }
 
-        if (mAllowNonNativeRefreshRateOverride) {
-            overriddenInfo.refreshRateOverride = frameRateHz;
-            if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
-                    callingUid)) {
-                overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
-                        info.supportedModes.length + 1);
-                overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
-                        new Display.Mode(Display.DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE,
-                                currentMode.getPhysicalWidth(), currentMode.getPhysicalHeight(),
-                                overriddenInfo.refreshRateOverride);
-                overriddenInfo.modeId =
-                        overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1]
-                                .getModeId();
-            }
-            return overriddenInfo;
+        overriddenInfo.refreshRateOverride = frameRateHz;
+        if (!CompatChanges.isChangeEnabled(DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE,
+                callingUid)) {
+            overriddenInfo.supportedModes = Arrays.copyOf(info.supportedModes,
+                    info.supportedModes.length + 1);
+            overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1] =
+                    new Display.Mode(Display.DISPLAY_MODE_ID_FOR_FRAME_RATE_OVERRIDE,
+                            currentMode.getPhysicalWidth(), currentMode.getPhysicalHeight(),
+                            overriddenInfo.refreshRateOverride,
+                            new float[0], currentMode.getSupportedHdrTypes());
+            overriddenInfo.modeId =
+                    overriddenInfo.supportedModes[overriddenInfo.supportedModes.length - 1]
+                            .getModeId();
         }
-
-        return info;
+        return overriddenInfo;
     }
 
     private DisplayInfo getDisplayInfoInternal(int displayId, int callingUid) {
@@ -1283,6 +1277,9 @@
         if ((flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
             flags &= ~VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
         }
+        if ((flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0 && virtualDevice != null) {
+            flags |= VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
+        }
 
         if (projection != null) {
             try {
@@ -1410,7 +1407,7 @@
         // If the display is to be added to a device display group, we need to make the
         // LogicalDisplayMapper aware of the link between the new display and its associated virtual
         // device before triggering DISPLAY_DEVICE_EVENT_ADDED.
-        if (virtualDevice != null && (flags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) == 0) {
+        if ((flags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
             try {
                 final int virtualDeviceId = virtualDevice.getDeviceId();
                 mLogicalDisplayMapper.associateDisplayDeviceWithVirtualDevice(
@@ -1581,7 +1578,7 @@
             mSyncRoot.notifyAll();
         }
 
-        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
+        sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
 
         Runnable work = updateDisplayStateLocked(device);
         if (work != null) {
@@ -1600,7 +1597,7 @@
         // We don't bother invalidating the display info caches here because any changes to the
         // display info will trigger a cache invalidation inside of LogicalDisplay before we hit
         // this point.
-        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
+        sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
         scheduleTraversalLocked(false);
         mPersistentDataStore.saveIfNeeded();
 
@@ -1630,7 +1627,7 @@
         mDisplayStates.delete(displayId);
         mDisplayBrightnesses.delete(displayId);
         DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
-        sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
+        sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
         scheduleTraversalLocked(false);
 
         if (mDisplayWindowPolicyControllers.contains(displayId)) {
@@ -1646,23 +1643,13 @@
     }
 
     private void handleLogicalDisplaySwappedLocked(@NonNull LogicalDisplay display) {
-        final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
-        final Runnable work = updateDisplayStateLocked(device);
-        if (work != null) {
-            mHandler.post(work);
-        }
-        final int displayId = display.getDisplayIdLocked();
+        handleLogicalDisplayChangedLocked(display);
 
+        final int displayId = display.getDisplayIdLocked();
         if (displayId == Display.DEFAULT_DISPLAY) {
             notifyDefaultDisplayDeviceUpdated(display);
         }
-        DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
-        if (dpc != null) {
-            dpc.onDisplayChanged();
-        }
-        mPersistentDataStore.saveIfNeeded();
         mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATIONS);
-        handleLogicalDisplayChangedLocked(display);
     }
 
     private void notifyDefaultDisplayDeviceUpdated(LogicalDisplay display) {
@@ -1674,7 +1661,7 @@
         final int displayId = display.getDisplayIdLocked();
         final DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
         if (dpc != null) {
-            dpc.onDeviceStateTransition();
+            dpc.onDisplayChanged();
         }
     }
 
@@ -2374,9 +2361,13 @@
         }
     }
 
-    private void sendDisplayEventLocked(int displayId, @DisplayEvent int event) {
-        Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
-        mHandler.sendMessage(msg);
+    private void sendDisplayEventLocked(@NonNull LogicalDisplay display, @DisplayEvent int event) {
+        // Only send updates outside of DisplayManagerService for enabled displays
+        if (display.isEnabledLocked()) {
+            int displayId = display.getDisplayIdLocked();
+            Message msg = mHandler.obtainMessage(MSG_DELIVER_DISPLAY_EVENT, displayId, event);
+            mHandler.sendMessage(msg);
+        }
     }
 
     private void sendDisplayGroupEvent(int groupId, int event) {
@@ -2602,11 +2593,6 @@
         long getDefaultDisplayDelayTimeout() {
             return WAIT_FOR_DEFAULT_DISPLAY_TIMEOUT;
         }
-
-        boolean getAllowNonNativeRefreshRateOverride() {
-            return DisplayProperties
-                    .debug_allow_non_native_refresh_rate_override().orElse(true);
-        }
     }
 
     @VisibleForTesting
@@ -2666,8 +2652,7 @@
     }
 
     private void handleBrightnessChange(LogicalDisplay display) {
-        sendDisplayEventLocked(display.getDisplayIdLocked(),
-                DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
+        sendDisplayEventLocked(display, DisplayManagerGlobal.EVENT_DISPLAY_BRIGHTNESS_CHANGED);
     }
 
     private DisplayDevice getDeviceForDisplayLocked(int displayId) {
@@ -2884,12 +2869,12 @@
          * Returns the list of all display ids.
          */
         @Override // Binder call
-        public int[] getDisplayIds() {
+        public int[] getDisplayIds(boolean includeDisabled) {
             final int callingUid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mSyncRoot) {
-                    return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid);
+                    return mLogicalDisplayMapper.getDisplayIdsLocked(callingUid, includeDisabled);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -3380,6 +3365,11 @@
             final long token = Binder.clearCallingIdentity();
             try {
                 synchronized (mSyncRoot) {
+                    LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(
+                            displayId, /* includeDisabled= */ false);
+                    if (display == null || !display.isEnabledLocked()) {
+                        return null;
+                    }
                     DisplayPowerControllerInterface dpc = mDisplayPowerControllers.get(displayId);
                     if (dpc != null) {
                         return dpc.getBrightnessInfo();
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index 306b8cf..405a2b9 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -16,6 +16,7 @@
 
 package com.android.server.display;
 
+import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
 import static android.hardware.display.DisplayManagerInternal.REFRESH_RATE_LIMIT_HIGH_BRIGHTNESS_MODE;
 import static android.os.PowerManager.BRIGHTNESS_INVALID;
 
@@ -48,7 +49,7 @@
 import android.provider.DeviceConfig;
 import android.provider.DeviceConfigInterface;
 import android.provider.Settings;
-import android.sysprop.DisplayProperties;
+import android.sysprop.SurfaceFlingerProperties;
 import android.text.TextUtils;
 import android.util.IndentingPrintWriter;
 import android.util.Pair;
@@ -137,8 +138,7 @@
 
     private boolean mAlwaysRespectAppRequest;
 
-    // TODO(b/241447632): remove the flag once SF changes are ready
-    private final boolean mRenderFrameRateIsPhysicalRefreshRate;
+    private final boolean mSupportsFrameRateOverride;
 
     /**
      * The allowed refresh rate switching type. This is used by SurfaceFlinger.
@@ -175,7 +175,7 @@
         mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler(),
                 mDeviceConfigDisplaySettings);
         mAlwaysRespectAppRequest = false;
-        mRenderFrameRateIsPhysicalRefreshRate = injector.renderFrameRateIsPhysicalRefreshRate();
+        mSupportsFrameRateOverride = injector.supportsFrameRateOverride();
     }
 
     /**
@@ -237,21 +237,6 @@
             }
         }
 
-        if (mRenderFrameRateIsPhysicalRefreshRate) {
-            for (int i = 0; i < votes.size(); i++) {
-
-                Vote vote = votes.valueAt(i);
-                vote.refreshRateRanges.physical.min = Math.max(vote.refreshRateRanges.physical.min,
-                        vote.refreshRateRanges.render.min);
-                vote.refreshRateRanges.physical.max = Math.min(vote.refreshRateRanges.physical.max,
-                        vote.refreshRateRanges.render.max);
-                vote.refreshRateRanges.render.min = Math.max(vote.refreshRateRanges.physical.min,
-                        vote.refreshRateRanges.render.min);
-                vote.refreshRateRanges.render.max = Math.min(vote.refreshRateRanges.physical.max,
-                        vote.refreshRateRanges.render.max);
-            }
-        }
-
         return votes;
     }
 
@@ -279,6 +264,18 @@
             disableRefreshRateSwitching = false;
             appRequestBaseModeRefreshRate = 0f;
         }
+
+        @Override
+        public String toString() {
+            return  "minPhysicalRefreshRate=" + minPhysicalRefreshRate
+                    + ", maxPhysicalRefreshRate=" + maxPhysicalRefreshRate
+                    + ", minRenderFrameRate=" + minRenderFrameRate
+                    + ", maxRenderFrameRate=" + maxRenderFrameRate
+                    + ", width=" + width
+                    + ", height=" + height
+                    + ", disableRefreshRateSwitching=" + disableRefreshRateSwitching
+                    + ", appRequestBaseModeRefreshRate=" + appRequestBaseModeRefreshRate;
+        }
     }
 
     // VoteSummary is returned as an output param to cut down a bit on the number of temporary
@@ -332,18 +329,8 @@
             }
 
             if (mLoggingEnabled) {
-                Slog.w(TAG, "Vote summary for priority "
-                        + Vote.priorityToString(priority)
-                        + ": width=" + summary.width
-                        + ", height=" + summary.height
-                        + ", minPhysicalRefreshRate=" + summary.minPhysicalRefreshRate
-                        + ", maxPhysicalRefreshRate=" + summary.maxPhysicalRefreshRate
-                        + ", minRenderFrameRate=" + summary.minRenderFrameRate
-                        + ", maxRenderFrameRate=" + summary.maxRenderFrameRate
-                        + ", disableRefreshRateSwitching="
-                        + summary.disableRefreshRateSwitching
-                        + ", appRequestBaseModeRefreshRate="
-                        + summary.appRequestBaseModeRefreshRate);
+                Slog.w(TAG, "Vote summary for priority " + Vote.priorityToString(priority)
+                        + ": " + summary);
             }
         }
     }
@@ -377,6 +364,23 @@
         return !availableModes.isEmpty() ? availableModes.get(0) : null;
     }
 
+    private void disableModeSwitching(VoteSummary summary, float fps) {
+        summary.minPhysicalRefreshRate = summary.maxPhysicalRefreshRate = fps;
+        summary.maxRenderFrameRate = Math.min(summary.maxRenderFrameRate, fps);
+
+        if (mLoggingEnabled) {
+            Slog.i(TAG, "Disabled mode switching on summary: " + summary);
+        }
+    }
+
+    private void disableRenderRateSwitching(VoteSummary summary) {
+        summary.minRenderFrameRate = summary.maxRenderFrameRate;
+
+        if (mLoggingEnabled) {
+            Slog.i(TAG, "Disabled render rate switching on summary: " + summary);
+        }
+    }
+
     /**
      * Calculates the refresh rate ranges and display modes that the system is allowed to freely
      * switch between based on global and display-specific constraints.
@@ -405,7 +409,7 @@
             int highestConsideredPriority = Vote.MAX_PRIORITY;
 
             if (mAlwaysRespectAppRequest) {
-                lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE;
+                lowestConsideredPriority = Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE;
                 highestConsideredPriority = Vote.PRIORITY_APP_REQUEST_SIZE;
             }
 
@@ -533,19 +537,15 @@
 
             if (modeSwitchingDisabled || primarySummary.disableRefreshRateSwitching) {
                 float fps = baseMode.getRefreshRate();
-                primarySummary.minPhysicalRefreshRate = primarySummary.maxPhysicalRefreshRate = fps;
+                disableModeSwitching(primarySummary, fps);
                 if (modeSwitchingDisabled) {
-                    appRequestSummary.minPhysicalRefreshRate =
-                            appRequestSummary.maxPhysicalRefreshRate = fps;
-                }
-            }
+                    disableModeSwitching(appRequestSummary, fps);
+                    disableRenderRateSwitching(primarySummary);
 
-            if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE
-                    || mRenderFrameRateIsPhysicalRefreshRate) {
-                primarySummary.minRenderFrameRate = primarySummary.minPhysicalRefreshRate;
-                primarySummary.maxRenderFrameRate = primarySummary.maxPhysicalRefreshRate;
-                appRequestSummary.minRenderFrameRate = appRequestSummary.minPhysicalRefreshRate;
-                appRequestSummary.maxRenderFrameRate = appRequestSummary.maxPhysicalRefreshRate;
+                    if (mModeSwitchingType == DisplayManager.SWITCHING_TYPE_NONE) {
+                        disableRenderRateSwitching(appRequestSummary);
+                    }
+                }
             }
 
             boolean allowGroupSwitching =
@@ -611,6 +611,22 @@
                 continue;
             }
 
+            // The physical refresh rate must be in the render frame rate range, unless
+            // frame rate override is supported.
+            if (!mSupportsFrameRateOverride) {
+                if (physicalRefreshRate < (summary.minRenderFrameRate - FLOAT_TOLERANCE)
+                        || physicalRefreshRate > (summary.maxRenderFrameRate + FLOAT_TOLERANCE)) {
+                    if (mLoggingEnabled) {
+                        Slog.w(TAG, "Discarding mode " + mode.getModeId()
+                                + ", outside render rate bounds"
+                                + ": minPhysicalRefreshRate=" + summary.minPhysicalRefreshRate
+                                + ", maxPhysicalRefreshRate=" + summary.maxPhysicalRefreshRate
+                                + ", modeRefreshRate=" + physicalRefreshRate);
+                    }
+                    continue;
+                }
+            }
+
             // Check whether the render frame rate range is achievable by the mode's physical
             // refresh rate, meaning that if a divisor of the physical refresh rate is in range
             // of the render frame rate.
@@ -1640,7 +1656,7 @@
             SparseArray<Display.Mode[]> modes = new SparseArray<>();
             SparseArray<Display.Mode> defaultModes = new SparseArray<>();
             DisplayInfo info = new DisplayInfo();
-            Display[] displays = dm.getDisplays();
+            Display[] displays = dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
             for (Display d : displays) {
                 final int displayId = d.getDisplayId();
                 d.getDisplayInfo(info);
@@ -2517,7 +2533,8 @@
             sensorManager.addProximityActiveListener(BackgroundThread.getExecutor(), this);
 
             synchronized (mSensorObserverLock) {
-                for (Display d : mDisplayManager.getDisplays()) {
+                for (Display d : mDisplayManager.getDisplays(
+                        DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
                     mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
                 }
             }
@@ -2528,7 +2545,8 @@
         }
 
         private void recalculateVotesLocked() {
-            final Display[] displays = mDisplayManager.getDisplays();
+            final Display[] displays = mDisplayManager.getDisplays(
+                    DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
             for (Display d : displays) {
                 int displayId = d.getDisplayId();
                 Vote vote = null;
@@ -2976,7 +2994,7 @@
 
         IThermalService getThermalService();
 
-        boolean renderFrameRateIsPhysicalRefreshRate();
+        boolean supportsFrameRateOverride();
     }
 
     @VisibleForTesting
@@ -3031,9 +3049,11 @@
         }
 
         @Override
-        public boolean renderFrameRateIsPhysicalRefreshRate() {
-            return DisplayProperties
-                    .debug_render_frame_rate_is_physical_refresh_rate().orElse(true);
+        public boolean supportsFrameRateOverride() {
+            return SurfaceFlingerProperties.enable_frame_rate_override().orElse(false)
+                            && !SurfaceFlingerProperties.frame_rate_override_for_native_rates()
+                                    .orElse(true)
+                            && SurfaceFlingerProperties.frame_rate_override_global().orElse(false);
         }
 
         private DisplayManager getDisplayManager() {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d6f0fd0..9d47892 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -219,15 +219,6 @@
 
     private final float mScreenBrightnessDefault;
 
-    // The minimum allowed brightness while in VR.
-    private final float mScreenBrightnessForVrRangeMinimum;
-
-    // The maximum allowed brightness while in VR.
-    private final float mScreenBrightnessForVrRangeMaximum;
-
-    // The default screen brightness for VR.
-    private final float mScreenBrightnessForVrDefault;
-
     // True if auto-brightness should be used.
     private boolean mUseSoftwareAutoBrightnessConfig;
 
@@ -450,9 +441,6 @@
     // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set.
     private float mTemporaryScreenBrightness;
 
-    // The current screen brightness while in VR mode.
-    private float mScreenBrightnessForVr;
-
     // The last auto brightness adjustment that was set by the user and not temporary. Set to
     // Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
     private float mAutoBrightnessAdjustment;
@@ -497,6 +485,9 @@
     private final String mSuspendBlockerIdProxNegative;
     private final String mSuspendBlockerIdProxDebounce;
 
+    private boolean mIsEnabled;
+    private boolean mIsInTransition;
+
     /**
      * Creates the display power controller.
      */
@@ -520,6 +511,8 @@
         mDisplayDevice = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
         mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
         mDisplayStatsId = mUniqueDisplayId.hashCode();
+        mIsEnabled = logicalDisplay.isEnabledLocked();
+        mIsInTransition = logicalDisplay.isInTransitionLocked();
         mHandler = new DisplayControllerHandler(handler.getLooper());
         mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
         mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
@@ -558,14 +551,6 @@
         mScreenBrightnessDefault = clampAbsoluteBrightness(
                 mLogicalDisplay.getDisplayInfoLocked().brightnessDefault);
 
-        // VR SETTINGS
-        mScreenBrightnessForVrDefault = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_VR));
-        mScreenBrightnessForVrRangeMaximum = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM_VR));
-        mScreenBrightnessForVrRangeMinimum = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR));
-
         mAllowAutoBrightnessWhileDozingConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_allowAutoBrightnessWhileDozing);
 
@@ -638,7 +623,6 @@
         loadProximitySensor();
 
         mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
-        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
         mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -807,29 +791,36 @@
         final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
         final IBinder token = device.getDisplayTokenLocked();
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
+        final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
         mHandler.post(() -> {
+            boolean changed = false;
             if (mDisplayDevice != device) {
+                changed = true;
                 mDisplayDevice = device;
                 mUniqueDisplayId = uniqueId;
                 mDisplayStatsId = mUniqueDisplayId.hashCode();
                 mDisplayDeviceConfig = config;
                 loadFromDisplayDeviceConfig(token, info);
+
+                // Since the underlying display-device changed, we really don't know the
+                // last command that was sent to change it's state. Lets assume it is unknown so
+                // that we trigger a change immediately.
+                mPowerState.resetScreenState();
+            }
+            if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
+                changed = true;
+                mIsEnabled = isEnabled;
+                mIsInTransition = isInTransition;
+            }
+
+            if (changed) {
                 updatePowerState();
             }
         });
     }
 
     /**
-     * Called when the displays are preparing to transition from one device state to another.
-     * This process involves turning off some displays so we need updatePowerState() to run and
-     * calculate the new state.
-     */
-    @Override
-    public void onDeviceStateTransition() {
-        sendUpdatePowerState();
-    }
-
-    /**
      * Unregisters all listeners and interrupts all running threads; halting future work.
      *
      * This method should be called when the DisplayPowerController is no longer in use; i.e. when
@@ -937,9 +928,6 @@
 
         mBrightnessSetting.registerListener(mBrightnessSettingListener);
         mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT),
-                false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
-        mContext.getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
                 false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
     }
@@ -1259,9 +1247,6 @@
                     mBrightnessReasonTemp.setReason(BrightnessReason.REASON_DOZE);
                 }
                 break;
-            case DisplayPowerRequest.POLICY_VR:
-                state = Display.STATE_VR;
-                break;
             case DisplayPowerRequest.POLICY_DIM:
             case DisplayPowerRequest.POLICY_BRIGHT:
             default:
@@ -1316,8 +1301,8 @@
             mIgnoreProximityUntilChanged = false;
         }
 
-        if (!mLogicalDisplay.isEnabled()
-                || mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
+        if (!mIsEnabled
+                || mIsInTransition
                 || mScreenOffBecauseOfProximity) {
             state = Display.STATE_OFF;
         }
@@ -1339,12 +1324,6 @@
             mBrightnessReasonTemp.setReason(BrightnessReason.REASON_SCREEN_OFF);
         }
 
-        // Always use the VR brightness when in the VR state.
-        if (state == Display.STATE_VR) {
-            brightnessState = mScreenBrightnessForVr;
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_VR);
-        }
-
         if ((Float.isNaN(brightnessState))
                 && isValidBrightnessValue(mPowerRequest.screenBrightnessOverride)) {
             brightnessState = mPowerRequest.screenBrightnessOverride;
@@ -1563,7 +1542,7 @@
                 mBrightnessThrottler.getBrightnessMaxReason());
 
         // Animate the screen brightness when the screen is on or dozing.
-        // Skip the animation when the screen is off or suspended or transition to/from VR.
+        // Skip the animation when the screen is off.
         boolean brightnessAdjusted = false;
         final boolean brightnessIsTemporary =
                 mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
@@ -1586,8 +1565,6 @@
                 }
             }
 
-            final boolean wasOrWillBeInVr =
-                    (state == Display.STATE_VR || oldState == Display.STATE_VR);
             final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState
                     != RAMP_STATE_SKIP_NONE) || skipRampBecauseOfProximityChangeToNegative;
             // While dozing, sometimes the brightness is split into buckets. Rather than animating
@@ -1629,7 +1606,7 @@
                     && (animateValue != currentBrightness
                     || sdrAnimateValue != currentSdrBrightness)) {
                 if (initialRampSkip || hasBrightnessBuckets
-                        || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
+                        || !isDisplayContentVisible || brightnessIsTemporary) {
                     animateScreenBrightness(animateValue, sdrAnimateValue,
                             SCREEN_ANIMATION_RATE_MINIMUM);
                 } else {
@@ -2066,12 +2043,6 @@
         }
     }
 
-    private float clampScreenBrightnessForVr(float value) {
-        return MathUtils.constrain(
-                value, mScreenBrightnessForVrRangeMinimum,
-                mScreenBrightnessForVrRangeMaximum);
-    }
-
     private float clampScreenBrightness(float value) {
         if (Float.isNaN(value)) {
             value = PowerManager.BRIGHTNESS_MIN;
@@ -2160,23 +2131,6 @@
                 mPowerState.setColorFadeLevel(1.0f);
                 mPowerState.dismissColorFade();
             }
-        } else if (target == Display.STATE_VR) {
-            // Wait for brightness animation to complete beforehand when entering VR
-            // from screen on to prevent a perceptible jump because brightness may operate
-            // differently when the display is configured for dozing.
-            if (mScreenBrightnessRampAnimator.isAnimating()
-                    && mPowerState.getScreenState() == Display.STATE_ON) {
-                return;
-            }
-
-            // Set screen state.
-            if (!setScreenState(Display.STATE_VR)) {
-                return; // screen on blocked
-            }
-
-            // Dismiss the black surface without fanfare.
-            mPowerState.setColorFadeLevel(1.0f);
-            mPowerState.dismissColorFade();
         } else if (target == Display.STATE_DOZE) {
             // Want screen dozing.
             // Wait for brightness animation to complete beforehand when entering doze
@@ -2384,9 +2338,6 @@
                 mAutomaticBrightnessController.resetShortTermModel();
             }
         }
-        // We don't bother with a pending variable for VR screen brightness since we just
-        // immediately adapt to it.
-        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         sendUpdatePowerState();
     }
 
@@ -2405,13 +2356,6 @@
         return clampAbsoluteBrightness(brightness);
     }
 
-    private float getScreenBrightnessForVrSetting() {
-        final float brightnessFloat = Settings.System.getFloatForUser(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, mScreenBrightnessForVrDefault,
-                UserHandle.USER_CURRENT);
-        return clampScreenBrightnessForVr(brightnessFloat);
-    }
-
     @Override
     public void setBrightness(float brightnessValue) {
         // Update the setting, which will eventually call back into DPC to have us actually update
@@ -2491,7 +2435,9 @@
                     : 1.0f;
             mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated,
                     powerFactor, hadUserDataPoint,
-                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId);
+                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId,
+                    mAutomaticBrightnessController.getLastSensorValues(),
+                    mAutomaticBrightnessController.getLastSensorTimestamps());
         }
     }
 
@@ -2585,9 +2531,6 @@
         pw.println("  mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault);
         pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
-        pw.println("  mScreenBrightnessForVrRangeMinimum=" + mScreenBrightnessForVrRangeMinimum);
-        pw.println("  mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
-        pw.println("  mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
         pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
         pw.println("  mAllowAutoBrightnessWhileDozingConfig="
                 + mAllowAutoBrightnessWhileDozingConfig);
@@ -2637,7 +2580,6 @@
         pw.println("  mBrightnessReason=" + mBrightnessReason);
         pw.println("  mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
         pw.println("  mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment);
-        pw.println("  mScreenBrightnessForVrFloat=" + mScreenBrightnessForVr);
         pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
         pw.println("  mAppliedDimming=" + mAppliedDimming);
         pw.println("  mAppliedLowPower=" + mAppliedLowPower);
diff --git a/services/core/java/com/android/server/display/DisplayPowerController2.java b/services/core/java/com/android/server/display/DisplayPowerController2.java
index 9ded42a..346b340 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController2.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController2.java
@@ -198,15 +198,6 @@
 
     private final float mScreenBrightnessDefault;
 
-    // The minimum allowed brightness while in VR.
-    private final float mScreenBrightnessForVrRangeMinimum;
-
-    // The maximum allowed brightness while in VR.
-    private final float mScreenBrightnessForVrRangeMaximum;
-
-    // The default screen brightness for VR.
-    private final float mScreenBrightnessForVrDefault;
-
     // True if auto-brightness should be used.
     private boolean mUseSoftwareAutoBrightnessConfig;
 
@@ -299,9 +290,7 @@
     private boolean mAppliedAutoBrightness;
     private boolean mAppliedDimming;
     private boolean mAppliedLowPower;
-    private boolean mAppliedTemporaryBrightness;
     private boolean mAppliedTemporaryAutoBrightnessAdjustment;
-    private boolean mAppliedBrightnessBoost;
     private boolean mAppliedThrottling;
 
     // Reason for which the brightness was last changed. See {@link BrightnessReason} for more
@@ -395,14 +384,6 @@
     // behalf of the user.
     private float mCurrentScreenBrightnessSetting;
 
-    // The temporary screen brightness. Typically set when a user is interacting with the
-    // brightness slider but hasn't settled on a choice yet. Set to
-    // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set.
-    private float mTemporaryScreenBrightness;
-
-    // The current screen brightness while in VR mode.
-    private float mScreenBrightnessForVr;
-
     // The last auto brightness adjustment that was set by the user and not temporary. Set to
     // Float.NaN when an auto-brightness adjustment hasn't been recorded yet.
     private float mAutoBrightnessAdjustment;
@@ -428,6 +409,8 @@
 
     private DisplayDeviceConfig mDisplayDeviceConfig;
 
+    private boolean mIsEnabled;
+    private boolean mIsInTransition;
     /**
      * Creates the display power controller.
      */
@@ -445,6 +428,8 @@
         mHandler = new DisplayControllerHandler(handler.getLooper());
         mDisplayDeviceConfig = logicalDisplay.getPrimaryDisplayDeviceLocked()
                 .getDisplayDeviceConfig();
+        mIsEnabled = logicalDisplay.isEnabledLocked();
+        mIsInTransition = logicalDisplay.isInTransitionLocked();
         mWakelockController = mInjector.getWakelockController(mDisplayId, callbacks);
         mDisplayPowerProximityStateController = mInjector.getDisplayPowerProximityStateController(
                 mWakelockController, mDisplayDeviceConfig, mHandler.getLooper(),
@@ -490,14 +475,6 @@
         mScreenBrightnessDefault = clampAbsoluteBrightness(
                 mLogicalDisplay.getDisplayInfoLocked().brightnessDefault);
 
-        // VR SETTINGS
-        mScreenBrightnessForVrDefault = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_VR));
-        mScreenBrightnessForVrRangeMaximum = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM_VR));
-        mScreenBrightnessForVrRangeMinimum = clampAbsoluteBrightness(
-                pm.getBrightnessConstraint(PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR));
-
         loadBrightnessRampRates();
         mSkipScreenOnBrightnessRamp = resources.getBoolean(
                 R.bool.config_skipScreenOnBrightnessRamp);
@@ -564,9 +541,7 @@
         mDisplayBrightnessController =
                 new DisplayBrightnessController(context, null, mDisplayId);
         mCurrentScreenBrightnessSetting = getScreenBrightnessSetting();
-        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         mAutoBrightnessAdjustment = getAutoBrightnessAdjustmentSetting();
-        mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mTemporaryAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
         mPendingAutoBrightnessAdjustment = PowerManager.BRIGHTNESS_INVALID_FLOAT;
@@ -728,30 +703,37 @@
         final DisplayDeviceConfig config = device.getDisplayDeviceConfig();
         final IBinder token = device.getDisplayTokenLocked();
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        final boolean isEnabled = mLogicalDisplay.isEnabledLocked();
+        final boolean isInTransition = mLogicalDisplay.isInTransitionLocked();
         mHandler.post(() -> {
+            boolean changed = false;
             if (mDisplayDevice != device) {
+                changed = true;
                 mDisplayDevice = device;
                 mUniqueDisplayId = uniqueId;
                 mDisplayStatsId = mUniqueDisplayId.hashCode();
                 mDisplayDeviceConfig = config;
                 loadFromDisplayDeviceConfig(token, info);
                 mDisplayPowerProximityStateController.notifyDisplayDeviceChanged(config);
+
+                // Since the underlying display-device changed, we really don't know the
+                // last command that was sent to change it's state. Lets assume it is unknown so
+                // that we trigger a change immediately.
+                mPowerState.resetScreenState();
+            }
+            if (mIsEnabled != isEnabled || mIsInTransition != isInTransition) {
+                changed = true;
+                mIsEnabled = isEnabled;
+                mIsInTransition = isInTransition;
+            }
+
+            if (changed) {
                 updatePowerState();
             }
         });
     }
 
     /**
-     * Called when the displays are preparing to transition from one device state to another.
-     * This process involves turning off some displays so we need updatePowerState() to run and
-     * calculate the new state.
-     */
-    @Override
-    public void onDeviceStateTransition() {
-        sendUpdatePowerState();
-    }
-
-    /**
      * Unregisters all listeners and interrupts all running threads; halting future work.
      *
      * This method should be called when the DisplayPowerController2 is no longer in use; i.e. when
@@ -858,9 +840,6 @@
 
         mBrightnessSetting.registerListener(mBrightnessSettingListener);
         mContext.getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT),
-                false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
-        mContext.getContentResolver().registerContentObserver(
                 Settings.System.getUriFor(Settings.System.SCREEN_AUTO_BRIGHTNESS_ADJ),
                 false /*notifyForDescendants*/, mSettingsObserver, UserHandle.USER_ALL);
     }
@@ -1159,9 +1138,6 @@
                     state = Display.STATE_DOZE;
                 }
                 break;
-            case DisplayPowerRequest.POLICY_VR:
-                state = Display.STATE_VR;
-                break;
             case DisplayPowerRequest.POLICY_DIM:
             case DisplayPowerRequest.POLICY_BRIGHT:
             default:
@@ -1172,8 +1148,8 @@
 
         mDisplayPowerProximityStateController.updateProximityState(mPowerRequest, state);
 
-        if (!mLogicalDisplay.isEnabled()
-                || mLogicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
+        if (!mIsEnabled
+                || mIsInTransition
                 || mDisplayPowerProximityStateController.isScreenOffBecauseOfProximity()) {
             state = Display.STATE_OFF;
         }
@@ -1195,12 +1171,6 @@
         float brightnessState = displayBrightnessState.getBrightness();
         mBrightnessReasonTemp.set(displayBrightnessState.getBrightnessReason());
 
-        // Always use the VR brightness when in the VR state.
-        if (state == Display.STATE_VR) {
-            brightnessState = mScreenBrightnessForVr;
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_VR);
-        }
-
         final boolean autoBrightnessEnabledInDoze =
                 mDisplayBrightnessController.isAllowAutoBrightnessWhileDozingConfig()
                         && Display.isDozeState(state);
@@ -1218,16 +1188,6 @@
 
         final boolean userSetBrightnessChanged = updateUserSetScreenBrightness();
 
-        // Use the temporary screen brightness if there isn't an override, either from
-        // WindowManager or based on the display state.
-        if (isValidBrightnessValue(mTemporaryScreenBrightness)) {
-            brightnessState = mTemporaryScreenBrightness;
-            mAppliedTemporaryBrightness = true;
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_TEMPORARY);
-        } else {
-            mAppliedTemporaryBrightness = false;
-        }
-
         final boolean autoBrightnessAdjustmentChanged = updateAutoBrightnessAdjustment();
 
         // Use the autobrightness adjustment override if set.
@@ -1241,18 +1201,6 @@
             brightnessAdjustmentFlags = BrightnessReason.ADJUSTMENT_AUTO;
             mAppliedTemporaryAutoBrightnessAdjustment = false;
         }
-        // Apply brightness boost.
-        // We do this here after deciding whether auto-brightness is enabled so that we don't
-        // disable the light sensor during this temporary state.  That way when boost ends we will
-        // be able to resume normal auto-brightness behavior without any delay.
-        if (mPowerRequest.boostScreenBrightness
-                && brightnessState != PowerManager.BRIGHTNESS_OFF_FLOAT) {
-            brightnessState = PowerManager.BRIGHTNESS_MAX;
-            mBrightnessReasonTemp.setReason(BrightnessReason.REASON_BOOST);
-            mAppliedBrightnessBoost = true;
-        } else {
-            mAppliedBrightnessBoost = false;
-        }
 
         // If the brightness is already set then it's been overridden by something other than the
         // user, or is a temporary adjustment.
@@ -1411,10 +1359,11 @@
                 mBrightnessThrottler.getBrightnessMaxReason());
 
         // Animate the screen brightness when the screen is on or dozing.
-        // Skip the animation when the screen is off or suspended or transition to/from VR.
+        // Skip the animation when the screen is off or suspended.
         boolean brightnessAdjusted = false;
         final boolean brightnessIsTemporary =
-                mAppliedTemporaryBrightness || mAppliedTemporaryAutoBrightnessAdjustment;
+                (mBrightnessReason.getReason() == BrightnessReason.REASON_TEMPORARY)
+                        || mAppliedTemporaryAutoBrightnessAdjustment;
         if (!mPendingScreenOff) {
             if (mSkipScreenOnBrightnessRamp) {
                 if (state == Display.STATE_ON) {
@@ -1434,8 +1383,6 @@
                 }
             }
 
-            final boolean wasOrWillBeInVr =
-                    (state == Display.STATE_VR || oldState == Display.STATE_VR);
             final boolean initialRampSkip = (state == Display.STATE_ON && mSkipRampState
                     != RAMP_STATE_SKIP_NONE) || mDisplayPowerProximityStateController
                     .shouldSkipRampBecauseOfProximityChangeToNegative();
@@ -1478,7 +1425,7 @@
                     && (animateValue != currentBrightness
                     || sdrAnimateValue != currentSdrBrightness)) {
                 if (initialRampSkip || hasBrightnessBuckets
-                        || wasOrWillBeInVr || !isDisplayContentVisible || brightnessIsTemporary) {
+                        || !isDisplayContentVisible || brightnessIsTemporary) {
                     animateScreenBrightness(animateValue, sdrAnimateValue,
                             SCREEN_ANIMATION_RATE_MINIMUM);
                 } else {
@@ -1891,12 +1838,6 @@
                 fallbackType);
     }
 
-    private float clampScreenBrightnessForVr(float value) {
-        return MathUtils.constrain(
-                value, mScreenBrightnessForVrRangeMinimum,
-                mScreenBrightnessForVrRangeMaximum);
-    }
-
     private float clampScreenBrightness(float value) {
         if (Float.isNaN(value)) {
             value = PowerManager.BRIGHTNESS_MIN;
@@ -1985,23 +1926,6 @@
                 mPowerState.setColorFadeLevel(1.0f);
                 mPowerState.dismissColorFade();
             }
-        } else if (target == Display.STATE_VR) {
-            // Wait for brightness animation to complete beforehand when entering VR
-            // from screen on to prevent a perceptible jump because brightness may operate
-            // differently when the display is configured for dozing.
-            if (mScreenBrightnessRampAnimator.isAnimating()
-                    && mPowerState.getScreenState() == Display.STATE_ON) {
-                return;
-            }
-
-            // Set screen state.
-            if (!setScreenState(Display.STATE_VR)) {
-                return; // screen on blocked
-            }
-
-            // Dismiss the black surface without fanfare.
-            mPowerState.setColorFadeLevel(1.0f);
-            mPowerState.dismissColorFade();
         } else if (target == Display.STATE_DOZE) {
             // Want screen dozing.
             // Wait for brightness animation to complete beforehand when entering doze
@@ -2118,9 +2042,6 @@
                 mAutomaticBrightnessController.resetShortTermModel();
             }
         }
-        // We don't bother with a pending variable for VR screen brightness since we just
-        // immediately adapt to it.
-        mScreenBrightnessForVr = getScreenBrightnessForVrSetting();
         sendUpdatePowerState();
     }
 
@@ -2139,13 +2060,6 @@
         return clampAbsoluteBrightness(brightness);
     }
 
-    private float getScreenBrightnessForVrSetting() {
-        final float brightnessFloat = Settings.System.getFloatForUser(mContext.getContentResolver(),
-                Settings.System.SCREEN_BRIGHTNESS_FOR_VR_FLOAT, mScreenBrightnessForVrDefault,
-                UserHandle.USER_CURRENT);
-        return clampScreenBrightnessForVr(brightnessFloat);
-    }
-
     @Override
     public void setBrightness(float brightnessValue) {
         // Update the setting, which will eventually call back into DPC to have us actually update
@@ -2202,13 +2116,15 @@
         }
         if (mCurrentScreenBrightnessSetting == mPendingScreenBrightnessSetting) {
             mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-            mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+            mDisplayBrightnessController
+                    .setTemporaryBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT);
             return false;
         }
         setCurrentScreenBrightness(mPendingScreenBrightnessSetting);
         mLastUserSetScreenBrightness = mPendingScreenBrightnessSetting;
         mPendingScreenBrightnessSetting = PowerManager.BRIGHTNESS_INVALID_FLOAT;
-        mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+        mDisplayBrightnessController
+                .setTemporaryBrightness(PowerManager.BRIGHTNESS_INVALID_FLOAT);
         return true;
     }
 
@@ -2225,7 +2141,9 @@
                     : 1.0f;
             mBrightnessTracker.notifyBrightnessChanged(brightnessInNits, userInitiated,
                     powerFactor, hadUserDataPoint,
-                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId);
+                    mAutomaticBrightnessController.isDefaultConfig(), mUniqueDisplayId,
+                    mAutomaticBrightnessController.getLastSensorValues(),
+                    mAutomaticBrightnessController.getLastSensorTimestamps());
         }
     }
 
@@ -2257,9 +2175,6 @@
         pw.println("  mScreenBrightnessRangeDefault=" + mScreenBrightnessDefault);
         pw.println("  mScreenBrightnessDozeConfig=" + mScreenBrightnessDozeConfig);
         pw.println("  mScreenBrightnessDimConfig=" + mScreenBrightnessDimConfig);
-        pw.println("  mScreenBrightnessForVrRangeMinimum=" + mScreenBrightnessForVrRangeMinimum);
-        pw.println("  mScreenBrightnessForVrRangeMaximum=" + mScreenBrightnessForVrRangeMaximum);
-        pw.println("  mScreenBrightnessForVrDefault=" + mScreenBrightnessForVrDefault);
         pw.println("  mUseSoftwareAutoBrightnessConfig=" + mUseSoftwareAutoBrightnessConfig);
         pw.println("  mSkipScreenOnBrightnessRamp=" + mSkipScreenOnBrightnessRamp);
         pw.println("  mColorFadeFadesConfig=" + mColorFadeFadesConfig);
@@ -2291,20 +2206,16 @@
         pw.println("  mLastUserSetScreenBrightness=" + mLastUserSetScreenBrightness);
         pw.println("  mPendingScreenBrightnessSetting="
                 + mPendingScreenBrightnessSetting);
-        pw.println("  mTemporaryScreenBrightness=" + mTemporaryScreenBrightness);
         pw.println("  mAutoBrightnessAdjustment=" + mAutoBrightnessAdjustment);
         pw.println("  mBrightnessReason=" + mBrightnessReason);
         pw.println("  mTemporaryAutoBrightnessAdjustment=" + mTemporaryAutoBrightnessAdjustment);
         pw.println("  mPendingAutoBrightnessAdjustment=" + mPendingAutoBrightnessAdjustment);
-        pw.println("  mScreenBrightnessForVrFloat=" + mScreenBrightnessForVr);
         pw.println("  mAppliedAutoBrightness=" + mAppliedAutoBrightness);
         pw.println("  mAppliedDimming=" + mAppliedDimming);
         pw.println("  mAppliedLowPower=" + mAppliedLowPower);
         pw.println("  mAppliedThrottling=" + mAppliedThrottling);
-        pw.println("  mAppliedTemporaryBrightness=" + mAppliedTemporaryBrightness);
         pw.println("  mAppliedTemporaryAutoBrightnessAdjustment="
                 + mAppliedTemporaryAutoBrightnessAdjustment);
-        pw.println("  mAppliedBrightnessBoost=" + mAppliedBrightnessBoost);
         pw.println("  mDozing=" + mDozing);
         pw.println("  mSkipRampState=" + skipRampStateToString(mSkipRampState));
         pw.println("  mScreenOnBlockStartRealTime=" + mScreenOnBlockStartRealTime);
@@ -2541,7 +2452,8 @@
 
                 case MSG_SET_TEMPORARY_BRIGHTNESS:
                     // TODO: Should we have a a timeout for the temporary brightness?
-                    mTemporaryScreenBrightness = Float.intBitsToFloat(msg.arg1);
+                    mDisplayBrightnessController
+                            .setTemporaryBrightness(Float.intBitsToFloat(msg.arg1));
                     updatePowerState();
                     break;
 
diff --git a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
index 6677f35..46f1343 100644
--- a/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
+++ b/services/core/java/com/android/server/display/DisplayPowerControllerInterface.java
@@ -45,11 +45,6 @@
     void stop();
 
     /**
-     * Used to manage the displays preparing to transition from one device state to another.
-     */
-    void onDeviceStateTransition();
-
-    /**
      * Used to update the display's BrightnessConfiguration
      * @param config The new BrightnessConfiguration
      */
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 2f22d33..f650b11 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -145,7 +145,7 @@
     public void setScreenState(int state) {
         if (mScreenState != state) {
             if (DEBUG) {
-                Slog.d(TAG, "setScreenState: state=" + state);
+                Slog.w(TAG, "setScreenState: state=" + Display.stateToString(state));
             }
 
             mScreenState = state;
@@ -339,6 +339,15 @@
         if (mColorFade != null) mColorFade.dump(pw);
     }
 
+    /**
+     * Resets the screen state to unknown. Useful when the underlying display-device changes for the
+     * LogicalDisplay and we do not know the last state that was sent to it.
+     */
+    void resetScreenState() {
+        mScreenState = Display.STATE_UNKNOWN;
+        mScreenReady = false;
+    }
+
     private void scheduleScreenUpdate() {
         if (!mScreenUpdatePending) {
             mScreenUpdatePending = true;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5a714f5..dc5c80f2 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -38,6 +38,7 @@
 import android.view.DisplayAddress;
 import android.view.DisplayCutout;
 import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
 import android.view.RoundedCorners;
 import android.view.SurfaceControl;
 
@@ -583,7 +584,9 @@
                 DisplayModeRecord record = mSupportedModes.valueAt(i);
                 if (record.hasMatchingMode(mode)
                         && refreshRatesEquals(alternativeRefreshRates,
-                                record.mMode.getAlternativeRefreshRates())) {
+                                record.mMode.getAlternativeRefreshRates())
+                        && hdrTypesEqual(mode.supportedHdrTypes,
+                            record.mMode.getSupportedHdrTypes())) {
                     return record;
                 }
             }
@@ -686,6 +689,9 @@
                         res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
                 mInfo.installOrientation = mStaticDisplayInfo.installOrientation;
 
+                mInfo.displayShape = DisplayShape.fromResources(
+                        res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
+
                 if (mStaticDisplayInfo.isInternal) {
                     mInfo.type = Display.TYPE_INTERNAL;
                     mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
@@ -758,18 +764,8 @@
                             }
                         }
 
-                        // If the state change was from or to VR, then we need to tell the light
-                        // so that it can apply appropriate VR brightness settings. Also, update the
-                        // brightness so the state is propogated to light.
-                        boolean vrModeChange = false;
-                        if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
-                                currentState != state) {
-                            setVrMode(state == Display.STATE_VR);
-                            vrModeChange = true;
-                        }
-
                         // Apply brightness changes given that we are in a non-suspended state.
-                        if (brightnessChanged || vrModeChange) {
+                        if (brightnessChanged) {
                             setDisplayBrightness(brightnessState, sdrBrightnessState);
                             mBrightnessState = brightnessState;
                             mSdrBrightnessState = sdrBrightnessState;
@@ -781,15 +777,6 @@
                         }
                     }
 
-                    private void setVrMode(boolean isVrEnabled) {
-                        if (DEBUG) {
-                            Slog.d(TAG, "setVrMode("
-                                    + "id=" + physicalDisplayId
-                                    + ", state=" + Display.stateToString(state) + ")");
-                        }
-                        mBacklightAdapter.setVrMode(isVrEnabled);
-                    }
-
                     private void setDisplayState(int state) {
                         if (DEBUG) {
                             Slog.d(TAG, "setDisplayState("
@@ -1241,6 +1228,13 @@
         }
     }
 
+    private boolean hdrTypesEqual(int[] modeHdrTypes, int[] recordHdrTypes) {
+        int[] modeHdrTypesCopy = Arrays.copyOf(modeHdrTypes, modeHdrTypes.length);
+        Arrays.sort(modeHdrTypesCopy);
+        // Record HDR types are already sorted when we create the DisplayModeRecord
+        return Arrays.equals(modeHdrTypesCopy, recordHdrTypes);
+    }
+
     /** Supplies a context whose Resources apply runtime-overlays */
     Context getOverlayContext() {
         if (mOverlayContext == null) {
@@ -1258,7 +1252,7 @@
         DisplayModeRecord(SurfaceControl.DisplayMode mode,
                 float[] alternativeRefreshRates) {
             mMode = createMode(mode.width, mode.height, mode.refreshRate,
-                    alternativeRefreshRates);
+                    alternativeRefreshRates, mode.supportedHdrTypes);
         }
 
         /**
@@ -1272,7 +1266,7 @@
             return mMode.getPhysicalWidth() == mode.width
                     && mMode.getPhysicalHeight() == mode.height
                     && Float.floatToIntBits(mMode.getRefreshRate())
-                        == Float.floatToIntBits(mode.refreshRate);
+                    == Float.floatToIntBits(mode.refreshRate);
         }
 
         public String toString() {
@@ -1501,12 +1495,6 @@
             }
         }
 
-        void setVrMode(boolean isVrModeEnabled) {
-            if (mBacklight != null) {
-                mBacklight.setVrMode(isVrModeEnabled);
-            }
-        }
-
         void setForceSurfaceControl(boolean forceSurfaceControl) {
             mForceSurfaceControl = forceSurfaceControl;
         }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index dedc56a..8dd169bf 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -18,7 +18,6 @@
 
 import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
 
-import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Point;
@@ -68,33 +67,6 @@
 final class LogicalDisplay {
     private static final String TAG = "LogicalDisplay";
 
-    /**
-     * Phase indicating the logical display's existence is hidden from the rest of the framework.
-     * This can happen if the current layout has specifically requested to keep this display
-     * disabled.
-     */
-    static final int DISPLAY_PHASE_DISABLED = -1;
-
-    /**
-     * Phase indicating that the logical display is going through a layout transition.
-     * When in this phase, other systems can choose to special case power-state handling of a
-     * display that might be in a transition.
-     */
-    static final int DISPLAY_PHASE_LAYOUT_TRANSITION = 0;
-
-    /**
-     * The display is exposed to the rest of the system and its power state is determined by a
-     * power-request from PowerManager.
-     */
-    static final int DISPLAY_PHASE_ENABLED = 1;
-
-    @IntDef(prefix = {"DISPLAY_PHASE" }, value = {
-        DISPLAY_PHASE_DISABLED,
-        DISPLAY_PHASE_LAYOUT_TRANSITION,
-        DISPLAY_PHASE_ENABLED
-    })
-    @interface DisplayPhase {}
-
     // The layer stack we use when the display has been blanked to prevent any
     // of its content from appearing.
     private static final int BLANK_LAYER_STACK = -1;
@@ -159,14 +131,6 @@
     private final Rect mTempDisplayRect = new Rect();
 
     /**
-     * Indicates the current phase of the display. Generally, phases supersede any
-     * requests from PowerManager in DPC's calculation for the display state. Only when the
-     * phase is ENABLED does PowerManager's request for the display take effect.
-     */
-    @DisplayPhase
-    private int mPhase = DISPLAY_PHASE_ENABLED;
-
-    /**
      * The UID mappings for refresh rate override
      */
     private DisplayEventReceiver.FrameRateOverride[] mFrameRateOverrides;
@@ -181,12 +145,22 @@
      */
     private final SparseArray<Float> mTempFrameRateOverride;
 
+    // Indicates the display is enabled (allowed to be ON).
+    private boolean mIsEnabled;
+
+    // Indicates the display is part of a transition from one device-state ({@link
+    // DeviceStateManager}) to another. Being a "part" of a transition means that either
+    // the {@link mIsEnabled} is changing, or the underlying mPrimiaryDisplayDevice is changing.
+    private boolean mIsInTransition;
+
     public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
         mDisplayId = displayId;
         mLayerStack = layerStack;
         mPrimaryDisplayDevice = primaryDisplayDevice;
         mPendingFrameRateOverrideUids = new ArraySet<>();
         mTempFrameRateOverride = new SparseArray<>();
+        mIsEnabled = true;
+        mIsInTransition = false;
     }
 
     /**
@@ -233,6 +207,7 @@
                 info.displayCutout = mOverrideDisplayInfo.displayCutout;
                 info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
                 info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
+                info.displayShape = mOverrideDisplayInfo.displayShape;
             }
             mInfo.set(info);
         }
@@ -384,6 +359,9 @@
             if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
                 mBaseDisplayInfo.flags |= Display.FLAG_TOUCH_FEEDBACK_DISABLED;
             }
+            if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) != 0) {
+                mBaseDisplayInfo.flags |= Display.FLAG_OWN_FOCUS;
+            }
             Rect maskingInsets = getMaskingInsets(deviceInfo);
             int maskedWidth = deviceInfo.width - maskingInsets.left - maskingInsets.right;
             int maskedHeight = deviceInfo.height - maskingInsets.top - maskingInsets.bottom;
@@ -434,6 +412,7 @@
             mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
             mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
             mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
+            mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo.set(null);
         }
@@ -526,7 +505,7 @@
         // Prevent displays that are disabled from receiving input.
         // TODO(b/188914255): Remove once input can dispatch against device vs layerstack.
         device.setDisplayFlagsLocked(t,
-                (isEnabled() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
+                (isEnabledLocked() && device.getDisplayDeviceInfoLocked().touch != TOUCH_NONE)
                         ? SurfaceControl.DISPLAY_RECEIVES_INPUT
                         : 0);
 
@@ -768,32 +747,45 @@
         return old;
     }
 
-    public void setPhase(@DisplayPhase int phase) {
-        mPhase = phase;
-    }
-
-    /**
-     * Returns the currently set phase for this LogicalDisplay. Phases are used when transitioning
-     * from one device state to another. {@see LogicalDisplayMapper}.
-     */
-    @DisplayPhase
-    public int getPhase() {
-        return mPhase;
-    }
-
     /**
      * @return {@code true} if the LogicalDisplay is enabled or {@code false}
      * if disabled indicating that the display should be hidden from the rest of the apps and
      * framework.
      */
-    public boolean isEnabled() {
-        // DISPLAY_PHASE_LAYOUT_TRANSITION is still considered an 'enabled' phase.
-        return mPhase == DISPLAY_PHASE_ENABLED || mPhase == DISPLAY_PHASE_LAYOUT_TRANSITION;
+    public boolean isEnabledLocked() {
+        return mIsEnabled;
+    }
+
+    /**
+     * Sets the display as enabled.
+     *
+     * @param enable True if enabled, false otherwise.
+     */
+    public void setEnabledLocked(boolean enabled) {
+        mIsEnabled = enabled;
+    }
+
+    /**
+     * @return {@code true} if the LogicalDisplay is in a transition phase. This is used to indicate
+     * that we are getting ready to swap the underlying display-device and the display should be
+     * rendered appropriately to reduce jank.
+     */
+    public boolean isInTransitionLocked() {
+        return mIsInTransition;
+    }
+
+    /**
+     * Sets the transition phase.
+     * @param isInTransition True if it display is in transition.
+     */
+    public void setIsInTransitionLocked(boolean isInTransition) {
+        mIsInTransition = isInTransition;
     }
 
     public void dumpLocked(PrintWriter pw) {
         pw.println("mDisplayId=" + mDisplayId);
-        pw.println("mPhase=" + mPhase);
+        pw.println("mIsEnabled=" + mIsEnabled);
+        pw.println("mIsInTransition=" + mIsInTransition);
         pw.println("mLayerStack=" + mLayerStack);
         pw.println("mHasContent=" + mHasContent);
         pw.println("mDesiredDisplayModeSpecs={" + mDesiredDisplayModeSpecs + "}");
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index cb97e28..80f47a1 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -40,7 +40,7 @@
 import android.view.DisplayInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.display.LogicalDisplay.DisplayPhase;
+import com.android.server.display.layout.DisplayIdProducer;
 import com.android.server.display.layout.Layout;
 
 import java.io.PrintWriter;
@@ -83,6 +83,8 @@
     private static final int UPDATE_STATE_TRANSITION = 1;
     private static final int UPDATE_STATE_UPDATED = 2;
 
+    private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
+
     /**
      * Temporary display info, used for comparing display configurations.
      */
@@ -171,6 +173,8 @@
     private final ArrayMap<String, Integer> mVirtualDeviceDisplayMapping = new ArrayMap<>();
 
     private int mNextNonDefaultGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+    private final DisplayIdProducer mIdProducer = (isDefault) ->
+            isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++;
     private Layout mCurrentLayout = null;
     private int mDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
     private int mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
@@ -180,6 +184,14 @@
     LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
             @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
             @NonNull Handler handler) {
+        this(context, repo, listener, syncRoot, handler,
+                new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
+                        : sNextNonDefaultDisplayId++));
+    }
+
+    LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+            @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
+            @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap) {
         mSyncRoot = syncRoot;
         mPowerManager = context.getSystemService(PowerManager.class);
         mInteractive = mPowerManager.isInteractive();
@@ -194,7 +206,7 @@
         mDeviceStatesOnWhichToSleep = toSparseBooleanArray(context.getResources().getIntArray(
                 com.android.internal.R.array.config_deviceStatesOnWhichToSleep));
         mDisplayDeviceRepo.addListener(this);
-        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap();
+        mDeviceStateToLayoutMap = deviceStateToLayoutMap;
     }
 
     @Override
@@ -231,10 +243,22 @@
     }
 
     public LogicalDisplay getDisplayLocked(int displayId) {
-        return mLogicalDisplays.get(displayId);
+        return getDisplayLocked(displayId, /* includeDisabled= */ true);
+    }
+
+    public LogicalDisplay getDisplayLocked(int displayId, boolean includeDisabled) {
+        LogicalDisplay display = mLogicalDisplays.get(displayId);
+        if (display == null || display.isEnabledLocked() || includeDisabled) {
+            return display;
+        }
+        return null;
     }
 
     public LogicalDisplay getDisplayLocked(DisplayDevice device) {
+        return getDisplayLocked(device, /* includeDisabled= */ true);
+    }
+
+    public LogicalDisplay getDisplayLocked(DisplayDevice device, boolean includeDisabled) {
         if (device == null) {
             return null;
         }
@@ -242,21 +266,26 @@
         for (int i = 0; i < count; i++) {
             final LogicalDisplay display = mLogicalDisplays.valueAt(i);
             if (display.getPrimaryDisplayDeviceLocked() == device) {
-                return display;
+                if (display.isEnabledLocked() || includeDisabled) {
+                    return display;
+                }
+                return null;
             }
         }
         return null;
     }
 
-    public int[] getDisplayIdsLocked(int callingUid) {
+    public int[] getDisplayIdsLocked(int callingUid, boolean includeDisabled) {
         final int count = mLogicalDisplays.size();
         int[] displayIds = new int[count];
         int n = 0;
         for (int i = 0; i < count; i++) {
             LogicalDisplay display = mLogicalDisplays.valueAt(i);
-            DisplayInfo info = display.getDisplayInfoLocked();
-            if (info.hasAccess(callingUid)) {
-                displayIds[n++] = mLogicalDisplays.keyAt(i);
+            if (display.isEnabledLocked() || includeDisabled) {
+                DisplayInfo info = display.getDisplayInfoLocked();
+                if (info.hasAccess(callingUid)) {
+                    displayIds[n++] = mLogicalDisplays.keyAt(i);
+                }
             }
         }
         if (n != count) {
@@ -390,14 +419,12 @@
 
     void setDeviceStateLocked(int state, boolean isOverrideActive) {
         Slog.i(TAG, "Requesting Transition to state: " + state + ", from state=" + mDeviceState
-                + ", interactive=" + mInteractive);
+                + ", interactive=" + mInteractive + ", mBootCompleted=" + mBootCompleted);
         // As part of a state transition, we may need to turn off some displays temporarily so that
         // the transition is smooth. Plus, on some devices, only one internal displays can be
-        // on at a time. We use DISPLAY_PHASE_LAYOUT_TRANSITION to mark a display that needs to be
+        // on at a time. We use LogicalDisplay.setIsInTransition to mark a display that needs to be
         // temporarily turned off.
-        if (mDeviceState != DeviceStateManager.INVALID_DEVICE_STATE) {
-            resetLayoutLocked(mDeviceState, state, LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION);
-        }
+        resetLayoutLocked(mDeviceState, state, /* transitionValue= */ true);
         mPendingDeviceState = state;
         final boolean wakeDevice = shouldDeviceBeWoken(mPendingDeviceState, mDeviceState,
                 mInteractive, mBootCompleted);
@@ -507,7 +534,7 @@
         final int count = mLogicalDisplays.size();
         for (int i = 0; i < count; i++) {
             final LogicalDisplay display = mLogicalDisplays.valueAt(i);
-            if (display.getPhase() != LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
+            if (!display.isInTransitionLocked()) {
                 continue;
             }
 
@@ -523,7 +550,7 @@
     }
 
     private void transitionToPendingStateLocked() {
-        resetLayoutLocked(mDeviceState, mPendingDeviceState, LogicalDisplay.DISPLAY_PHASE_ENABLED);
+        resetLayoutLocked(mDeviceState, mPendingDeviceState, /* transitionValue= */ false);
         mDeviceState = mPendingDeviceState;
         mPendingDeviceState = DeviceStateManager.INVALID_DEVICE_STATE;
         applyLayoutLocked();
@@ -568,7 +595,7 @@
 
         // Create a logical display for the new display device
         LogicalDisplay display = createNewLogicalDisplayLocked(
-                device, Layout.assignDisplayIdLocked(false /*isDefault*/));
+                device, mIdProducer.getId(/* isDefault= */ false));
 
         applyLayoutLocked();
         updateLogicalDisplaysLocked();
@@ -601,7 +628,7 @@
                         & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0
                         && !nextDeviceInfo.address.equals(deviceInfo.address)) {
                     layout.createDisplayLocked(nextDeviceInfo.address,
-                            /* isDefault= */ true, /* isEnabled= */ true);
+                            /* isDefault= */ true, /* isEnabled= */ true, mIdProducer);
                     applyLayoutLocked();
                     return;
                 }
@@ -838,17 +865,17 @@
 
     /**
      * Goes through all the displays used in the layouts for the specified {@code fromState} and
-     * {@code toState} and applies the specified {@code phase}. When a new layout is requested, we
-     * put the displays that will change into a transitional phase so that they can all be turned
-     * OFF. Once all are confirmed OFF, then this method gets called again to reset the phase to
-     * normal operation. This helps to ensure that all display-OFF requests are made before
+     * {@code toState} and un/marks them for transition. When a new layout is requested, we
+     * mark the displays that will change into a transitional phase so that they can all be turned
+     * OFF. Once all are confirmed OFF, then this method gets called again to reset transition
+     * marker. This helps to ensure that all display-OFF requests are made before
      * display-ON which in turn hides any resizing-jank windows might incur when switching displays.
      *
      * @param fromState The state we are switching from.
      * @param toState The state we are switching to.
-     * @param phase The new phase to apply to the displays.
+     * @param transitionValue The value to mark the transition state: true == transitioning.
      */
-    private void resetLayoutLocked(int fromState, int toState, @DisplayPhase int phase) {
+    private void resetLayoutLocked(int fromState, int toState, boolean transitionValue) {
         final Layout fromLayout = mDeviceStateToLayoutMap.get(fromState);
         final Layout toLayout = mDeviceStateToLayoutMap.get(toState);
 
@@ -866,12 +893,16 @@
             // new layout.
             final DisplayAddress address = device.getDisplayDeviceInfoLocked().address;
 
-            // Virtual displays do not have addresses.
+            // Virtual displays do not have addresses, so account for nulls.
             final Layout.Display fromDisplay =
                     address != null ? fromLayout.getByAddress(address) : null;
             final Layout.Display toDisplay =
                     address != null ? toLayout.getByAddress(address) : null;
 
+            // If the display is in one of the layouts but not the other, then the content will
+            // change, so in this case we also want to blank the displays to avoid jank.
+            final boolean displayNotInBothLayouts = (fromDisplay == null) != (toDisplay == null);
+
             // If a layout doesn't mention a display-device at all, then the display-device defaults
             // to enabled. This is why we treat null as "enabled" in the code below.
             final boolean wasEnabled = fromDisplay == null || fromDisplay.isEnabled();
@@ -886,16 +917,23 @@
             // 3) It's enabled, but it's mapped to a new logical display ID. To the user this
             //    would look like apps moving from one screen to another since task-stacks stay
             //    with the logical display [ID].
+            // 4) It's in one layout but not the other, so the content will change.
             final boolean isTransitioning =
-                    (logicalDisplay.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION)
+                    logicalDisplay.isInTransitionLocked()
                     || (wasEnabled != willBeEnabled)
-                    || deviceHasNewLogicalDisplayId;
+                    || deviceHasNewLogicalDisplayId
+                    || displayNotInBothLayouts;
 
             if (isTransitioning) {
-                setDisplayPhase(logicalDisplay, phase);
-                if (phase == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION) {
-                    mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION);
+                if (transitionValue != logicalDisplay.isInTransitionLocked()) {
+                    Slog.i(TAG, "Set isInTransition on display " + displayId + ": "
+                            + transitionValue);
                 }
+                // This will either mark the display as "transitioning" if we are starting to change
+                // the device state, or remove the transitioning marker if the state change is
+                // ending.
+                logicalDisplay.setIsInTransitionLocked(transitionValue);
+                mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_TRANSITION);
             }
         }
     }
@@ -940,9 +978,7 @@
                 newDisplay.swapDisplaysLocked(oldDisplay);
             }
 
-            if (!displayLayout.isEnabled()) {
-                setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED);
-            }
+            setEnabledLocked(newDisplay, displayLayout.isEnabled());
         }
 
     }
@@ -961,23 +997,25 @@
         final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
         display.updateLocked(mDisplayDeviceRepo);
         mLogicalDisplays.put(displayId, display);
-        setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED);
         return display;
     }
 
-    private void setDisplayPhase(LogicalDisplay display, @DisplayPhase int phase) {
+    private void setEnabledLocked(LogicalDisplay display, boolean isEnabled) {
         final int displayId = display.getDisplayIdLocked();
         final DisplayInfo info = display.getDisplayInfoLocked();
 
         final boolean disallowSecondaryDisplay = mSingleDisplayDemoMode
                 && (info.type != Display.TYPE_INTERNAL);
-        if (phase != LogicalDisplay.DISPLAY_PHASE_DISABLED && disallowSecondaryDisplay) {
+        if (isEnabled && disallowSecondaryDisplay) {
             Slog.i(TAG, "Not creating a logical display for a secondary display because single"
                     + " display demo mode is enabled: " + display.getDisplayInfoLocked());
-            phase = LogicalDisplay.DISPLAY_PHASE_DISABLED;
+            isEnabled = false;
         }
 
-        display.setPhase(phase);
+        if (display.isEnabledLocked() != isEnabled) {
+            Slog.i(TAG, "SetEnabled on display " + displayId + ": " + isEnabled);
+            display.setEnabledLocked(isEnabled);
+        }
     }
 
     private int assignDisplayGroupIdLocked(
@@ -1005,7 +1043,8 @@
             return;
         }
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-        layout.createDisplayLocked(info.address, /* isDefault= */ true, /* isEnabled= */ true);
+        layout.createDisplayLocked(info.address, /* isDefault= */ true, /* isEnabled= */ true,
+                mIdProducer);
     }
 
     private int assignLayerStackLocked(int displayId) {
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index b0de844..0e11b53 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -29,6 +29,7 @@
 import android.util.DisplayMetrics;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.Surface;
 import android.view.SurfaceControl;
@@ -361,6 +362,8 @@
                 mInfo.state = mState;
                 // The display is trusted since it is created by system.
                 mInfo.flags |= FLAG_TRUSTED;
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 20b82c3..d24630d 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -20,7 +20,9 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT;
@@ -31,6 +33,7 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
 
 import static com.android.server.display.DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED;
+import static com.android.server.display.DisplayDeviceInfo.FLAG_DEVICE_DISPLAY_GROUP;
 import static com.android.server.display.DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
 import static com.android.server.display.DisplayDeviceInfo.FLAG_TOUCH_FEEDBACK_DISABLED;
 import static com.android.server.display.DisplayDeviceInfo.FLAG_TRUSTED;
@@ -51,6 +54,7 @@
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.view.Display;
+import android.view.DisplayShape;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -464,6 +468,9 @@
                         mInfo.flags |= FLAG_OWN_DISPLAY_GROUP;
                     }
                 }
+                if ((mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
+                    mInfo.flags |= FLAG_DEVICE_DISPLAY_GROUP;
+                }
 
                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0) {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_SECURE;
@@ -495,13 +502,29 @@
                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
                     mInfo.flags |= FLAG_TRUSTED;
                 }
-                if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0
-                        && (mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0) {
-                    mInfo.flags |= FLAG_ALWAYS_UNLOCKED;
+                if ((mFlags & VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED) != 0) {
+                    if ((mInfo.flags & DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP) != 0
+                            || (mFlags & VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP) != 0) {
+                        mInfo.flags |= FLAG_ALWAYS_UNLOCKED;
+                    } else {
+                        Slog.w(
+                                TAG,
+                                "Ignoring VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED as it requires"
+                                    + " VIRTUAL_DISPLAY_FLAG_DEVICE_DISPLAY_GROUP or"
+                                    + " VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP.");
+                    }
                 }
                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_TOUCH_FEEDBACK_DISABLED) != 0) {
                     mInfo.flags |= FLAG_TOUCH_FEEDBACK_DISABLED;
                 }
+                if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_FOCUS) != 0) {
+                    if ((mFlags & VIRTUAL_DISPLAY_FLAG_TRUSTED) != 0) {
+                        mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_FOCUS;
+                    } else {
+                        Slog.w(TAG, "Ignoring VIRTUAL_DISPLAY_FLAG_OWN_FOCUS as it requires "
+                                + "VIRTUAL_DISPLAY_FLAG_TRUSTED.");
+                    }
+                }
 
                 mInfo.type = Display.TYPE_VIRTUAL;
                 mInfo.touch = ((mFlags & VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH) == 0) ?
@@ -511,6 +534,9 @@
 
                 mInfo.ownerUid = mOwnerUid;
                 mInfo.ownerPackageName = mOwnerPackageName;
+
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 146b003..c759d98 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -34,6 +34,7 @@
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayAddress;
+import android.view.DisplayShape;
 import android.view.Surface;
 import android.view.SurfaceControl;
 
@@ -655,6 +656,8 @@
                 mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
                 // The display is trusted since it is created by system.
                 mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
+                mInfo.displayShape =
+                        DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
             }
             return mInfo;
         }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index d8eacd9..b6be713 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -34,10 +34,9 @@
     public static final int REASON_DOZE_DEFAULT = 3;
     public static final int REASON_AUTOMATIC = 4;
     public static final int REASON_SCREEN_OFF = 5;
-    public static final int REASON_VR = 6;
-    public static final int REASON_OVERRIDE = 7;
-    public static final int REASON_TEMPORARY = 8;
-    public static final int REASON_BOOST = 9;
+    public static final int REASON_OVERRIDE = 6;
+    public static final int REASON_TEMPORARY = 7;
+    public static final int REASON_BOOST = 8;
     public static final int REASON_MAX = REASON_BOOST;
 
     public static final int MODIFIER_DIMMED = 0x1;
@@ -185,8 +184,6 @@
                 return "automatic";
             case REASON_SCREEN_OFF:
                 return "screen_off";
-            case REASON_VR:
-                return "vr";
             case REASON_OVERRIDE:
                 return "override";
             case REASON_TEMPORARY:
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
index d62b1ee..fd4e296 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessUtils.java
@@ -28,7 +28,7 @@
      * Checks whether the brightness is within the valid brightness range, not including off.
      */
     public static boolean isValidBrightnessValue(float brightness) {
-        return brightness >= PowerManager.BRIGHTNESS_MIN
+        return !Float.isNaN(brightness) && brightness >= PowerManager.BRIGHTNESS_MIN
                 && brightness <= PowerManager.BRIGHTNESS_MAX;
     }
 
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
index 80b5e65..bdc8d9d 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessController.java
@@ -68,6 +68,21 @@
     }
 
     /**
+     * Sets the temporary brightness
+     */
+    public void setTemporaryBrightness(Float temporaryBrightness) {
+        mDisplayBrightnessStrategySelector.getTemporaryDisplayBrightnessStrategy()
+                .setTemporaryScreenBrightness(temporaryBrightness);
+    }
+
+    /**
+     * Returns the current selected DisplayBrightnessStrategy
+     */
+    public DisplayBrightnessStrategy getCurrentDisplayBrightnessStrategy() {
+        return mDisplayBrightnessStrategy;
+    }
+
+    /**
      * Returns a boolean flag indicating if the light sensor is to be used to decide the screen
      * brightness when dozing
      */
diff --git a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
index b83b13b..7d05f13 100644
--- a/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
+++ b/services/core/java/com/android/server/display/brightness/DisplayBrightnessStrategySelector.java
@@ -19,16 +19,19 @@
 import android.annotation.NonNull;
 import android.content.Context;
 import android.hardware.display.DisplayManagerInternal;
+import android.util.IndentingPrintWriter;
 import android.util.Slog;
 import android.view.Display;
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DisplayBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
 import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
 import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
 import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
+import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
 
 import java.io.PrintWriter;
 
@@ -48,7 +51,11 @@
     // The brightness strategy used to manage the brightness state when the request state is
     // invalid.
     private final OverrideBrightnessStrategy mOverrideBrightnessStrategy;
-    // The brightness strategy used to manage the brightness state request is invalid.
+    // The brightness strategy used to manage the brightness state in temporary state
+    private final TemporaryBrightnessStrategy mTemporaryBrightnessStrategy;
+    // The brightness strategy used to manage the brightness state when boost is requested
+    private final BoostBrightnessStrategy mBoostBrightnessStrategy;
+    // The brightness strategy used to manage the brightness state when the request is invalid.
     private final InvalidBrightnessStrategy mInvalidBrightnessStrategy;
 
     // We take note of the old brightness strategy so that we can know when the strategy changes.
@@ -67,6 +74,8 @@
         mDozeBrightnessStrategy = injector.getDozeBrightnessStrategy();
         mScreenOffBrightnessStrategy = injector.getScreenOffBrightnessStrategy();
         mOverrideBrightnessStrategy = injector.getOverrideBrightnessStrategy();
+        mTemporaryBrightnessStrategy = injector.getTemporaryBrightnessStrategy();
+        mBoostBrightnessStrategy = injector.getBoostBrightnessStrategy();
         mInvalidBrightnessStrategy = injector.getInvalidBrightnessStrategy();
         mAllowAutoBrightnessWhileDozingConfig = context.getResources().getBoolean(
                 R.bool.config_allowAutoBrightnessWhileDozing);
@@ -84,11 +93,16 @@
         DisplayBrightnessStrategy displayBrightnessStrategy = mInvalidBrightnessStrategy;
         if (targetDisplayState == Display.STATE_OFF) {
             displayBrightnessStrategy = mScreenOffBrightnessStrategy;
+        } else if (displayPowerRequest.boostScreenBrightness) {
+            displayBrightnessStrategy = mBoostBrightnessStrategy;
         } else if (shouldUseDozeBrightnessStrategy(displayPowerRequest)) {
             displayBrightnessStrategy = mDozeBrightnessStrategy;
         } else if (BrightnessUtils
                 .isValidBrightnessValue(displayPowerRequest.screenBrightnessOverride)) {
             displayBrightnessStrategy = mOverrideBrightnessStrategy;
+        } else if (BrightnessUtils.isValidBrightnessValue(
+                mTemporaryBrightnessStrategy.getTemporaryScreenBrightness())) {
+            displayBrightnessStrategy = mTemporaryBrightnessStrategy;
         }
 
         if (!mOldBrightnessStrategyName.equals(displayBrightnessStrategy.getName())) {
@@ -101,6 +115,10 @@
         return displayBrightnessStrategy;
     }
 
+    public TemporaryBrightnessStrategy getTemporaryDisplayBrightnessStrategy() {
+        return mTemporaryBrightnessStrategy;
+    }
+
     /**
      * Returns a boolean flag indicating if the light sensor is to be used to decide the screen
      * brightness when dozing
@@ -120,6 +138,8 @@
         writer.println(
                 "  mAllowAutoBrightnessWhileDozingConfig= "
                         + mAllowAutoBrightnessWhileDozingConfig);
+        IndentingPrintWriter ipw = new IndentingPrintWriter(writer, " ");
+        mTemporaryBrightnessStrategy.dump(ipw);
     }
 
     /**
@@ -152,6 +172,14 @@
             return new OverrideBrightnessStrategy();
         }
 
+        TemporaryBrightnessStrategy getTemporaryBrightnessStrategy() {
+            return new TemporaryBrightnessStrategy();
+        }
+
+        BoostBrightnessStrategy getBoostBrightnessStrategy() {
+            return new BoostBrightnessStrategy();
+        }
+
         InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
             return new InvalidBrightnessStrategy();
         }
diff --git a/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
new file mode 100644
index 0000000..475ef50
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/BoostBrightnessStrategy.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
+
+/**
+ * Manages the brightness of the display when the system brightness boost is requested.
+ */
+public class BoostBrightnessStrategy implements DisplayBrightnessStrategy {
+
+    public BoostBrightnessStrategy() {
+    }
+
+    // Set the brightness to the maximum value when display brightness boost is requested
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        // Todo(brup): Introduce a validator class and add validations before setting the brightness
+        DisplayBrightnessState displayBrightnessState =
+                BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_BOOST,
+                        PowerManager.BRIGHTNESS_MAX,
+                        PowerManager.BRIGHTNESS_MAX);
+        return displayBrightnessState;
+    }
+
+    @Override
+    public String getName() {
+        return "BoostBrightnessStrategy";
+    }
+}
diff --git a/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
new file mode 100644
index 0000000..f8063f3
--- /dev/null
+++ b/services/core/java/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategy.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display.brightness.strategy;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+import com.android.server.display.brightness.BrightnessUtils;
+
+import java.io.PrintWriter;
+
+/**
+ * Manages the brightness of the display when the system brightness is temporary
+ */
+public class TemporaryBrightnessStrategy implements DisplayBrightnessStrategy {
+    // The temporary screen brightness. Typically set when a user is interacting with the
+    // brightness slider but hasn't settled on a choice yet. Set to
+    // PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary brightness set.
+    private float mTemporaryScreenBrightness;
+
+    public TemporaryBrightnessStrategy() {
+        mTemporaryScreenBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+    }
+
+    // Use the temporary screen brightness if there isn't an override, either from
+    // WindowManager or based on the display state.
+    @Override
+    public DisplayBrightnessState updateBrightness(
+            DisplayManagerInternal.DisplayPowerRequest displayPowerRequest) {
+        // Todo(brup): Introduce a validator class and add validations before setting the brightness
+        DisplayBrightnessState displayBrightnessState =
+                BrightnessUtils.constructDisplayBrightnessState(BrightnessReason.REASON_TEMPORARY,
+                        mTemporaryScreenBrightness,
+                        mTemporaryScreenBrightness);
+        mTemporaryScreenBrightness = Float.NaN;
+        return displayBrightnessState;
+    }
+
+    @Override
+    public String getName() {
+        return "TemporaryBrightnessStrategy";
+    }
+
+    public float getTemporaryScreenBrightness() {
+        return mTemporaryScreenBrightness;
+    }
+
+    public void setTemporaryScreenBrightness(float temporaryScreenBrightness) {
+        mTemporaryScreenBrightness = temporaryScreenBrightness;
+    }
+
+    /**
+     * Dumps the state of this class.
+     */
+    public void dump(PrintWriter writer) {
+        writer.println("TemporaryBrightnessStrategy:");
+        writer.println("  mTemporaryScreenBrightness:" + mTemporaryScreenBrightness);
+    }
+}
diff --git a/services/core/java/com/android/server/display/layout/DisplayIdProducer.java b/services/core/java/com/android/server/display/layout/DisplayIdProducer.java
new file mode 100644
index 0000000..3029757
--- /dev/null
+++ b/services/core/java/com/android/server/display/layout/DisplayIdProducer.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display.layout;
+
+/**
+ * Interface for producing logical display ids.
+ */
+public interface DisplayIdProducer {
+
+    /**
+     * Generates a new display ID
+     * @param isDefault if requested display is the default display.
+     * @return the next unique logical display Id.
+     */
+    int getId(boolean isDefault);
+}
diff --git a/services/core/java/com/android/server/display/layout/Layout.java b/services/core/java/com/android/server/display/layout/Layout.java
index 7e16ea8..4a466fd 100644
--- a/services/core/java/com/android/server/display/layout/Layout.java
+++ b/services/core/java/com/android/server/display/layout/Layout.java
@@ -50,15 +50,33 @@
         return mDisplays.toString();
     }
 
+    @Override
+    public boolean equals(Object obj) {
+
+        if (!(obj instanceof  Layout)) {
+            return false;
+        }
+
+        Layout otherLayout = (Layout) obj;
+        return this.mDisplays.equals(otherLayout.mDisplays);
+    }
+
+    @Override
+    public int hashCode() {
+        return mDisplays.hashCode();
+    }
+
     /**
      * Creates a simple 1:1 LogicalDisplay mapping for the specified DisplayDevice.
      *
      * @param address Address of the device.
      * @param isDefault Indicates if the device is meant to be the default display.
+     * @param isEnabled Indicates if this display is usable and can be switched on
      * @return The new layout.
      */
     public Display createDisplayLocked(
-            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled) {
+            @NonNull DisplayAddress address, boolean isDefault, boolean isEnabled,
+            DisplayIdProducer idProducer) {
         if (contains(address)) {
             Slog.w(TAG, "Attempting to add second definition for display-device: " + address);
             return null;
@@ -74,7 +92,7 @@
         // Note that the logical display ID is saved into the layout, so when switching between
         // different layouts, a logical display can be destroyed and later recreated with the
         // same logical display ID.
-        final int logicalDisplayId = assignDisplayIdLocked(isDefault);
+        final int logicalDisplayId = idProducer.getId(isDefault);
         final Display display = new Display(address, logicalDisplayId, isEnabled);
 
         mDisplays.add(display);
@@ -158,25 +176,64 @@
      * Describes how a {@link LogicalDisplay} is built from {@link DisplayDevice}s.
      */
     public static class Display {
+        public static final int POSITION_UNKNOWN = -1;
+        public static final int POSITION_FRONT = 0;
+        public static final int POSITION_REAR = 1;
+
         // Address of the display device to map to this display.
         private final DisplayAddress mAddress;
 
         // Logical Display ID to apply to this display.
         private final int mLogicalDisplayId;
 
-        // Indicates that this display is not usable and should remain off.
+        // Indicates if this display is usable and can be switched on
         private final boolean mIsEnabled;
 
+        // The direction the display faces
+        // {@link DeviceStateToLayoutMap.POSITION_FRONT} or
+        // {@link DeviceStateToLayoutMap.POSITION_REAR}.
+        // {@link DeviceStateToLayoutMap.POSITION_UNKNOWN} is unspecified.
+        private int mPosition;
+
         Display(@NonNull DisplayAddress address, int logicalDisplayId, boolean isEnabled) {
             mAddress = address;
             mLogicalDisplayId = logicalDisplayId;
             mIsEnabled = isEnabled;
+            mPosition = POSITION_UNKNOWN;
         }
 
         @Override
         public String toString() {
-            return "{addr: " + mAddress + ", dispId: " + mLogicalDisplayId
-                    + "(" + (mIsEnabled ? "ON" : "OFF") + ")}";
+            return "{"
+                    + "dispId: " + mLogicalDisplayId
+                    + "(" + (mIsEnabled ? "ON" : "OFF") + ")"
+                    + ", addr: " + mAddress
+                    +  ((mPosition == POSITION_UNKNOWN) ? "" : ", position: " + mPosition)
+                    + "}";
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (!(obj instanceof Display)) {
+                return false;
+            }
+
+            Display otherDisplay = (Display) obj;
+
+            return otherDisplay.mIsEnabled == this.mIsEnabled
+                    && otherDisplay.mPosition == this.mPosition
+                    && otherDisplay.mLogicalDisplayId == this.mLogicalDisplayId
+                    && this.mAddress.equals(otherDisplay.mAddress);
+        }
+
+        @Override
+        public int hashCode() {
+            int result = 1;
+            result = 31 * result + Boolean.hashCode(mIsEnabled);
+            result = 31 * result + mPosition;
+            result = 31 * result + mLogicalDisplayId;
+            result = 31 * result + mAddress.hashCode();
+            return result;
         }
 
         public DisplayAddress getAddress() {
@@ -190,5 +247,9 @@
         public boolean isEnabled() {
             return mIsEnabled;
         }
+
+        public void setPosition(int position) {
+            mPosition = position;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/display/utils/SensorUtils.java b/services/core/java/com/android/server/display/utils/SensorUtils.java
index cb40b40..4924ad5 100644
--- a/services/core/java/com/android/server/display/utils/SensorUtils.java
+++ b/services/core/java/com/android/server/display/utils/SensorUtils.java
@@ -33,6 +33,9 @@
      */
     public static Sensor findSensor(SensorManager sensorManager, String sensorType,
             String sensorName, int fallbackType) {
+        if ("".equals(sensorName) && "".equals(sensorType)) {
+            return null;
+        }
         final boolean isNameSpecified = !TextUtils.isEmpty(sensorName);
         final boolean isTypeSpecified = !TextUtils.isEmpty(sensorType);
         if (isNameSpecified || isTypeSpecified) {
diff --git a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
index 049a339..4855be6 100644
--- a/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
+++ b/services/core/java/com/android/server/hdmi/ArcTerminationActionFromAvr.java
@@ -27,7 +27,7 @@
     private static final int STATE_ARC_TERMINATED = 2;
 
     // the required maximum response time specified in CEC 9.2
-    private static final int TIMEOUT_MS = 1000;
+    public static final int TIMEOUT_MS = 1000;
 
     ArcTerminationActionFromAvr(HdmiCecLocalDevice source) {
         super(source);
@@ -85,6 +85,8 @@
     }
 
     private void handleTerminateArcTimeout() {
+        // Disable ARC if TV didn't respond with <Report ARC Terminated> in time.
+        audioSystem().setArcStatus(false);
         HdmiLogger.debug("handleTerminateArcTimeout");
         finish();
     }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
index 79820a2..6925507 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecConfig.java
@@ -16,7 +16,7 @@
 
 package com.android.server.hdmi;
 
-import static android.hardware.hdmi.HdmiControlManager.CecSettingName;
+import static android.hardware.hdmi.HdmiControlManager.SettingName;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -45,7 +45,10 @@
 
 /**
  * The {@link HdmiCecConfig} class is used for getting information about
- * available HDMI CEC settings.
+ * available HDMI control settings, including CEC settings and eARC settings.
+ *
+ * TODO(b/240379115): rename this class and related methods in this package to represent that the
+ * settings storage mechanism applies to all HDMI control settings and not just CEC settings.
  */
 public class HdmiCecConfig {
     private static final String TAG = "HdmiCecConfig";
@@ -105,7 +108,7 @@
          *
          * @param setting name of a CEC setting that changed
          */
-        void onChange(@NonNull @CecSettingName String setting);
+        void onChange(@NonNull @SettingName String setting);
     }
 
     /**
@@ -204,21 +207,21 @@
 
     protected class Setting {
         @NonNull private final Context mContext;
-        @NonNull private final @CecSettingName String mName;
+        @NonNull private final @SettingName String mName;
         private final boolean mUserConfigurable;
 
         private Value mDefaultValue = null;
         private List<Value> mAllowedValues = new ArrayList<>();
 
         Setting(@NonNull Context context,
-                @NonNull @CecSettingName String name,
+                @NonNull @SettingName String name,
                 int userConfResId) {
             mContext = context;
             mName = name;
             mUserConfigurable = mContext.getResources().getBoolean(userConfResId);
         }
 
-        public @CecSettingName String getName() {
+        public @SettingName String getName() {
             return mName;
         }
 
@@ -315,6 +318,16 @@
                 R.bool.config_cecRoutingControlDisabled_allowed,
                 R.bool.config_cecRoutingControlDisabled_default);
 
+        Setting soundbarMode = registerSetting(
+                HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+                R.bool.config_cecSoundbarMode_userConfigurable);
+        soundbarMode.registerValue(HdmiControlManager.SOUNDBAR_MODE_ENABLED,
+                R.bool.config_cecSoundbarModeEnabled_allowed,
+                R.bool.config_cecSoundbarModeEnabled_default);
+        soundbarMode.registerValue(HdmiControlManager.SOUNDBAR_MODE_DISABLED,
+                R.bool.config_cecSoundbarModeDisabled_allowed,
+                R.bool.config_cecSoundbarModeDisabled_default);
+
         Setting powerControlMode = registerSetting(
                 HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                 R.bool.config_cecPowerControlMode_userConfigurable);
@@ -663,6 +676,16 @@
                 R.bool.config_cecQuerySadMaxDisabled_allowed,
                 R.bool.config_cecQuerySadMaxDisabled_default);
 
+        Setting earcEnabled = registerSetting(
+                HdmiControlManager.SETTING_NAME_EARC_ENABLED,
+                R.bool.config_earcEnabled_userConfigurable);
+        earcEnabled.registerValue(HdmiControlManager.EARC_FEATURE_ENABLED,
+                R.bool.config_earcFeatureEnabled_allowed,
+                R.bool.config_earcFeatureEnabled_default);
+        earcEnabled.registerValue(HdmiControlManager.EARC_FEATURE_DISABLED,
+                R.bool.config_earcFeatureDisabled_allowed,
+                R.bool.config_earcFeatureDisabled_default);
+
         verifySettings();
     }
 
@@ -670,7 +693,7 @@
         this(context, new StorageAdapter(context));
     }
 
-    private Setting registerSetting(@NonNull @CecSettingName String name,
+    private Setting registerSetting(@NonNull @SettingName String name,
                                int userConfResId) {
         Setting setting = new Setting(mContext, name, userConfResId);
         mSettings.put(name, setting);
@@ -701,6 +724,8 @@
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
                 return STORAGE_SHARED_PREFS;
+            case HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE:
+                return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
@@ -760,6 +785,8 @@
                 return STORAGE_SHARED_PREFS;
             case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX:
                 return STORAGE_SHARED_PREFS;
+            case HdmiControlManager.SETTING_NAME_EARC_ENABLED:
+                return STORAGE_SHARED_PREFS;
             default:
                 throw new VerificationException("Invalid CEC setting '" + setting.getName()
                         + "' storage.");
@@ -774,6 +801,8 @@
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL:
                 return setting.getName();
+            case HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE:
+                return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE:
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE:
@@ -833,6 +862,8 @@
                 return setting.getName();
             case HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX:
                 return setting.getName();
+            case HdmiControlManager.SETTING_NAME_EARC_ENABLED:
+                return setting.getName();
             default:
                 throw new VerificationException("Invalid CEC setting '" + setting.getName()
                     + "' storage key.");
@@ -871,14 +902,6 @@
         }
     }
 
-    private void notifySettingChanged(@NonNull @CecSettingName String name) {
-        Setting setting = getSetting(name);
-        if (setting == null) {
-            throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
-        }
-        notifySettingChanged(setting);
-    }
-
     protected void notifySettingChanged(@NonNull Setting setting) {
         synchronized (mLock) {
             ArrayMap<SettingChangeListener, Executor> listeners =
@@ -902,7 +925,7 @@
     /**
      * Register change listener for a given setting name using DirectExecutor.
      */
-    public void registerChangeListener(@NonNull @CecSettingName String name,
+    public void registerChangeListener(@NonNull @SettingName String name,
                                        SettingChangeListener listener) {
         registerChangeListener(name, listener, ConcurrentUtils.DIRECT_EXECUTOR);
     }
@@ -910,7 +933,7 @@
     /**
      * Register change listener for a given setting name and executor.
      */
-    public void registerChangeListener(@NonNull @CecSettingName String name,
+    public void registerChangeListener(@NonNull @SettingName String name,
                                        SettingChangeListener listener,
                                        Executor executor) {
         Setting setting = getSetting(name);
@@ -933,7 +956,7 @@
     /**
      * Remove change listener for a given setting name.
      */
-    public void removeChangeListener(@NonNull @CecSettingName String name,
+    public void removeChangeListener(@NonNull @SettingName String name,
                                      SettingChangeListener listener) {
         Setting setting = getSetting(name);
         if (setting == null) {
@@ -954,14 +977,14 @@
     /**
      * Returns a list of all settings based on the XML metadata.
      */
-    public @CecSettingName List<String> getAllSettings() {
+    public @SettingName List<String> getAllSettings() {
         return new ArrayList<>(mSettings.keySet());
     }
 
     /**
      * Returns a list of user-modifiable settings based on the XML metadata.
      */
-    public @CecSettingName List<String> getUserSettings() {
+    public @SettingName List<String> getUserSettings() {
         List<String> settings = new ArrayList<>();
         for (Setting setting: mSettings.values()) {
             if (setting.getUserConfigurable()) {
@@ -975,7 +998,7 @@
      * For a given setting name returns true if and only if the value type of that
      * setting is a string.
      */
-    public boolean isStringValueType(@NonNull @CecSettingName String name) {
+    public boolean isStringValueType(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -987,7 +1010,7 @@
      * For a given setting name returns true if and only if the value type of that
      * setting is an int.
      */
-    public boolean isIntValueType(@NonNull @CecSettingName String name) {
+    public boolean isIntValueType(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -998,7 +1021,7 @@
     /**
      * For a given setting name returns values that are allowed for that setting (string).
      */
-    public List<String> getAllowedStringValues(@NonNull @CecSettingName String name) {
+    public List<String> getAllowedStringValues(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1017,7 +1040,7 @@
     /**
      * For a given setting name returns values that are allowed for that setting (string).
      */
-    public List<Integer> getAllowedIntValues(@NonNull @CecSettingName String name) {
+    public List<Integer> getAllowedIntValues(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1036,7 +1059,7 @@
     /**
      * For a given setting name returns the default value for that setting (string).
      */
-    public String getDefaultStringValue(@NonNull @CecSettingName String name) {
+    public String getDefaultStringValue(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1051,7 +1074,7 @@
     /**
      * For a given setting name returns the default value for that setting (int).
      */
-    public int getDefaultIntValue(@NonNull @CecSettingName String name) {
+    public int getDefaultIntValue(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1066,7 +1089,7 @@
     /**
      * For a given setting name returns the current value of that setting (string).
      */
-    public String getStringValue(@NonNull @CecSettingName String name) {
+    public String getStringValue(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1082,7 +1105,7 @@
     /**
      * For a given setting name returns the current value of that setting (int).
      */
-    public int getIntValue(@NonNull @CecSettingName String name) {
+    public int getIntValue(@NonNull @SettingName String name) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1100,7 +1123,7 @@
     /**
      * For a given setting name and value sets the current value of that setting (string).
      */
-    public void setStringValue(@NonNull @CecSettingName String name, @NonNull String value) {
+    public void setStringValue(@NonNull @SettingName String name, @NonNull String value) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
@@ -1123,7 +1146,7 @@
     /**
      * For a given setting name and value sets the current value of that setting (int).
      */
-    public void setIntValue(@NonNull @CecSettingName String name, int value) {
+    public void setIntValue(@NonNull @SettingName String name, int value) {
         Setting setting = getSetting(name);
         if (setting == null) {
             throw new IllegalArgumentException("Setting '" + name + "' does not exist.");
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index 5c1b33c..50edd0e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -636,7 +636,7 @@
     void onReceiveCommand(HdmiCecMessage message) {
         assertRunOnServiceThread();
         if (((ACTION_ON_RECEIVE_MSG & CEC_DISABLED_IGNORE) == 0)
-                && !mService.isControlEnabled()
+                && !mService.isCecControlEnabled()
                 && !HdmiCecMessage.isCecTransportMessage(message.getOpcode())) {
             if ((ACTION_ON_RECEIVE_MSG & CEC_DISABLED_LOG_WARNING) != 0) {
                 HdmiLogger.warning("Message " + message + " received when cec disabled");
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 2622cef..b4d7fb9 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -698,7 +698,7 @@
 
     protected void reportFeatures() {
         List<Integer> localDeviceTypes = new ArrayList<>();
-        for (HdmiCecLocalDevice localDevice : mService.getAllLocalDevices()) {
+        for (HdmiCecLocalDevice localDevice : mService.getAllCecLocalDevices()) {
             localDeviceTypes.add(localDevice.mDeviceType);
         }
 
@@ -728,7 +728,7 @@
     protected int handleStandby(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // Seq #12
-        if (mService.isControlEnabled()
+        if (mService.isCecControlEnabled()
                 && !mService.isProhibitMode()
                 && mService.isPowerOnOrTransient()) {
             mService.standby();
@@ -1359,7 +1359,8 @@
         List<SendKeyAction> action = getActions(SendKeyAction.class);
         int logicalAddress = findAudioReceiverAddress();
         if (logicalAddress == Constants.ADDR_INVALID
-                || logicalAddress == mDeviceInfo.getLogicalAddress()) {
+                || mService.getAllCecLocalDevices().stream().anyMatch(
+                        device -> device.getDeviceInfo().getLogicalAddress() == logicalAddress)) {
             // Don't send key event to invalid device or itself.
             Slog.w(
                     TAG,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 32ff5e22..ccaa9255d 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -226,6 +226,8 @@
     @Override
     @ServiceThreadOnly
     protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
+        terminateAudioReturnChannel();
+
         super.disableDevice(initiatedByCec, callback);
         assertRunOnServiceThread();
         mService.unregisterTvInputCallback(mTvInputCallback);
@@ -884,7 +886,7 @@
     private void notifyArcStatusToAudioService(boolean enabled) {
         // Note that we don't set any name to ARC.
         mService.getAudioManager()
-            .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI, enabled ? 1 : 0, "", "");
+            .setWiredDeviceConnectionState(AudioSystem.DEVICE_IN_HDMI_ARC, enabled ? 1 : 0, "", "");
     }
 
     void reportAudioStatus(int source) {
@@ -1042,7 +1044,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             setRoutingPort(portId);
             setLocalActivePort(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
@@ -1088,6 +1090,16 @@
         }
     }
 
+    private void terminateAudioReturnChannel() {
+        // remove pending initiation actions
+        removeAction(ArcInitiationActionFromAvr.class);
+        if (!isArcEnabled()
+                || !mService.readBooleanSystemProperty(Constants.PROPERTY_ARC_SUPPORT, true)) {
+            return;
+        }
+        addAndStartAction(new ArcTerminationActionFromAvr(this));
+    }
+
     /** Reports if System Audio Mode is supported by the connected TV */
     interface TvSystemAudioModeSupportedCallback {
 
@@ -1312,6 +1324,9 @@
     @ServiceThreadOnly
     private void launchDeviceDiscovery() {
         assertRunOnServiceThread();
+        if (mService.isDeviceDiscoveryHandledByPlayback()) {
+            return;
+        }
         if (hasAction(DeviceDiscoveryAction.class)) {
             Slog.i(TAG, "Device Discovery Action is in progress. Restarting.");
             removeAction(DeviceDiscoveryAction.class);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
index e6c2e7c..3ec3f94 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java
@@ -137,7 +137,7 @@
                         // Since we removed all devices when it starts and device discovery action
                         // does not poll local devices, we should put device info of local device
                         // manually here.
-                        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+                        for (HdmiCecLocalDevice device : mService.getAllCecLocalDevices()) {
                             mService.getHdmiCecNetwork().addCecDevice(device.getDeviceInfo());
                         }
 
@@ -190,7 +190,7 @@
         if (isAlreadyActiveSource(targetDevice, targetAddress, callback)) {
             return;
         }
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             setActiveSource(targetDevice, "HdmiCecLocalDevicePlayback#deviceSelect()");
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
@@ -239,7 +239,7 @@
     @ServiceThreadOnly
     protected void onStandby(boolean initiatedByCec, int standbyAction) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             return;
         }
         boolean wasActiveSource = isActiveSource();
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 8a22ab9..96e7b03 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -259,7 +259,7 @@
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
         }
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             setActiveSource(targetDevice, "HdmiCecLocalDeviceTv#deviceSelect()");
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
@@ -272,7 +272,7 @@
     private void handleSelectInternalSource() {
         assertRunOnServiceThread();
         // Seq #18
-        if (mService.isControlEnabled()
+        if (mService.isCecControlEnabled()
                 && getActiveSource().logicalAddress != getDeviceInfo().getLogicalAddress()) {
             updateActiveSource(
                     getDeviceInfo().getLogicalAddress(),
@@ -371,7 +371,7 @@
             return;
         }
         getActiveSource().invalidate();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             setActivePortId(portId);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
@@ -694,7 +694,7 @@
                         // Since we removed all devices when it starts and
                         // device discovery action does not poll local devices,
                         // we should put device info of local device manually here
-                        for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) {
+                        for (HdmiCecLocalDevice device : mService.getAllCecLocalDevices()) {
                             mService.getHdmiCecNetwork().addCecDevice(device.getDeviceInfo());
                         }
 
@@ -742,7 +742,7 @@
     // Seq #32
     void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled() || hasAction(DeviceDiscoveryAction.class)) {
+        if (!mService.isCecControlEnabled() || hasAction(DeviceDiscoveryAction.class)) {
             setSystemAudioMode(false);
             invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE);
             return;
@@ -1181,7 +1181,7 @@
     }
 
     private boolean isMessageForSystemAudio(HdmiCecMessage message) {
-        return mService.isControlEnabled()
+        return mService.isCecControlEnabled()
                 && message.getSource() == Constants.ADDR_AUDIO_SYSTEM
                 && (message.getDestination() == Constants.ADDR_TV
                         || message.getDestination() == Constants.ADDR_BROADCAST)
@@ -1330,7 +1330,7 @@
         removeAction(SystemAudioAutoInitiationAction.class);
         removeAction(VolumeControlAction.class);
 
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             setSystemAudioMode(false);
         }
     }
@@ -1376,7 +1376,7 @@
     protected void onStandby(boolean initiatedByCec, int standbyAction) {
         assertRunOnServiceThread();
         // Seq #11
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             return;
         }
         boolean sendStandbyOnSleep =
@@ -1415,7 +1415,7 @@
     @Constants.HandleMessageResult
     int startOneTouchRecord(int recorderAddress, byte[] recordSource) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
             announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED);
             return Constants.ABORT_NOT_IN_CORRECT_MODE;
@@ -1444,7 +1444,7 @@
     @ServiceThreadOnly
     void stopOneTouchRecord(int recorderAddress) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             Slog.w(TAG, "Can not stop one touch record. CEC control is disabled.");
             announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED);
             return;
@@ -1478,7 +1478,7 @@
     @ServiceThreadOnly
     void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
             announceTimerRecordingResult(recorderAddress,
                     TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED);
@@ -1514,7 +1514,7 @@
     @ServiceThreadOnly
     void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) {
         assertRunOnServiceThread();
-        if (!mService.isControlEnabled()) {
+        if (!mService.isCecControlEnabled()) {
             Slog.w(TAG, "Can not start one touch record. CEC control is disabled.");
             announceClearTimerRecordingResult(recorderAddress, CLEAR_TIMER_STATUS_CEC_DISABLE);
             return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java b/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
index 552ff37..f819f00 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecPowerStatusController.java
@@ -75,7 +75,7 @@
     }
 
     private void sendReportPowerStatus(int powerStatus) {
-        for (HdmiCecLocalDevice localDevice : mHdmiControlService.getAllLocalDevices()) {
+        for (HdmiCecLocalDevice localDevice : mHdmiControlService.getAllCecLocalDevices()) {
             mHdmiControlService.sendCecCommand(
                     HdmiCecMessageBuilder.buildReportPowerStatus(
                             localDevice.getDeviceInfo().getLogicalAddress(),
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 1ae1b5b..43cd71a 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -19,6 +19,8 @@
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE;
 import static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE;
 import static android.hardware.hdmi.HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
+import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_DISABLED;
+import static android.hardware.hdmi.HdmiControlManager.SOUNDBAR_MODE_ENABLED;
 
 import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
 import static com.android.server.hdmi.Constants.DISABLED;
@@ -188,6 +190,7 @@
     static final int INITIATED_BY_SCREEN_ON = 2;
     static final int INITIATED_BY_WAKE_UP_MESSAGE = 3;
     static final int INITIATED_BY_HOTPLUG = 4;
+    static final int INITIATED_BY_SOUNDBAR_MODE = 5;
 
     // The reason code representing the intent action that drives the standby
     // procedure. The procedure starts either by Intent.ACTION_SCREEN_OFF or
@@ -336,8 +339,8 @@
     // Used to synchronize the access to the service.
     private final Object mLock = new Object();
 
-    // Type of logical devices hosted in the system. Stored in the unmodifiable list.
-    private final List<Integer> mLocalDevices;
+    // Type of CEC logical devices hosted in the system. Stored in the unmodifiable list.
+    private final List<Integer> mCecLocalDevices;
 
     // List of records for HDMI control status change listener for death monitoring.
     @GuardedBy("mLock")
@@ -496,7 +499,7 @@
     @VisibleForTesting HdmiControlService(Context context, List<Integer> deviceTypes,
             AudioDeviceVolumeManagerWrapperInterface audioDeviceVolumeManager) {
         super(context);
-        mLocalDevices = deviceTypes;
+        mCecLocalDevices = deviceTypes;
         mSettingsObserver = new SettingsObserver(mHandler);
         mHdmiCecConfig = new HdmiCecConfig(context);
         mAudioDeviceVolumeManager = audioDeviceVolumeManager;
@@ -504,7 +507,7 @@
 
     public HdmiControlService(Context context) {
         super(context);
-        mLocalDevices = readDeviceTypes();
+        mCecLocalDevices = readDeviceTypes();
         mSettingsObserver = new SettingsObserver(mHandler);
         mHdmiCecConfig = new HdmiCecConfig(context);
     }
@@ -666,7 +669,7 @@
                     public void onChange(String setting) {
                         @HdmiControlManager.HdmiCecControl int enabled = mHdmiCecConfig.getIntValue(
                                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED);
-                        setControlEnabled(enabled);
+                        setCecEnabled(enabled);
                     }
                 }, mServiceThreadExecutor);
         mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
@@ -693,6 +696,14 @@
                         }
                     }
                 }, mServiceThreadExecutor);
+        mHdmiCecConfig.registerChangeListener(HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+                new HdmiCecConfig.SettingChangeListener() {
+                    @Override
+                    public void onChange(String setting) {
+                        setSoundbarMode(mHdmiCecConfig.getIntValue(
+                                HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE));
+                    }
+                }, mServiceThreadExecutor);
         mHdmiCecConfig.registerChangeListener(
                 HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
                 new HdmiCecConfig.SettingChangeListener() {
@@ -747,7 +758,7 @@
             mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_ON);
             // Start all actions that were queued because the device was in standby
             if (mAddressAllocated) {
-                for (HdmiCecLocalDevice localDevice : getAllLocalDevices()) {
+                for (HdmiCecLocalDevice localDevice : getAllCecLocalDevices()) {
                     localDevice.startQueuedActions();
                 }
             }
@@ -770,6 +781,11 @@
     }
 
     @VisibleForTesting
+    void setAudioManager(AudioManager audioManager) {
+        mAudioManager = audioManager;
+    }
+
+    @VisibleForTesting
     void setCecController(HdmiCecController cecController) {
         mCecController = cecController;
     }
@@ -847,6 +863,47 @@
     }
 
     /**
+     * Triggers the address allocation that states the presence of a local device audio system in
+     * the network.
+     */
+    @VisibleForTesting
+    public void setSoundbarMode(final int settingValue) {
+        HdmiCecLocalDevicePlayback playback = playback();
+        HdmiCecLocalDeviceAudioSystem audioSystem = audioSystem();
+        if (playback == null) {
+            Slog.w(TAG, "Device type not compatible to change soundbar mode.");
+            return;
+        }
+        if (!SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+            Slog.w(TAG, "Device type doesn't support ARC.");
+            return;
+        }
+        if (settingValue == SOUNDBAR_MODE_DISABLED && audioSystem != null) {
+            if (audioSystem.isArcEnabled()) {
+                audioSystem.addAndStartAction(new ArcTerminationActionFromAvr(audioSystem));
+            }
+            if (isSystemAudioActivated()) {
+                audioSystem.terminateSystemAudioMode();
+            }
+        }
+        mAddressAllocated = false;
+        initializeCecLocalDevices(INITIATED_BY_SOUNDBAR_MODE);
+    }
+
+    /**
+     * Checks if the Device Discovery is handled by the local device playback.
+     * See {@link HdmiCecLocalDeviceAudioSystem#launchDeviceDiscovery}.
+     */
+    public boolean isDeviceDiscoveryHandledByPlayback() {
+        HdmiCecLocalDevicePlayback playback = playback();
+        if (playback != null && (playback.hasAction(DeviceDiscoveryAction.class)
+                || playback.hasAction(HotplugDetectionAction.class))) {
+            return true;
+        }
+        return false;
+    }
+
+    /**
      * Called when the initialization of local devices is complete.
      */
     private void onInitializeCecComplete(int initiatedBy) {
@@ -866,7 +923,7 @@
                 break;
             case INITIATED_BY_SCREEN_ON:
                 reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP;
-                final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
+                final List<HdmiCecLocalDevice> devices = getAllCecLocalDevices();
                 for (HdmiCecLocalDevice device : devices) {
                     device.onInitializeCecComplete(initiatedBy);
                 }
@@ -990,15 +1047,33 @@
 
         mCecController.enableSystemCecControl(true);
         mCecController.setLanguage(mMenuLanguage);
-        initializeLocalDevices(initiatedBy);
+        initializeCecLocalDevices(initiatedBy);
+    }
+
+    /**
+     * If the Soundbar mode is turned on, adds the local device type audio system in the list of
+     * local devices types. This method is called when the local devices are initialized such that
+     * the list of local devices is in sync with the Soundbar mode setting.
+     * @return the list of integer device types
+     */
+    @ServiceThreadOnly
+    private List<Integer> getCecLocalDeviceTypes() {
+        ArrayList<Integer> allLocalDeviceTypes = new ArrayList<>(mCecLocalDevices);
+        if (mHdmiCecConfig.getIntValue(HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE)
+                == SOUNDBAR_MODE_ENABLED
+                && !allLocalDeviceTypes.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM)
+                && SystemProperties.getBoolean(Constants.PROPERTY_ARC_SUPPORT, true)) {
+            allLocalDeviceTypes.add(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        }
+        return allLocalDeviceTypes;
     }
 
     @ServiceThreadOnly
-    private void initializeLocalDevices(final int initiatedBy) {
+    private void initializeCecLocalDevices(final int initiatedBy) {
         assertRunOnServiceThread();
         // A container for [Device type, Local device info].
         ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
-        for (int type : mLocalDevices) {
+        for (int type : getCecLocalDeviceTypes()) {
             HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type);
             if (localDevice == null) {
                 localDevice = HdmiCecLocalDevice.create(this, type);
@@ -1008,7 +1083,7 @@
         }
         // It's now safe to flush existing local devices from mCecController since they were
         // already moved to 'localDevices'.
-        clearLocalDevices();
+        clearCecLocalDevices();
         allocateLogicalAddress(localDevices, initiatedBy);
     }
 
@@ -1051,9 +1126,10 @@
 
                             // Address allocation completed for all devices. Notify each device.
                             if (allocatingDevices.size() == ++finished[0]) {
-                                if (initiatedBy != INITIATED_BY_HOTPLUG) {
-                                    // In case of the hotplug we don't call
-                                    // onInitializeCecComplete()
+                                if (initiatedBy != INITIATED_BY_HOTPLUG
+                                        && initiatedBy != INITIATED_BY_SOUNDBAR_MODE) {
+                                    // In case of the hotplug or soundbar mode setting toggle
+                                    // we don't call onInitializeCecComplete()
                                     // since we reallocate the logical address only.
                                     onInitializeCecComplete(initiatedBy);
                                 }
@@ -1331,7 +1407,7 @@
      * Returns whether the source address of a message is a local logical address.
      */
     private boolean sourceAddressIsLocal(HdmiCecMessage message) {
-        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+        for (HdmiCecLocalDevice device : getAllCecLocalDevices()) {
             if (message.getSource() == device.getDeviceInfo().getLogicalAddress()
                     && message.getSource() != Constants.ADDR_UNREGISTERED) {
                 HdmiLogger.warning(
@@ -1413,7 +1489,7 @@
         if (connected && !isTvDevice()
                 && getPortInfo(portId).getType() == HdmiPortInfo.PORT_OUTPUT) {
             ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
-            for (int type : mLocalDevices) {
+            for (int type : getCecLocalDeviceTypes()) {
                 HdmiCecLocalDevice localDevice = mHdmiCecNetwork.getLocalDevice(type);
                 if (localDevice == null) {
                     localDevice = HdmiCecLocalDevice.create(this, type);
@@ -1461,7 +1537,7 @@
         return strategy | iterationStrategy;
     }
 
-    List<HdmiCecLocalDevice> getAllLocalDevices() {
+    List<HdmiCecLocalDevice> getAllCecLocalDevices() {
         assertRunOnServiceThread();
         return mHdmiCecNetwork.getLocalDeviceList();
     }
@@ -1484,7 +1560,7 @@
         if (physicalAddress == getPhysicalAddress()) {
             return;
         }
-        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+        for (HdmiCecLocalDevice device : getAllCecLocalDevices()) {
             if (device.getDeviceInfo().getLogicalAddress() == logicalAddress) {
                 HdmiLogger.debug("allocate logical address for " + device.getDeviceInfo());
                 ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>();
@@ -1555,7 +1631,7 @@
     // Set the display name in HdmiDeviceInfo of the current devices to content provided by
     // Global.DEVICE_NAME. Only set and broadcast if the new name is different.
     private void setDisplayName(String newDisplayName) {
-        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+        for (HdmiCecLocalDevice device : getAllCecLocalDevices()) {
             HdmiDeviceInfo deviceInfo = device.getDeviceInfo();
             if (deviceInfo.getDisplayName().equals(newDisplayName)) {
                 continue;
@@ -1816,10 +1892,10 @@
         @Override
         public int[] getSupportedTypes() {
             initBinderCall();
-            // mLocalDevices is an unmodifiable list - no lock necesary.
-            int[] localDevices = new int[mLocalDevices.size()];
+            // mCecLocalDevices is an unmodifiable list - no lock necessary.
+            int[] localDevices = new int[mCecLocalDevices.size()];
             for (int i = 0; i < localDevices.length; ++i) {
-                localDevices[i] = mLocalDevices.get(i);
+                localDevices[i] = mCecLocalDevices.get(i);
             }
             return localDevices;
         }
@@ -2379,7 +2455,7 @@
             runOnServiceThread(new Runnable() {
                 @Override
                 public void run() {
-                    if (!isControlEnabled()) {
+                    if (!isCecControlEnabled()) {
                         Slog.w(TAG, "Hdmi control is disabled.");
                         return ;
                     }
@@ -3172,15 +3248,15 @@
     }
 
     boolean isTvDevice() {
-        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV);
+        return mCecLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV);
     }
 
     boolean isAudioSystemDevice() {
-        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
+        return mCecLocalDevices.contains(HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
     }
 
     boolean isPlaybackDevice() {
-        return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
+        return mCecLocalDevices.contains(HdmiDeviceInfo.DEVICE_PLAYBACK);
     }
 
     boolean isSwitchDevice() {
@@ -3217,7 +3293,7 @@
         return mAudioDeviceVolumeManager;
     }
 
-    boolean isControlEnabled() {
+    boolean isCecControlEnabled() {
         synchronized (mLock) {
             return mHdmiControlEnabled == HdmiControlManager.HDMI_CEC_CONTROL_ENABLED;
         }
@@ -3329,7 +3405,7 @@
         invokeVendorCommandListenersOnControlStateChanged(false,
                 HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY);
 
-        final List<HdmiCecLocalDevice> devices = getAllLocalDevices();
+        final List<HdmiCecLocalDevice> devices = getAllCecLocalDevices();
 
         if (!isStandbyMessageReceived() && !canGoToStandby()) {
             mPowerStatusController.setPowerStatus(HdmiControlManager.POWER_STATUS_STANDBY);
@@ -3339,7 +3415,7 @@
             return;
         }
 
-        disableDevices(new PendingActionClearedCallback() {
+        disableCecLocalDevices(new PendingActionClearedCallback() {
             @Override
             public void onCleared(HdmiCecLocalDevice device) {
                 Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType);
@@ -3387,7 +3463,7 @@
         return mMenuLanguage;
     }
 
-    private void disableDevices(PendingActionClearedCallback callback) {
+    private void disableCecLocalDevices(PendingActionClearedCallback callback) {
         if (mCecController != null) {
             for (HdmiCecLocalDevice device : mHdmiCecNetwork.getLocalDeviceList()) {
                 device.disableDevice(mStandbyMessageReceived, callback);
@@ -3397,7 +3473,8 @@
     }
 
     @ServiceThreadOnly
-    private void clearLocalDevices() {
+    @VisibleForTesting
+    protected void clearCecLocalDevices() {
         assertRunOnServiceThread();
         if (mCecController == null) {
             return;
@@ -3573,7 +3650,7 @@
     }
 
     @ServiceThreadOnly
-    void setControlEnabled(@HdmiControlManager.HdmiCecControl int enabled) {
+    void setCecEnabled(@HdmiControlManager.HdmiCecControl int enabled) {
         assertRunOnServiceThread();
 
         synchronized (mLock) {
@@ -3581,7 +3658,7 @@
         }
 
         if (enabled == HDMI_CEC_CONTROL_ENABLED) {
-            enableHdmiControlService();
+            onEnableCec();
             setHdmiCecVolumeControlEnabledInternal(getHdmiCecConfig().getIntValue(
                     HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE));
             return;
@@ -3596,7 +3673,7 @@
         runOnServiceThread(new Runnable() {
             @Override
             public void run() {
-                disableHdmiControlService();
+                onDisableCec();
             }
         });
         announceHdmiControlStatusChange(enabled);
@@ -3605,7 +3682,7 @@
     }
 
     @ServiceThreadOnly
-    private void enableHdmiControlService() {
+    private void onEnableCec() {
         mCecController.enableCec(true);
         mCecController.enableSystemCecControl(true);
         mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED);
@@ -3614,8 +3691,8 @@
     }
 
     @ServiceThreadOnly
-    private void disableHdmiControlService() {
-        disableDevices(
+    private void onDisableCec() {
+        disableCecLocalDevices(
                 new PendingActionClearedCallback() {
                     @Override
                     public void onCleared(HdmiCecLocalDevice device) {
@@ -3627,7 +3704,7 @@
                                         mCecController.enableCec(false);
                                         mCecController.enableSystemCecControl(false);
                                         mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED);
-                                        clearLocalDevices();
+                                        clearCecLocalDevices();
                                     }
                                 });
                     }
@@ -3671,7 +3748,7 @@
 
         // If the current device is a source device, check if the current Active Source matches
         // the local device info.
-        for (HdmiCecLocalDevice device : getAllLocalDevices()) {
+        for (HdmiCecLocalDevice device : getAllCecLocalDevices()) {
             boolean deviceIsActiveSource =
                     logicalAddress == device.getDeviceInfo().getLogicalAddress()
                             && physicalAddress == getPhysicalAddress();
diff --git a/services/core/java/com/android/server/input/BatteryController.java b/services/core/java/com/android/server/input/BatteryController.java
index c83fa2d..c99a7a0 100644
--- a/services/core/java/com/android/server/input/BatteryController.java
+++ b/services/core/java/com/android/server/input/BatteryController.java
@@ -19,7 +19,13 @@
 import android.annotation.BinderThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.BatteryState;
 import android.hardware.input.IInputDeviceBatteryListener;
 import android.hardware.input.IInputDeviceBatteryState;
@@ -46,6 +52,7 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 
 /**
@@ -74,6 +81,7 @@
     private final NativeInputManagerService mNative;
     private final Handler mHandler;
     private final UEventManager mUEventManager;
+    private final BluetoothBatteryManager mBluetoothBatteryManager;
 
     // Maps a pid to the registered listener record for that process. There can only be one battery
     // listener per process.
@@ -88,18 +96,23 @@
     private boolean mIsPolling = false;
     @GuardedBy("mLock")
     private boolean mIsInteractive = true;
+    @Nullable
+    @GuardedBy("mLock")
+    private BluetoothBatteryManager.BluetoothBatteryListener mBluetoothBatteryListener;
 
     BatteryController(Context context, NativeInputManagerService nativeService, Looper looper) {
-        this(context, nativeService, looper, new UEventManager() {});
+        this(context, nativeService, looper, new UEventManager() {},
+                new LocalBluetoothBatteryManager(context));
     }
 
     @VisibleForTesting
     BatteryController(Context context, NativeInputManagerService nativeService, Looper looper,
-            UEventManager uEventManager) {
+            UEventManager uEventManager, BluetoothBatteryManager bbm) {
         mContext = context;
         mNative = nativeService;
         mHandler = new Handler(looper);
         mUEventManager = uEventManager;
+        mBluetoothBatteryManager = bbm;
     }
 
     public void systemRunning() {
@@ -150,6 +163,7 @@
                 // This is the first listener that is monitoring this device.
                 monitor = new DeviceMonitor(deviceId);
                 mDeviceMonitors.put(deviceId, monitor);
+                updateBluetoothMonitoring();
             }
 
             if (DEBUG) {
@@ -202,25 +216,39 @@
         mHandler.postDelayed(this::handlePollEvent, delayStart ? POLLING_PERIOD_MILLIS : 0);
     }
 
-    private String getInputDeviceName(int deviceId) {
+    private <R> R processInputDevice(int deviceId, R defaultValue, Function<InputDevice, R> func) {
         final InputDevice device =
                 Objects.requireNonNull(mContext.getSystemService(InputManager.class))
                         .getInputDevice(deviceId);
-        return device != null ? device.getName() : "<none>";
+        return device == null ? defaultValue : func.apply(device);
+    }
+
+    private String getInputDeviceName(int deviceId) {
+        return processInputDevice(deviceId, "<none>" /*defaultValue*/, InputDevice::getName);
     }
 
     private boolean hasBattery(int deviceId) {
-        final InputDevice device =
-                Objects.requireNonNull(mContext.getSystemService(InputManager.class))
-                        .getInputDevice(deviceId);
-        return device != null && device.hasBattery();
+        return processInputDevice(deviceId, false /*defaultValue*/, InputDevice::hasBattery);
     }
 
     private boolean isUsiDevice(int deviceId) {
-        final InputDevice device =
-                Objects.requireNonNull(mContext.getSystemService(InputManager.class))
-                        .getInputDevice(deviceId);
-        return device != null && device.supportsUsi();
+        return processInputDevice(deviceId, false /*defaultValue*/, InputDevice::supportsUsi);
+    }
+
+    @Nullable
+    private BluetoothDevice getBluetoothDevice(int inputDeviceId) {
+        return getBluetoothDevice(mContext,
+                processInputDevice(inputDeviceId, null /*defaultValue*/,
+                        InputDevice::getBluetoothAddress));
+    }
+
+    @Nullable
+    private static BluetoothDevice getBluetoothDevice(Context context, String address) {
+        if (address == null) return null;
+        final BluetoothAdapter adapter =
+                Objects.requireNonNull(context.getSystemService(BluetoothManager.class))
+                        .getAdapter();
+        return adapter.getRemoteDevice(address);
     }
 
     @GuardedBy("mLock")
@@ -350,6 +378,17 @@
         }
     }
 
+    private void handleBluetoothBatteryLevelChange(long eventTime, String address) {
+        synchronized (mLock) {
+            final DeviceMonitor monitor = findIf(mDeviceMonitors, (m) ->
+                    (m.mBluetoothDevice != null
+                            && address.equals(m.mBluetoothDevice.getAddress())));
+            if (monitor != null) {
+                monitor.onBluetoothBatteryChanged(eventTime);
+            }
+        }
+    }
+
     /** Gets the current battery state of an input device. */
     public IInputDeviceBatteryState getBatteryState(int deviceId) {
         synchronized (mLock) {
@@ -475,17 +514,52 @@
                 isPresent ? mNative.getBatteryCapacity(deviceId) / 100.f : Float.NaN);
     }
 
+    // Queries the battery state of an input device from Bluetooth.
+    private State queryBatteryStateFromBluetooth(int deviceId, long updateTime,
+            @NonNull BluetoothDevice bluetoothDevice) {
+        final int level = mBluetoothBatteryManager.getBatteryLevel(bluetoothDevice.getAddress());
+        if (level == BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF
+                || level == BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+            return new State(deviceId);
+        }
+        return new State(deviceId, updateTime, true /*isPresent*/, BatteryState.STATUS_UNKNOWN,
+                level / 100.f);
+    }
+
+    private void updateBluetoothMonitoring() {
+        synchronized (mLock) {
+            if (anyOf(mDeviceMonitors, (m) -> m.mBluetoothDevice != null)) {
+                // At least one input device being monitored is connected over Bluetooth.
+                if (mBluetoothBatteryListener == null) {
+                    if (DEBUG) Slog.d(TAG, "Registering bluetooth battery listener");
+                    mBluetoothBatteryListener = this::handleBluetoothBatteryLevelChange;
+                    mBluetoothBatteryManager.addListener(mBluetoothBatteryListener);
+                }
+            } else if (mBluetoothBatteryListener != null) {
+                // No Bluetooth input devices are monitored, so remove the registered listener.
+                if (DEBUG) Slog.d(TAG, "Unregistering bluetooth battery listener");
+                mBluetoothBatteryManager.removeListener(mBluetoothBatteryListener);
+                mBluetoothBatteryListener = null;
+            }
+        }
+    }
+
     // Holds the state of an InputDevice for which battery changes are currently being monitored.
     private class DeviceMonitor {
         protected final State mState;
         // Represents whether the input device has a sysfs battery node.
         protected boolean mHasBattery = false;
 
+        protected final State mBluetoothState;
+        @Nullable
+        private BluetoothDevice mBluetoothDevice;
+
         @Nullable
         private UEventBatteryListener mUEventBatteryListener;
 
         DeviceMonitor(int deviceId) {
             mState = new State(deviceId);
+            mBluetoothState = new State(deviceId);
 
             // Load the initial battery state and start monitoring.
             final long eventTime = SystemClock.uptimeMillis();
@@ -506,18 +580,31 @@
         }
 
         private void configureDeviceMonitor(long eventTime) {
+            final int deviceId = mState.deviceId;
             if (mHasBattery != hasBattery(mState.deviceId)) {
                 mHasBattery = !mHasBattery;
                 if (mHasBattery) {
-                    startMonitoring();
+                    startNativeMonitoring();
                 } else {
-                    stopMonitoring();
+                    stopNativeMonitoring();
                 }
                 updateBatteryStateFromNative(eventTime);
             }
+
+            final BluetoothDevice bluetoothDevice = getBluetoothDevice(deviceId);
+            if (!Objects.equals(mBluetoothDevice, bluetoothDevice)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "Bluetooth device "
+                            + ((bluetoothDevice != null) ? "is" : "is not")
+                            + " now present for deviceId " + deviceId);
+                }
+                mBluetoothDevice = bluetoothDevice;
+                updateBluetoothMonitoring();
+                updateBatteryStateFromBluetooth(eventTime);
+            }
         }
 
-        private void startMonitoring() {
+        private void startNativeMonitoring() {
             final String batteryPath = mNative.getBatteryDevicePath(mState.deviceId);
             if (batteryPath == null) {
                 return;
@@ -538,7 +625,7 @@
             return path.startsWith("/sys") ? path.substring(4) : path;
         }
 
-        private void stopMonitoring() {
+        private void stopNativeMonitoring() {
             if (mUEventBatteryListener != null) {
                 mUEventManager.removeListener(mUEventBatteryListener);
                 mUEventBatteryListener = null;
@@ -547,7 +634,9 @@
 
         // This must be called when the device is no longer being monitored.
         public void onMonitorDestroy() {
-            stopMonitoring();
+            stopNativeMonitoring();
+            mBluetoothDevice = null;
+            updateBluetoothMonitoring();
         }
 
         protected void updateBatteryStateFromNative(long eventTime) {
@@ -555,6 +644,13 @@
                     queryBatteryStateFromNative(mState.deviceId, eventTime, mHasBattery));
         }
 
+        protected void updateBatteryStateFromBluetooth(long eventTime) {
+            final State bluetoothState = mBluetoothDevice == null ? new State(mState.deviceId)
+                    : queryBatteryStateFromBluetooth(mState.deviceId, eventTime,
+                            mBluetoothDevice);
+            mBluetoothState.updateIfChanged(bluetoothState);
+        }
+
         public void onPoll(long eventTime) {
             processChangesAndNotify(eventTime, this::updateBatteryStateFromNative);
         }
@@ -563,6 +659,10 @@
             processChangesAndNotify(eventTime, this::updateBatteryStateFromNative);
         }
 
+        public void onBluetoothBatteryChanged(long eventTime) {
+            processChangesAndNotify(eventTime, this::updateBatteryStateFromBluetooth);
+        }
+
         public boolean requiresPolling() {
             return true;
         }
@@ -577,6 +677,10 @@
 
         // Returns the current battery state that can be used to notify listeners BatteryController.
         public State getBatteryStateForReporting() {
+            // Give precedence to the Bluetooth battery state if it's present.
+            if (mBluetoothState.isPresent) {
+                return new State(mBluetoothState);
+            }
             return new State(mState);
         }
 
@@ -585,7 +689,8 @@
             return "DeviceId=" + mState.deviceId
                     + ", Name='" + getInputDeviceName(mState.deviceId) + "'"
                     + ", NativeBattery=" + mState
-                    + ", UEventListener=" + (mUEventBatteryListener != null ? "added" : "none");
+                    + ", UEventListener=" + (mUEventBatteryListener != null ? "added" : "none")
+                    + ", BluetoothBattery=" + mBluetoothState;
         }
     }
 
@@ -670,6 +775,10 @@
 
         @Override
         public State getBatteryStateForReporting() {
+            // Give precedence to the Bluetooth battery state if it's present.
+            if (mBluetoothState.isPresent) {
+                return new State(mBluetoothState);
+            }
             return mValidityTimeoutCallback != null
                     ? new State(mState) : new State(mState.deviceId);
         }
@@ -729,6 +838,82 @@
         }
     }
 
+    // An interface used to change the API of adding a bluetooth battery listener to a more
+    // test-friendly format.
+    @VisibleForTesting
+    interface BluetoothBatteryManager {
+        @VisibleForTesting
+        interface BluetoothBatteryListener {
+            void onBluetoothBatteryChanged(long eventTime, String address);
+        }
+        void addListener(BluetoothBatteryListener listener);
+        void removeListener(BluetoothBatteryListener listener);
+        int getBatteryLevel(String address);
+    }
+
+    private static class LocalBluetoothBatteryManager implements BluetoothBatteryManager {
+        private final Context mContext;
+        @Nullable
+        @GuardedBy("mBroadcastReceiver")
+        private BluetoothBatteryListener mRegisteredListener;
+        @GuardedBy("mBroadcastReceiver")
+        private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (!BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED.equals(intent.getAction())) {
+                    return;
+                }
+                final BluetoothDevice bluetoothDevice = intent.getParcelableExtra(
+                        BluetoothDevice.EXTRA_DEVICE, BluetoothDevice.class);
+                if (bluetoothDevice == null) {
+                    return;
+                }
+                // We do not use the EXTRA_LEVEL value. Instead, the battery level will be queried
+                // from BluetoothDevice later so that we use a single source for the battery level.
+                synchronized (mBroadcastReceiver) {
+                    if (mRegisteredListener != null) {
+                        final long eventTime = SystemClock.uptimeMillis();
+                        mRegisteredListener.onBluetoothBatteryChanged(
+                                eventTime, bluetoothDevice.getAddress());
+                    }
+                }
+            }
+        };
+
+        LocalBluetoothBatteryManager(Context context) {
+            mContext = context;
+        }
+
+        @Override
+        public void addListener(BluetoothBatteryListener listener) {
+            synchronized (mBroadcastReceiver) {
+                if (mRegisteredListener != null) {
+                    throw new IllegalStateException(
+                            "Only one bluetooth battery listener can be registered at once.");
+                }
+                mRegisteredListener = listener;
+                mContext.registerReceiver(mBroadcastReceiver,
+                        new IntentFilter(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED));
+            }
+        }
+
+        @Override
+        public void removeListener(BluetoothBatteryListener listener) {
+            synchronized (mBroadcastReceiver) {
+                if (!listener.equals(mRegisteredListener)) {
+                    throw new IllegalStateException("Listener is not registered.");
+                }
+                mRegisteredListener = null;
+                mContext.unregisterReceiver(mBroadcastReceiver);
+            }
+        }
+
+        @Override
+        public int getBatteryLevel(String address) {
+            return getBluetoothDevice(mContext, address).getBatteryLevel();
+        }
+    }
+
     // Helper class that adds copying and printing functionality to IInputDeviceBatteryState.
     private static class State extends IInputDeviceBatteryState {
 
@@ -792,11 +977,17 @@
 
     // Check if any value in an ArrayMap matches the predicate in an optimized way.
     private static <K, V> boolean anyOf(ArrayMap<K, V> arrayMap, Predicate<V> test) {
+        return findIf(arrayMap, test) != null;
+    }
+
+    // Find the first value in an ArrayMap that matches the predicate in an optimized way.
+    private static <K, V> V findIf(ArrayMap<K, V> arrayMap, Predicate<V> test) {
         for (int i = 0; i < arrayMap.size(); i++) {
-            if (test.test(arrayMap.valueAt(i))) {
-                return true;
+            final V value = arrayMap.valueAt(i);
+            if (test.test(value)) {
+                return value;
             }
         }
-        return false;
+        return null;
     }
 }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c20d880..81d782e 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,25 +25,13 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.content.res.TypedArray;
-import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
 import android.graphics.PointF;
 import android.hardware.SensorPrivacyManager;
@@ -66,7 +54,6 @@
 import android.hardware.lights.LightState;
 import android.media.AudioManager;
 import android.os.Binder;
-import android.os.Bundle;
 import android.os.CombinedVibration;
 import android.os.Environment;
 import android.os.Handler;
@@ -75,7 +62,6 @@
 import android.os.IVibratorStateListener;
 import android.os.InputEventInjectionResult;
 import android.os.InputEventInjectionSync;
-import android.os.LocaleList;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
@@ -112,19 +98,16 @@
 import android.view.SurfaceControl;
 import android.view.VerifiedInputEvent;
 import android.view.ViewConfiguration;
+import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
-import android.widget.Toast;
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
-import com.android.internal.util.XmlUtils;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
 import com.android.server.Watchdog;
@@ -132,7 +115,6 @@
 import com.android.server.policy.WindowManagerPolicy;
 
 import libcore.io.IoUtils;
-import libcore.io.Streams;
 
 import java.io.File;
 import java.io.FileDescriptor;
@@ -141,15 +123,11 @@
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.OptionalInt;
@@ -171,12 +149,9 @@
     private static final String VELOCITYTRACKER_STRATEGY_PROPERTY = "velocitytracker_strategy";
 
     private static final int MSG_DELIVER_INPUT_DEVICES_CHANGED = 1;
-    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
-    private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
-    private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
-    private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
-    private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
-    private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 7;
+    private static final int MSG_RELOAD_DEVICE_ALIASES = 2;
+    private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 3;
+    private static final int MSG_POINTER_DISPLAY_ID_CHANGED = 4;
 
     private static final int DEFAULT_VIBRATION_MAGNITUDE = 192;
     private static final AdditionalDisplayInputProperties
@@ -195,7 +170,6 @@
     private WindowManagerCallbacks mWindowManagerCallbacks;
     private WiredAccessoryCallbacks mWiredAccessoryCallbacks;
     private boolean mSystemReady;
-    private NotificationManager mNotificationManager;
 
     private final Object mTabletModeLock = new Object();
     // List of currently registered tablet mode changed listeners by process id
@@ -229,10 +203,6 @@
             new SparseArray<>();
     private final ArrayList<InputDevicesChangedListenerRecord>
             mTempInputDevicesChangedListenersToNotify = new ArrayList<>(); // handler thread only
-    private final ArrayList<InputDevice> mTempFullKeyboards =
-            new ArrayList<>(); // handler thread only
-    private boolean mKeyboardLayoutNotificationShown;
-    private Toast mSwitchedKeyboardLayoutToast;
 
     // State for vibrator tokens.
     private final Object mVibratorLock = new Object();
@@ -315,6 +285,9 @@
     @GuardedBy("mInputMonitors")
     final Map<IBinder, GestureMonitorSpyWindow> mInputMonitors = new HashMap<>();
 
+    // Manages Keyboard layouts for Physical keyboards
+    private final KeyboardLayoutManager mKeyboardLayoutManager;
+
     // Manages battery state for input devices.
     private final BatteryController mBatteryController;
 
@@ -430,6 +403,8 @@
         mContext = injector.getContext();
         mHandler = new InputManagerHandler(injector.getLooper());
         mNative = injector.getNativeService(this);
+        mKeyboardLayoutManager = new KeyboardLayoutManager(mContext, mNative, mDataStore,
+                injector.getLooper());
         mBatteryController = new BatteryController(mContext, mNative, injector.getLooper());
         mKeyboardBacklightController = new KeyboardBacklightController(mContext, mNative,
                 mDataStore, injector.getLooper());
@@ -518,8 +493,6 @@
         if (DEBUG) {
             Slog.d(TAG, "System ready.");
         }
-        mNotificationManager = (NotificationManager)mContext.getSystemService(
-                Context.NOTIFICATION_SERVICE);
 
         synchronized (mLidSwitchLock) {
             mSystemReady = true;
@@ -546,19 +519,7 @@
             setSensorPrivacy(Sensors.CAMERA, true);
         }
 
-        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
-        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
-        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
-        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
-        filter.addDataScheme("package");
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                updateKeyboardLayouts();
-            }
-        }, filter, null, mHandler);
-
-        filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
+        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_ALIAS_CHANGED);
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
@@ -567,23 +528,16 @@
         }, filter, null, mHandler);
 
         mHandler.sendEmptyMessage(MSG_RELOAD_DEVICE_ALIASES);
-        mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
 
         if (mWiredAccessoryCallbacks != null) {
             mWiredAccessoryCallbacks.systemReady();
         }
 
+        mKeyboardLayoutManager.systemRunning();
         mBatteryController.systemRunning();
         mKeyboardBacklightController.systemRunning();
     }
 
-    private void reloadKeyboardLayouts() {
-        if (DEBUG) {
-            Slog.d(TAG, "Reloading keyboard layouts.");
-        }
-        mNative.reloadKeyboardLayouts();
-    }
-
     private void reloadDeviceAliases() {
         if (DEBUG) {
             Slog.d(TAG, "Reloading device names.");
@@ -1044,9 +998,7 @@
     // Must be called on handler.
     private void deliverInputDevicesChanged(InputDevice[] oldInputDevices) {
         // Scan for changes.
-        int numFullKeyboardsAdded = 0;
         mTempInputDevicesChangedListenersToNotify.clear();
-        mTempFullKeyboards.clear();
         final int numListeners;
         final int[] deviceIdAndGeneration;
         synchronized (mInputDevicesLock) {
@@ -1071,15 +1023,6 @@
                     Log.d(TAG, "device " + inputDevice.getId() + " generation "
                             + inputDevice.getGeneration());
                 }
-
-                if (!inputDevice.isVirtual() && inputDevice.isFullKeyboard()) {
-                    if (!containsInputDeviceWithDescriptor(oldInputDevices,
-                            inputDevice.getDescriptor())) {
-                        mTempFullKeyboards.add(numFullKeyboardsAdded++, inputDevice);
-                    } else {
-                        mTempFullKeyboards.add(inputDevice);
-                    }
-                }
             }
         }
 
@@ -1089,119 +1032,6 @@
                     deviceIdAndGeneration);
         }
         mTempInputDevicesChangedListenersToNotify.clear();
-
-        // Check for missing keyboard layouts.
-        List<InputDevice> keyboardsMissingLayout = new ArrayList<>();
-        final int numFullKeyboards = mTempFullKeyboards.size();
-        synchronized (mDataStore) {
-            for (int i = 0; i < numFullKeyboards; i++) {
-                final InputDevice inputDevice = mTempFullKeyboards.get(i);
-                String layout =
-                    getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
-                if (layout == null) {
-                    layout = getDefaultKeyboardLayout(inputDevice);
-                    if (layout != null) {
-                        setCurrentKeyboardLayoutForInputDevice(
-                                inputDevice.getIdentifier(), layout);
-                    }
-                }
-                if (layout == null) {
-                    keyboardsMissingLayout.add(inputDevice);
-                }
-            }
-        }
-
-        if (mNotificationManager != null) {
-            if (!keyboardsMissingLayout.isEmpty()) {
-                if (keyboardsMissingLayout.size() > 1) {
-                    // We have more than one keyboard missing a layout, so drop the
-                    // user at the generic input methods page so they can pick which
-                    // one to set.
-                    showMissingKeyboardLayoutNotification(null);
-                } else {
-                    showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0));
-                }
-            } else if (mKeyboardLayoutNotificationShown) {
-                hideMissingKeyboardLayoutNotification();
-            }
-        }
-        mTempFullKeyboards.clear();
-    }
-
-    private String getDefaultKeyboardLayout(final InputDevice d) {
-        final Locale systemLocale = mContext.getResources().getConfiguration().locale;
-        // If our locale doesn't have a language for some reason, then we don't really have a
-        // reasonable default.
-        if (TextUtils.isEmpty(systemLocale.getLanguage())) {
-            return null;
-        }
-        final List<KeyboardLayout> layouts = new ArrayList<>();
-        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> {
-            // Only select a default when we know the layout is appropriate. For now, this
-            // means it's a custom layout for a specific keyboard.
-            if (layout.getVendorId() != d.getVendorId()
-                    || layout.getProductId() != d.getProductId()) {
-                return;
-            }
-            final LocaleList locales = layout.getLocales();
-            final int numLocales = locales.size();
-            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
-                if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
-                    layouts.add(layout);
-                    break;
-                }
-            }
-        });
-
-        if (layouts.isEmpty()) {
-            return null;
-        }
-
-        // First sort so that ones with higher priority are listed at the top
-        Collections.sort(layouts);
-        // Next we want to try to find an exact match of language, country and variant.
-        final int N = layouts.size();
-        for (int i = 0; i < N; i++) {
-            KeyboardLayout layout = layouts.get(i);
-            final LocaleList locales = layout.getLocales();
-            final int numLocales = locales.size();
-            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
-                final Locale locale = locales.get(localeIndex);
-                if (locale.getCountry().equals(systemLocale.getCountry())
-                        && locale.getVariant().equals(systemLocale.getVariant())) {
-                    return layout.getDescriptor();
-                }
-            }
-        }
-        // Then try an exact match of language and country
-        for (int i = 0; i < N; i++) {
-            KeyboardLayout layout = layouts.get(i);
-            final LocaleList locales = layout.getLocales();
-            final int numLocales = locales.size();
-            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
-                final Locale locale = locales.get(localeIndex);
-                if (locale.getCountry().equals(systemLocale.getCountry())) {
-                    return layout.getDescriptor();
-                }
-            }
-        }
-
-        // Give up and just use the highest priority layout with matching language
-        return layouts.get(0).getDescriptor();
-    }
-
-    private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
-        // Different languages are never compatible
-        if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
-            return false;
-        }
-        // If both the system and the keyboard layout have a country specifier, they must be equal.
-        if (!TextUtils.isEmpty(systemLocale.getCountry())
-                && !TextUtils.isEmpty(keyboardLocale.getCountry())
-                && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) {
-            return false;
-        }
-        return true;
     }
 
     @Override // Binder call & native callback
@@ -1302,446 +1132,88 @@
         }
     }
 
-    // Must be called on handler.
-    private void showMissingKeyboardLayoutNotification(InputDevice device) {
-        if (!mKeyboardLayoutNotificationShown) {
-            final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
-            if (device != null) {
-                intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
-            }
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
-                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-            final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
-                    intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
-
-            Resources r = mContext.getResources();
-            Notification notification =
-                    new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
-                            .setContentTitle(r.getString(
-                                    R.string.select_keyboard_layout_notification_title))
-                            .setContentText(r.getString(
-                                    R.string.select_keyboard_layout_notification_message))
-                            .setContentIntent(keyboardLayoutIntent)
-                            .setSmallIcon(R.drawable.ic_settings_language)
-                            .setColor(mContext.getColor(
-                                    com.android.internal.R.color.system_notification_accent_color))
-                            .build();
-            mNotificationManager.notifyAsUser(null,
-                    SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
-                    notification, UserHandle.ALL);
-            mKeyboardLayoutNotificationShown = true;
-        }
-    }
-
-    // Must be called on handler.
-    private void hideMissingKeyboardLayoutNotification() {
-        if (mKeyboardLayoutNotificationShown) {
-            mKeyboardLayoutNotificationShown = false;
-            mNotificationManager.cancelAsUser(null,
-                    SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
-                    UserHandle.ALL);
-        }
-    }
-
-    // Must be called on handler.
-    private void updateKeyboardLayouts() {
-        // Scan all input devices state for keyboard layouts that have been uninstalled.
-        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
-        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) ->
-                availableKeyboardLayouts.add(layout.getDescriptor()));
-        synchronized (mDataStore) {
-            try {
-                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
-            } finally {
-                mDataStore.saveIfNeeded();
-            }
-        }
-
-        // Reload keyboard layouts.
-        reloadKeyboardLayouts();
-    }
-
-    private static boolean containsInputDeviceWithDescriptor(InputDevice[] inputDevices,
-            String descriptor) {
-        final int numDevices = inputDevices.length;
-        for (int i = 0; i < numDevices; i++) {
-            final InputDevice inputDevice = inputDevices[i];
-            if (inputDevice.getDescriptor().equals(descriptor)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     @Override // Binder call
     public KeyboardLayout[] getKeyboardLayouts() {
-        final ArrayList<KeyboardLayout> list = new ArrayList<>();
-        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
-        return list.toArray(new KeyboardLayout[list.size()]);
+        return mKeyboardLayoutManager.getKeyboardLayouts();
     }
 
     @Override // Binder call
     public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
             final InputDeviceIdentifier identifier) {
-        final String[] enabledLayoutDescriptors =
-                getEnabledKeyboardLayoutsForInputDevice(identifier);
-        final ArrayList<KeyboardLayout> enabledLayouts =
-                new ArrayList<>(enabledLayoutDescriptors.length);
-        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
-        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
-            boolean mHasSeenDeviceSpecificLayout;
-
-            @Override
-            public void visitKeyboardLayout(Resources resources,
-                    int keyboardLayoutResId, KeyboardLayout layout) {
-                // First check if it's enabled. If the keyboard layout is enabled then we always
-                // want to return it as a possible layout for the device.
-                for (String s : enabledLayoutDescriptors) {
-                    if (s != null && s.equals(layout.getDescriptor())) {
-                        enabledLayouts.add(layout);
-                        return;
-                    }
-                }
-                // Next find any potential layouts that aren't yet enabled for the device. For
-                // devices that have special layouts we assume there's a reason that the generic
-                // layouts don't work for them so we don't want to return them since it's likely
-                // to result in a poor user experience.
-                if (layout.getVendorId() == identifier.getVendorId()
-                        && layout.getProductId() == identifier.getProductId()) {
-                    if (!mHasSeenDeviceSpecificLayout) {
-                        mHasSeenDeviceSpecificLayout = true;
-                        potentialLayouts.clear();
-                    }
-                    potentialLayouts.add(layout);
-                } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
-                        && !mHasSeenDeviceSpecificLayout) {
-                    potentialLayouts.add(layout);
-                }
-            }
-        });
-        final int enabledLayoutSize = enabledLayouts.size();
-        final int potentialLayoutSize = potentialLayouts.size();
-        KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize];
-        enabledLayouts.toArray(layouts);
-        for (int i = 0; i < potentialLayoutSize; i++) {
-            layouts[enabledLayoutSize + i] = potentialLayouts.get(i);
-        }
-        return layouts;
+        return mKeyboardLayoutManager.getKeyboardLayoutsForInputDevice(identifier);
     }
 
     @Override // Binder call
     public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
-        Objects.requireNonNull(keyboardLayoutDescriptor,
-                "keyboardLayoutDescriptor must not be null");
-
-        final KeyboardLayout[] result = new KeyboardLayout[1];
-        visitKeyboardLayout(keyboardLayoutDescriptor,
-                (resources, keyboardLayoutResId, layout) -> result[0] = layout);
-        if (result[0] == null) {
-            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
-                    + keyboardLayoutDescriptor + "'.");
-        }
-        return result[0];
-    }
-
-    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
-        final PackageManager pm = mContext.getPackageManager();
-        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
-        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
-                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
-            final ActivityInfo activityInfo = resolveInfo.activityInfo;
-            final int priority = resolveInfo.priority;
-            visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
-        }
-    }
-
-    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
-            KeyboardLayoutVisitor visitor) {
-        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
-        if (d != null) {
-            final PackageManager pm = mContext.getPackageManager();
-            try {
-                ActivityInfo receiver = pm.getReceiverInfo(
-                        new ComponentName(d.packageName, d.receiverName),
-                        PackageManager.GET_META_DATA
-                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
-                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
-            } catch (NameNotFoundException ignored) {
-            }
-        }
-    }
-
-    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
-            String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
-        Bundle metaData = receiver.metaData;
-        if (metaData == null) {
-            return;
-        }
-
-        int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
-        if (configResId == 0) {
-            Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
-                    + "' on receiver " + receiver.packageName + "/" + receiver.name);
-            return;
-        }
-
-        CharSequence receiverLabel = receiver.loadLabel(pm);
-        String collection = receiverLabel != null ? receiverLabel.toString() : "";
-        int priority;
-        if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
-            priority = requestedPriority;
-        } else {
-            priority = 0;
-        }
-
-        try {
-            Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
-            try (XmlResourceParser parser = resources.getXml(configResId)) {
-                XmlUtils.beginDocument(parser, "keyboard-layouts");
-
-                while (true) {
-                    XmlUtils.nextElement(parser);
-                    String element = parser.getName();
-                    if (element == null) {
-                        break;
-                    }
-                    if (element.equals("keyboard-layout")) {
-                        TypedArray a = resources.obtainAttributes(
-                                parser, R.styleable.KeyboardLayout);
-                        try {
-                            String name = a.getString(
-                                    R.styleable.KeyboardLayout_name);
-                            String label = a.getString(
-                                    R.styleable.KeyboardLayout_label);
-                            int keyboardLayoutResId = a.getResourceId(
-                                    R.styleable.KeyboardLayout_keyboardLayout,
-                                    0);
-                            String languageTags = a.getString(
-                                    R.styleable.KeyboardLayout_locale);
-                            LocaleList locales = getLocalesFromLanguageTags(languageTags);
-                            int vid = a.getInt(
-                                    R.styleable.KeyboardLayout_vendorId, -1);
-                            int pid = a.getInt(
-                                    R.styleable.KeyboardLayout_productId, -1);
-
-                            if (name == null || label == null || keyboardLayoutResId == 0) {
-                                Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
-                                        + "attributes in keyboard layout "
-                                        + "resource from receiver "
-                                        + receiver.packageName + "/" + receiver.name);
-                            } else {
-                                String descriptor = KeyboardLayoutDescriptor.format(
-                                        receiver.packageName, receiver.name, name);
-                                if (keyboardName == null || name.equals(keyboardName)) {
-                                    KeyboardLayout layout = new KeyboardLayout(
-                                            descriptor, label, collection, priority,
-                                            locales, vid, pid);
-                                    visitor.visitKeyboardLayout(
-                                            resources, keyboardLayoutResId, layout);
-                                }
-                            }
-                        } finally {
-                            a.recycle();
-                        }
-                    } else {
-                        Slog.w(TAG, "Skipping unrecognized element '" + element
-                                + "' in keyboard layout resource from receiver "
-                                + receiver.packageName + "/" + receiver.name);
-                    }
-                }
-            }
-        } catch (Exception ex) {
-            Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
-                    + receiver.packageName + "/" + receiver.name, ex);
-        }
-    }
-
-    @NonNull
-    private static LocaleList getLocalesFromLanguageTags(String languageTags) {
-        if (TextUtils.isEmpty(languageTags)) {
-            return LocaleList.getEmptyLocaleList();
-        }
-        return LocaleList.forLanguageTags(languageTags.replace('|', ','));
-    }
-
-    /**
-     * Builds a layout descriptor for the vendor/product. This returns the
-     * descriptor for ids that aren't useful (such as the default 0, 0).
-     */
-    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
-        Objects.requireNonNull(identifier, "identifier must not be null");
-        Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
-
-        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
-            return identifier.getDescriptor();
-        }
-        return "vendor:" + identifier.getVendorId() + ",product:" + identifier.getProductId();
+        return mKeyboardLayoutManager.getKeyboardLayout(keyboardLayoutDescriptor);
     }
 
     @Override // Binder call
     public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
-
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            String layout;
-            // try loading it using the layout descriptor if we have it
-            layout = mDataStore.getCurrentKeyboardLayout(key);
-            if (layout == null && !key.equals(identifier.getDescriptor())) {
-                // if it doesn't exist fall back to the device descriptor
-                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
-            }
-            if (DEBUG) {
-                Slog.d(TAG, "getCurrentKeyboardLayoutForInputDevice() "
-                        + identifier.toString() + ": " + layout);
-            }
-            return layout;
-        }
+        return mKeyboardLayoutManager.getCurrentKeyboardLayoutForInputDevice(identifier);
     }
 
+    @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
     @Override // Binder call
     public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                "setCurrentKeyboardLayoutForInputDevice()")) {
-            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
-        }
-
-        Objects.requireNonNull(keyboardLayoutDescriptor,
-                "keyboardLayoutDescriptor must not be null");
-
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            try {
-                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "setCurrentKeyboardLayoutForInputDevice() " + identifier
-                                + " key: " + key
-                                + " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
-                    }
-                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
-                }
-            } finally {
-                mDataStore.saveIfNeeded();
-            }
-        }
+        super.setCurrentKeyboardLayoutForInputDevice_enforcePermission();
+        mKeyboardLayoutManager.setCurrentKeyboardLayoutForInputDevice(identifier,
+                keyboardLayoutDescriptor);
     }
 
     @Override // Binder call
     public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            String[] layouts = mDataStore.getKeyboardLayouts(key);
-            if ((layouts == null || layouts.length == 0)
-                    && !key.equals(identifier.getDescriptor())) {
-                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
-            }
-            return layouts;
-        }
+        return mKeyboardLayoutManager.getEnabledKeyboardLayoutsForInputDevice(identifier);
     }
 
+    @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
     @Override // Binder call
     public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                "addKeyboardLayoutForInputDevice()")) {
-            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
-        }
-        Objects.requireNonNull(keyboardLayoutDescriptor,
-                "keyboardLayoutDescriptor must not be null");
-
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            try {
-                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
-                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
-                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
-                }
-                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
-                        && !Objects.equals(oldLayout,
-                                mDataStore.getCurrentKeyboardLayout(key))) {
-                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
-                }
-            } finally {
-                mDataStore.saveIfNeeded();
-            }
-        }
+        super.addKeyboardLayoutForInputDevice_enforcePermission();
+        mKeyboardLayoutManager.addKeyboardLayoutForInputDevice(identifier,
+                keyboardLayoutDescriptor);
     }
 
+    @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
     @Override // Binder call
     public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
             String keyboardLayoutDescriptor) {
-        if (!checkCallingPermission(android.Manifest.permission.SET_KEYBOARD_LAYOUT,
-                "removeKeyboardLayoutForInputDevice()")) {
-            throw new SecurityException("Requires SET_KEYBOARD_LAYOUT permission");
-        }
-        Objects.requireNonNull(keyboardLayoutDescriptor,
-                "keyboardLayoutDescriptor must not be null");
-
-        String key = getLayoutDescriptor(identifier);
-        synchronized (mDataStore) {
-            try {
-                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
-                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
-                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
-                }
-                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
-                if (!key.equals(identifier.getDescriptor())) {
-                    // We need to remove from both places to ensure it is gone
-                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
-                            keyboardLayoutDescriptor);
-                }
-                if (removed && !Objects.equals(oldLayout,
-                                mDataStore.getCurrentKeyboardLayout(key))) {
-                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
-                }
-            } finally {
-                mDataStore.saveIfNeeded();
-            }
-        }
+        super.removeKeyboardLayoutForInputDevice_enforcePermission();
+        mKeyboardLayoutManager.removeKeyboardLayoutForInputDevice(identifier,
+                keyboardLayoutDescriptor);
     }
 
+    @Override // Binder call
+    public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        return mKeyboardLayoutManager.getKeyboardLayoutForInputDevice(identifier, userId,
+                imeInfo, imeSubtype);
+    }
+
+    @EnforcePermission(Manifest.permission.SET_KEYBOARD_LAYOUT)
+    @Override // Binder call
+    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
+        super.setKeyboardLayoutForInputDevice_enforcePermission();
+        mKeyboardLayoutManager.setKeyboardLayoutForInputDevice(identifier, userId, imeInfo,
+                imeSubtype, keyboardLayoutDescriptor);
+    }
+
+    @Override // Binder call
+    public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        return mKeyboardLayoutManager.getKeyboardLayoutListForInputDevice(identifier, userId,
+                imeInfo, imeSubtype);
+    }
+
+
     public void switchKeyboardLayout(int deviceId, int direction) {
-        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
-    }
-
-    // Must be called on handler.
-    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
-        final InputDevice device = getInputDevice(deviceId);
-        if (device != null) {
-            final boolean changed;
-            final String keyboardLayoutDescriptor;
-
-            String key = getLayoutDescriptor(device.getIdentifier());
-            synchronized (mDataStore) {
-                try {
-                    changed = mDataStore.switchKeyboardLayout(key, direction);
-                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
-                            key);
-                } finally {
-                    mDataStore.saveIfNeeded();
-                }
-            }
-
-            if (changed) {
-                if (mSwitchedKeyboardLayoutToast != null) {
-                    mSwitchedKeyboardLayoutToast.cancel();
-                    mSwitchedKeyboardLayoutToast = null;
-                }
-                if (keyboardLayoutDescriptor != null) {
-                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
-                    if (keyboardLayout != null) {
-                        mSwitchedKeyboardLayoutToast = Toast.makeText(
-                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
-                        mSwitchedKeyboardLayoutToast.show();
-                    }
-                }
-
-                reloadKeyboardLayouts();
-            }
-        }
+        mKeyboardLayoutManager.switchKeyboardLayout(deviceId, direction);
     }
 
     public void setFocusedApplication(int displayId, InputApplicationHandle application) {
@@ -2682,7 +2154,13 @@
     public String getInputDeviceBluetoothAddress(int deviceId) {
         super.getInputDeviceBluetoothAddress_enforcePermission();
 
-        return mNative.getBluetoothAddress(deviceId);
+        final String address = mNative.getBluetoothAddress(deviceId);
+        if (address == null) return null;
+        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
+            throw new IllegalStateException("The Bluetooth address of input device " + deviceId
+                    + " should not be invalid: address=" + address);
+        }
+        return address;
     }
 
     @EnforcePermission(Manifest.permission.MONITOR_INPUT)
@@ -2770,6 +2248,11 @@
             if (mOverriddenPointerDisplayId != Display.INVALID_DISPLAY) {
                 pw.println("mOverriddenPointerDisplayId: " + mOverriddenPointerDisplayId);
             }
+
+            pw.println("mAcknowledgedPointerDisplayId=" + mAcknowledgedPointerDisplayId);
+            pw.println("mRequestedPointerDisplayId=" + mRequestedPointerDisplayId);
+            pw.println("mPointerIconType=" + PointerIcon.typeToString(mPointerIconType));
+            pw.println("mPointerIcon=" + mPointerIcon);
         }
     }
     private boolean checkCallingPermission(String permission, String func) {
@@ -3252,28 +2735,7 @@
         if (!mSystemReady) {
             return null;
         }
-
-        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
-        if (keyboardLayoutDescriptor == null) {
-            return null;
-        }
-
-        final String[] result = new String[2];
-        visitKeyboardLayout(keyboardLayoutDescriptor,
-                (resources, keyboardLayoutResId, layout) -> {
-                    try (InputStreamReader stream = new InputStreamReader(
-                            resources.openRawResource(keyboardLayoutResId))) {
-                        result[0] = layout.getDescriptor();
-                        result[1] = Streams.readFully(stream);
-                    } catch (IOException | NotFoundException ignored) {
-                    }
-                });
-        if (result[0] == null) {
-            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
-                    + keyboardLayoutDescriptor + "'.");
-            return null;
-        }
-        return result;
+        return mKeyboardLayoutManager.getKeyboardLayoutOverlay(identifier);
     }
 
     // Native callback.
@@ -3471,15 +2933,6 @@
                 case MSG_DELIVER_INPUT_DEVICES_CHANGED:
                     deliverInputDevicesChanged((InputDevice[])msg.obj);
                     break;
-                case MSG_SWITCH_KEYBOARD_LAYOUT:
-                    handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
-                    break;
-                case MSG_RELOAD_KEYBOARD_LAYOUTS:
-                    reloadKeyboardLayouts();
-                    break;
-                case MSG_UPDATE_KEYBOARD_LAYOUTS:
-                    updateKeyboardLayouts();
-                    break;
                 case MSG_RELOAD_DEVICE_ALIASES:
                     reloadDeviceAliases();
                     break;
@@ -3548,39 +3001,6 @@
         }
     }
 
-    private static final class KeyboardLayoutDescriptor {
-        public String packageName;
-        public String receiverName;
-        public String keyboardLayoutName;
-
-        public static String format(String packageName,
-                String receiverName, String keyboardName) {
-            return packageName + "/" + receiverName + "/" + keyboardName;
-        }
-
-        public static KeyboardLayoutDescriptor parse(String descriptor) {
-            int pos = descriptor.indexOf('/');
-            if (pos < 0 || pos + 1 == descriptor.length()) {
-                return null;
-            }
-            int pos2 = descriptor.indexOf('/', pos + 1);
-            if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
-                return null;
-            }
-
-            KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
-            result.packageName = descriptor.substring(0, pos);
-            result.receiverName = descriptor.substring(pos + 1, pos2);
-            result.keyboardLayoutName = descriptor.substring(pos2 + 1);
-            return result;
-        }
-    }
-
-    private interface KeyboardLayoutVisitor {
-        void visitKeyboardLayout(Resources resources,
-                int keyboardLayoutResId, KeyboardLayout layout);
-    }
-
     private final class InputDevicesChangedListenerRecord implements DeathRecipient {
         private final int mPid;
         private final IInputDevicesChangedListener mListener;
diff --git a/services/core/java/com/android/server/input/KeyboardLayoutManager.java b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
new file mode 100644
index 0000000..85d6197
--- /dev/null
+++ b/services/core/java/com/android/server/input/KeyboardLayoutManager.java
@@ -0,0 +1,776 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.input;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.hardware.input.InputDeviceIdentifier;
+import android.hardware.input.InputManager;
+import android.hardware.input.KeyboardLayout;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.LocaleList;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Slog;
+import android.view.InputDevice;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+import android.widget.Toast;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.messages.nano.SystemMessageProto;
+import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.XmlUtils;
+
+import libcore.io.Streams;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.stream.Stream;
+
+/**
+ * A component of {@link InputManagerService} responsible for managing Physical Keyboard layouts.
+ *
+ * @hide
+ */
+final class KeyboardLayoutManager implements InputManager.InputDeviceListener {
+
+    private static final String TAG = "KeyboardLayoutManager";
+
+    // To enable these logs, run: 'adb shell setprop log.tag.KeyboardLayoutManager DEBUG'
+    // (requires restart)
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+    private static final int MSG_UPDATE_EXISTING_DEVICES = 1;
+    private static final int MSG_SWITCH_KEYBOARD_LAYOUT = 2;
+    private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
+    private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
+
+    private final Context mContext;
+    private final NativeInputManagerService mNative;
+    // The PersistentDataStore should be locked before use.
+    @GuardedBy("mDataStore")
+    private final PersistentDataStore mDataStore;
+    private final Handler mHandler;
+    private final List<InputDevice> mKeyboardsWithMissingLayouts = new ArrayList<>();
+    private boolean mKeyboardLayoutNotificationShown = false;
+    private Toast mSwitchedKeyboardLayoutToast;
+
+    KeyboardLayoutManager(Context context, NativeInputManagerService nativeService,
+            PersistentDataStore dataStore, Looper looper) {
+        mContext = context;
+        mNative = nativeService;
+        mDataStore = dataStore;
+        mHandler = new Handler(looper, this::handleMessage, true /* async */);
+    }
+
+    public void systemRunning() {
+        // Listen to new Package installations to fetch new Keyboard layouts
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                updateKeyboardLayouts();
+            }
+        }, filter, null, mHandler);
+
+        mHandler.sendEmptyMessage(MSG_UPDATE_KEYBOARD_LAYOUTS);
+
+        // Listen to new InputDevice changes
+        InputManager inputManager = Objects.requireNonNull(
+                mContext.getSystemService(InputManager.class));
+        inputManager.registerInputDeviceListener(this, mHandler);
+
+        Message msg = Message.obtain(mHandler, MSG_UPDATE_EXISTING_DEVICES,
+                inputManager.getInputDeviceIds());
+        mHandler.sendMessage(msg);
+    }
+
+    @Override
+    public void onInputDeviceAdded(int deviceId) {
+        onInputDeviceChanged(deviceId);
+    }
+
+    @Override
+    public void onInputDeviceRemoved(int deviceId) {
+        mKeyboardsWithMissingLayouts.removeIf(device -> device.getId() == deviceId);
+        maybeUpdateNotification();
+    }
+
+    @Override
+    public void onInputDeviceChanged(int deviceId) {
+        final InputDevice inputDevice = getInputDevice(deviceId);
+        if (inputDevice == null) {
+            return;
+        }
+        synchronized (mDataStore) {
+            String layout = getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier());
+            if (layout == null) {
+                layout = getDefaultKeyboardLayout(inputDevice);
+                if (layout != null) {
+                    setCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier(), layout);
+                } else {
+                    mKeyboardsWithMissingLayouts.add(inputDevice);
+                }
+            }
+            maybeUpdateNotification();
+        }
+    }
+
+    private String getDefaultKeyboardLayout(final InputDevice inputDevice) {
+        final Locale systemLocale = mContext.getResources().getConfiguration().locale;
+        // If our locale doesn't have a language for some reason, then we don't really have a
+        // reasonable default.
+        if (TextUtils.isEmpty(systemLocale.getLanguage())) {
+            return null;
+        }
+        final List<KeyboardLayout> layouts = new ArrayList<>();
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> {
+            // Only select a default when we know the layout is appropriate. For now, this
+            // means it's a custom layout for a specific keyboard.
+            if (layout.getVendorId() != inputDevice.getVendorId()
+                    || layout.getProductId() != inputDevice.getProductId()) {
+                return;
+            }
+            final LocaleList locales = layout.getLocales();
+            for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale != null && isCompatibleLocale(systemLocale, locale)) {
+                    layouts.add(layout);
+                    break;
+                }
+            }
+        });
+
+        if (layouts.isEmpty()) {
+            return null;
+        }
+
+        // First sort so that ones with higher priority are listed at the top
+        Collections.sort(layouts);
+        // Next we want to try to find an exact match of language, country and variant.
+        for (KeyboardLayout layout : layouts) {
+            final LocaleList locales = layout.getLocales();
+            for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale != null && locale.getCountry().equals(systemLocale.getCountry())
+                        && locale.getVariant().equals(systemLocale.getVariant())) {
+                    return layout.getDescriptor();
+                }
+            }
+        }
+        // Then try an exact match of language and country
+        for (KeyboardLayout layout : layouts) {
+            final LocaleList locales = layout.getLocales();
+            for (int localeIndex = 0; localeIndex < locales.size(); ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale != null && locale.getCountry().equals(systemLocale.getCountry())) {
+                    return layout.getDescriptor();
+                }
+            }
+        }
+
+        // Give up and just use the highest priority layout with matching language
+        return layouts.get(0).getDescriptor();
+    }
+
+    private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) {
+        // Different languages are never compatible
+        if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) {
+            return false;
+        }
+        // If both the system and the keyboard layout have a country specifier, they must be equal.
+        return TextUtils.isEmpty(systemLocale.getCountry())
+                || TextUtils.isEmpty(keyboardLocale.getCountry())
+                || systemLocale.getCountry().equals(keyboardLocale.getCountry());
+    }
+
+    private void updateKeyboardLayouts() {
+        // Scan all input devices state for keyboard layouts that have been uninstalled.
+        final HashSet<String> availableKeyboardLayouts = new HashSet<String>();
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) ->
+                availableKeyboardLayouts.add(layout.getDescriptor()));
+        synchronized (mDataStore) {
+            try {
+                mDataStore.removeUninstalledKeyboardLayouts(availableKeyboardLayouts);
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+
+        // Reload keyboard layouts.
+        reloadKeyboardLayouts();
+    }
+
+    public KeyboardLayout[] getKeyboardLayouts() {
+        final ArrayList<KeyboardLayout> list = new ArrayList<>();
+        visitAllKeyboardLayouts((resources, keyboardLayoutResId, layout) -> list.add(layout));
+        return list.toArray(new KeyboardLayout[0]);
+    }
+
+    public KeyboardLayout[] getKeyboardLayoutsForInputDevice(
+            final InputDeviceIdentifier identifier) {
+        final String[] enabledLayoutDescriptors =
+                getEnabledKeyboardLayoutsForInputDevice(identifier);
+        final ArrayList<KeyboardLayout> enabledLayouts =
+                new ArrayList<>(enabledLayoutDescriptors.length);
+        final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<>();
+        visitAllKeyboardLayouts(new KeyboardLayoutVisitor() {
+            boolean mHasSeenDeviceSpecificLayout;
+
+            @Override
+            public void visitKeyboardLayout(Resources resources,
+                    int keyboardLayoutResId, KeyboardLayout layout) {
+                // First check if it's enabled. If the keyboard layout is enabled then we always
+                // want to return it as a possible layout for the device.
+                for (String s : enabledLayoutDescriptors) {
+                    if (s != null && s.equals(layout.getDescriptor())) {
+                        enabledLayouts.add(layout);
+                        return;
+                    }
+                }
+                // Next find any potential layouts that aren't yet enabled for the device. For
+                // devices that have special layouts we assume there's a reason that the generic
+                // layouts don't work for them so we don't want to return them since it's likely
+                // to result in a poor user experience.
+                if (layout.getVendorId() == identifier.getVendorId()
+                        && layout.getProductId() == identifier.getProductId()) {
+                    if (!mHasSeenDeviceSpecificLayout) {
+                        mHasSeenDeviceSpecificLayout = true;
+                        potentialLayouts.clear();
+                    }
+                    potentialLayouts.add(layout);
+                } else if (layout.getVendorId() == -1 && layout.getProductId() == -1
+                        && !mHasSeenDeviceSpecificLayout) {
+                    potentialLayouts.add(layout);
+                }
+            }
+        });
+        return Stream.concat(enabledLayouts.stream(), potentialLayouts.stream()).toArray(
+                KeyboardLayout[]::new);
+    }
+
+    public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) {
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
+
+        final KeyboardLayout[] result = new KeyboardLayout[1];
+        visitKeyboardLayout(keyboardLayoutDescriptor,
+                (resources, keyboardLayoutResId, layout) -> result[0] = layout);
+        if (result[0] == null) {
+            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
+                    + keyboardLayoutDescriptor + "'.");
+        }
+        return result[0];
+    }
+
+    private void visitAllKeyboardLayouts(KeyboardLayoutVisitor visitor) {
+        final PackageManager pm = mContext.getPackageManager();
+        Intent intent = new Intent(InputManager.ACTION_QUERY_KEYBOARD_LAYOUTS);
+        for (ResolveInfo resolveInfo : pm.queryBroadcastReceivers(intent,
+                PackageManager.GET_META_DATA | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE)) {
+            final ActivityInfo activityInfo = resolveInfo.activityInfo;
+            final int priority = resolveInfo.priority;
+            visitKeyboardLayoutsInPackage(pm, activityInfo, null, priority, visitor);
+        }
+    }
+
+    private void visitKeyboardLayout(String keyboardLayoutDescriptor,
+            KeyboardLayoutVisitor visitor) {
+        KeyboardLayoutDescriptor d = KeyboardLayoutDescriptor.parse(keyboardLayoutDescriptor);
+        if (d != null) {
+            final PackageManager pm = mContext.getPackageManager();
+            try {
+                ActivityInfo receiver = pm.getReceiverInfo(
+                        new ComponentName(d.packageName, d.receiverName),
+                        PackageManager.GET_META_DATA
+                                | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE);
+                visitKeyboardLayoutsInPackage(pm, receiver, d.keyboardLayoutName, 0, visitor);
+            } catch (PackageManager.NameNotFoundException ignored) {
+            }
+        }
+    }
+
+    private void visitKeyboardLayoutsInPackage(PackageManager pm, ActivityInfo receiver,
+            String keyboardName, int requestedPriority, KeyboardLayoutVisitor visitor) {
+        Bundle metaData = receiver.metaData;
+        if (metaData == null) {
+            return;
+        }
+
+        int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS);
+        if (configResId == 0) {
+            Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS
+                    + "' on receiver " + receiver.packageName + "/" + receiver.name);
+            return;
+        }
+
+        CharSequence receiverLabel = receiver.loadLabel(pm);
+        String collection = receiverLabel != null ? receiverLabel.toString() : "";
+        int priority;
+        if ((receiver.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+            priority = requestedPriority;
+        } else {
+            priority = 0;
+        }
+
+        try {
+            Resources resources = pm.getResourcesForApplication(receiver.applicationInfo);
+            try (XmlResourceParser parser = resources.getXml(configResId)) {
+                XmlUtils.beginDocument(parser, "keyboard-layouts");
+
+                while (true) {
+                    XmlUtils.nextElement(parser);
+                    String element = parser.getName();
+                    if (element == null) {
+                        break;
+                    }
+                    if (element.equals("keyboard-layout")) {
+                        TypedArray a = resources.obtainAttributes(
+                                parser, R.styleable.KeyboardLayout);
+                        try {
+                            String name = a.getString(
+                                    R.styleable.KeyboardLayout_name);
+                            String label = a.getString(
+                                    R.styleable.KeyboardLayout_label);
+                            int keyboardLayoutResId = a.getResourceId(
+                                    R.styleable.KeyboardLayout_keyboardLayout,
+                                    0);
+                            String languageTags = a.getString(
+                                    R.styleable.KeyboardLayout_locale);
+                            LocaleList locales = getLocalesFromLanguageTags(languageTags);
+                            int vid = a.getInt(
+                                    R.styleable.KeyboardLayout_vendorId, -1);
+                            int pid = a.getInt(
+                                    R.styleable.KeyboardLayout_productId, -1);
+
+                            if (name == null || label == null || keyboardLayoutResId == 0) {
+                                Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' "
+                                        + "attributes in keyboard layout "
+                                        + "resource from receiver "
+                                        + receiver.packageName + "/" + receiver.name);
+                            } else {
+                                String descriptor = KeyboardLayoutDescriptor.format(
+                                        receiver.packageName, receiver.name, name);
+                                if (keyboardName == null || name.equals(keyboardName)) {
+                                    KeyboardLayout layout = new KeyboardLayout(
+                                            descriptor, label, collection, priority,
+                                            locales, vid, pid);
+                                    visitor.visitKeyboardLayout(
+                                            resources, keyboardLayoutResId, layout);
+                                }
+                            }
+                        } finally {
+                            a.recycle();
+                        }
+                    } else {
+                        Slog.w(TAG, "Skipping unrecognized element '" + element
+                                + "' in keyboard layout resource from receiver "
+                                + receiver.packageName + "/" + receiver.name);
+                    }
+                }
+            }
+        } catch (Exception ex) {
+            Slog.w(TAG, "Could not parse keyboard layout resource from receiver "
+                    + receiver.packageName + "/" + receiver.name, ex);
+        }
+    }
+
+    @NonNull
+    private static LocaleList getLocalesFromLanguageTags(String languageTags) {
+        if (TextUtils.isEmpty(languageTags)) {
+            return LocaleList.getEmptyLocaleList();
+        }
+        return LocaleList.forLanguageTags(languageTags.replace('|', ','));
+    }
+
+    /**
+     * Builds a layout descriptor for the vendor/product. This returns the
+     * descriptor for ids that aren't useful (such as the default 0, 0).
+     */
+    private String getLayoutDescriptor(InputDeviceIdentifier identifier) {
+        Objects.requireNonNull(identifier, "identifier must not be null");
+        Objects.requireNonNull(identifier.getDescriptor(), "descriptor must not be null");
+
+        if (identifier.getVendorId() == 0 && identifier.getProductId() == 0) {
+            return identifier.getDescriptor();
+        }
+        return "vendor:" + identifier.getVendorId() + ",product:" + identifier.getProductId();
+    }
+
+    public String getCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier) {
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            String layout;
+            // try loading it using the layout descriptor if we have it
+            layout = mDataStore.getCurrentKeyboardLayout(key);
+            if (layout == null && !key.equals(identifier.getDescriptor())) {
+                // if it doesn't exist fall back to the device descriptor
+                layout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+            }
+            if (DEBUG) {
+                Slog.d(TAG, "getCurrentKeyboardLayoutForInputDevice() "
+                        + identifier.toString() + ": " + layout);
+            }
+            return layout;
+        }
+    }
+
+    public void setCurrentKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            String keyboardLayoutDescriptor) {
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
+
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            try {
+                if (mDataStore.setCurrentKeyboardLayout(key, keyboardLayoutDescriptor)) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "setCurrentKeyboardLayoutForInputDevice() " + identifier
+                                + " key: " + key
+                                + " keyboardLayoutDescriptor: " + keyboardLayoutDescriptor);
+                    }
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+    }
+
+    public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) {
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            String[] layouts = mDataStore.getKeyboardLayouts(key);
+            if ((layouts == null || layouts.length == 0)
+                    && !key.equals(identifier.getDescriptor())) {
+                layouts = mDataStore.getKeyboardLayouts(identifier.getDescriptor());
+            }
+            return layouts;
+        }
+    }
+
+    public void addKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            String keyboardLayoutDescriptor) {
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
+
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            try {
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
+                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
+                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+                }
+                if (mDataStore.addKeyboardLayout(key, keyboardLayoutDescriptor)
+                        && !Objects.equals(oldLayout,
+                        mDataStore.getCurrentKeyboardLayout(key))) {
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+    }
+
+    public void removeKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            String keyboardLayoutDescriptor) {
+        Objects.requireNonNull(keyboardLayoutDescriptor,
+                "keyboardLayoutDescriptor must not be null");
+
+        String key = getLayoutDescriptor(identifier);
+        synchronized (mDataStore) {
+            try {
+                String oldLayout = mDataStore.getCurrentKeyboardLayout(key);
+                if (oldLayout == null && !key.equals(identifier.getDescriptor())) {
+                    oldLayout = mDataStore.getCurrentKeyboardLayout(identifier.getDescriptor());
+                }
+                boolean removed = mDataStore.removeKeyboardLayout(key, keyboardLayoutDescriptor);
+                if (!key.equals(identifier.getDescriptor())) {
+                    // We need to remove from both places to ensure it is gone
+                    removed |= mDataStore.removeKeyboardLayout(identifier.getDescriptor(),
+                            keyboardLayoutDescriptor);
+                }
+                if (removed && !Objects.equals(oldLayout,
+                        mDataStore.getCurrentKeyboardLayout(key))) {
+                    mHandler.sendEmptyMessage(MSG_RELOAD_KEYBOARD_LAYOUTS);
+                }
+            } finally {
+                mDataStore.saveIfNeeded();
+            }
+        }
+    }
+
+    public String getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        // TODO(b/259530132): Implement the new keyboard layout API: Returning non-IME specific
+        //  layout for now.
+        return getCurrentKeyboardLayoutForInputDevice(identifier);
+    }
+
+    public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype, String keyboardLayoutDescriptor) {
+        // TODO(b/259530132): Implement the new keyboard layout API: setting non-IME specific
+        //  layout for now.
+        setCurrentKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
+    }
+
+    public String[] getKeyboardLayoutListForInputDevice(InputDeviceIdentifier identifier,
+            @UserIdInt int userId, @NonNull InputMethodInfo imeInfo,
+            @NonNull InputMethodSubtype imeSubtype) {
+        // TODO(b/259530132): Implement the new keyboard layout API: Returning list of all
+        //  layouts for now.
+        KeyboardLayout[] allLayouts = getKeyboardLayouts();
+        String[] allLayoutDesc = new String[allLayouts.length];
+        for (int i = 0; i < allLayouts.length; i++) {
+            allLayoutDesc[i] = allLayouts[i].getDescriptor();
+        }
+        return allLayoutDesc;
+    }
+
+    public void switchKeyboardLayout(int deviceId, int direction) {
+        mHandler.obtainMessage(MSG_SWITCH_KEYBOARD_LAYOUT, deviceId, direction).sendToTarget();
+    }
+
+    // Must be called on handler.
+    private void handleSwitchKeyboardLayout(int deviceId, int direction) {
+        final InputDevice device = getInputDevice(deviceId);
+        if (device != null) {
+            final boolean changed;
+            final String keyboardLayoutDescriptor;
+
+            String key = getLayoutDescriptor(device.getIdentifier());
+            synchronized (mDataStore) {
+                try {
+                    changed = mDataStore.switchKeyboardLayout(key, direction);
+                    keyboardLayoutDescriptor = mDataStore.getCurrentKeyboardLayout(
+                            key);
+                } finally {
+                    mDataStore.saveIfNeeded();
+                }
+            }
+
+            if (changed) {
+                if (mSwitchedKeyboardLayoutToast != null) {
+                    mSwitchedKeyboardLayoutToast.cancel();
+                    mSwitchedKeyboardLayoutToast = null;
+                }
+                if (keyboardLayoutDescriptor != null) {
+                    KeyboardLayout keyboardLayout = getKeyboardLayout(keyboardLayoutDescriptor);
+                    if (keyboardLayout != null) {
+                        mSwitchedKeyboardLayoutToast = Toast.makeText(
+                                mContext, keyboardLayout.getLabel(), Toast.LENGTH_SHORT);
+                        mSwitchedKeyboardLayoutToast.show();
+                    }
+                }
+
+                reloadKeyboardLayouts();
+            }
+        }
+    }
+
+    public String[] getKeyboardLayoutOverlay(InputDeviceIdentifier identifier) {
+        String keyboardLayoutDescriptor = getCurrentKeyboardLayoutForInputDevice(identifier);
+        if (keyboardLayoutDescriptor == null) {
+            return null;
+        }
+
+        final String[] result = new String[2];
+        visitKeyboardLayout(keyboardLayoutDescriptor,
+                (resources, keyboardLayoutResId, layout) -> {
+                    try (InputStreamReader stream = new InputStreamReader(
+                            resources.openRawResource(keyboardLayoutResId))) {
+                        result[0] = layout.getDescriptor();
+                        result[1] = Streams.readFully(stream);
+                    } catch (IOException | Resources.NotFoundException ignored) {
+                    }
+                });
+        if (result[0] == null) {
+            Slog.w(TAG, "Could not get keyboard layout with descriptor '"
+                    + keyboardLayoutDescriptor + "'.");
+            return null;
+        }
+        return result;
+    }
+
+    private void reloadKeyboardLayouts() {
+        if (DEBUG) {
+            Slog.d(TAG, "Reloading keyboard layouts.");
+        }
+        mNative.reloadKeyboardLayouts();
+    }
+
+    private void maybeUpdateNotification() {
+        NotificationManager notificationManager = mContext.getSystemService(
+                NotificationManager.class);
+        if (notificationManager == null) {
+            return;
+        }
+        if (!mKeyboardsWithMissingLayouts.isEmpty()) {
+            if (mKeyboardsWithMissingLayouts.size() > 1) {
+                // We have more than one keyboard missing a layout, so drop the
+                // user at the generic input methods page, so they can pick which
+                // one to set.
+                showMissingKeyboardLayoutNotification(notificationManager, null);
+            } else {
+                showMissingKeyboardLayoutNotification(notificationManager,
+                        mKeyboardsWithMissingLayouts.get(0));
+            }
+        } else if (mKeyboardLayoutNotificationShown) {
+            hideMissingKeyboardLayoutNotification(notificationManager);
+        }
+    }
+
+    // Must be called on handler.
+    private void showMissingKeyboardLayoutNotification(NotificationManager notificationManager,
+            InputDevice device) {
+        if (!mKeyboardLayoutNotificationShown) {
+            final Intent intent = new Intent(Settings.ACTION_HARD_KEYBOARD_SETTINGS);
+            if (device != null) {
+                intent.putExtra(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, device.getIdentifier());
+            }
+            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+            final PendingIntent keyboardLayoutIntent = PendingIntent.getActivityAsUser(mContext, 0,
+                    intent, PendingIntent.FLAG_IMMUTABLE, null, UserHandle.CURRENT);
+
+            Resources r = mContext.getResources();
+            Notification notification =
+                    new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
+                            .setContentTitle(r.getString(
+                                    R.string.select_keyboard_layout_notification_title))
+                            .setContentText(r.getString(
+                                    R.string.select_keyboard_layout_notification_message))
+                            .setContentIntent(keyboardLayoutIntent)
+                            .setSmallIcon(R.drawable.ic_settings_language)
+                            .setColor(mContext.getColor(
+                                    com.android.internal.R.color.system_notification_accent_color))
+                            .build();
+            notificationManager.notifyAsUser(null,
+                    SystemMessageProto.SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
+                    notification, UserHandle.ALL);
+            mKeyboardLayoutNotificationShown = true;
+        }
+    }
+
+    // Must be called on handler.
+    private void hideMissingKeyboardLayoutNotification(NotificationManager notificationManager) {
+        if (mKeyboardLayoutNotificationShown) {
+            mKeyboardLayoutNotificationShown = false;
+            notificationManager.cancelAsUser(null,
+                    SystemMessageProto.SystemMessage.NOTE_SELECT_KEYBOARD_LAYOUT,
+                    UserHandle.ALL);
+        }
+    }
+
+    private boolean handleMessage(Message msg) {
+        switch (msg.what) {
+            case MSG_UPDATE_EXISTING_DEVICES:
+                // Circle through all the already added input devices
+                // Need to do it on handler thread and not block IMS thread
+                for (int deviceId : (int[]) msg.obj) {
+                    onInputDeviceAdded(deviceId);
+                }
+                return true;
+            case MSG_SWITCH_KEYBOARD_LAYOUT:
+                handleSwitchKeyboardLayout(msg.arg1, msg.arg2);
+                return true;
+            case MSG_RELOAD_KEYBOARD_LAYOUTS:
+                reloadKeyboardLayouts();
+                return true;
+            case MSG_UPDATE_KEYBOARD_LAYOUTS:
+                updateKeyboardLayouts();
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    private InputDevice getInputDevice(int deviceId) {
+        InputManager inputManager = mContext.getSystemService(InputManager.class);
+        return inputManager != null ? inputManager.getInputDevice(deviceId) : null;
+    }
+
+    private static final class KeyboardLayoutDescriptor {
+        public String packageName;
+        public String receiverName;
+        public String keyboardLayoutName;
+
+        public static String format(String packageName,
+                String receiverName, String keyboardName) {
+            return packageName + "/" + receiverName + "/" + keyboardName;
+        }
+
+        public static KeyboardLayoutDescriptor parse(String descriptor) {
+            int pos = descriptor.indexOf('/');
+            if (pos < 0 || pos + 1 == descriptor.length()) {
+                return null;
+            }
+            int pos2 = descriptor.indexOf('/', pos + 1);
+            if (pos2 < pos + 2 || pos2 + 1 == descriptor.length()) {
+                return null;
+            }
+
+            KeyboardLayoutDescriptor result = new KeyboardLayoutDescriptor();
+            result.packageName = descriptor.substring(0, pos);
+            result.receiverName = descriptor.substring(pos + 1, pos2);
+            result.keyboardLayoutName = descriptor.substring(pos2 + 1);
+            return result;
+        }
+    }
+
+    private interface KeyboardLayoutVisitor {
+        void visitKeyboardLayout(Resources resources,
+                int keyboardLayoutResId, KeyboardLayout layout);
+    }
+}
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 015e576..c53f1a5 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -110,11 +110,10 @@
 
     @AnyThread
     void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privilegedOperations,
-            int configChanges, @InputMethodNavButtonFlags int navigationBarFlags) {
+            @InputMethodNavButtonFlags int navigationBarFlags) {
         final IInputMethod.InitParams params = new IInputMethod.InitParams();
         params.token = token;
         params.privilegedOperations = privilegedOperations;
-        params.configChanges = configChanges;
         params.navigationBarFlags = navigationBarFlags;
         try {
             mTarget.initializeInternal(params);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 6dbb362..079234c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -42,12 +42,15 @@
 import android.view.inputmethod.InputMethodInfo;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.IInputMethod;
 import com.android.internal.inputmethod.InputBindResult;
 import com.android.internal.inputmethod.UnbindReason;
 import com.android.server.EventLogTags;
 import com.android.server.wm.WindowManagerInternal;
 
+import java.util.concurrent.CountDownLatch;
+
 /**
  * A controller managing the state of the input method binding.
  */
@@ -77,19 +80,26 @@
     @GuardedBy("ImfLock.class") private boolean mVisibleBound;
     @GuardedBy("ImfLock.class") private boolean mSupportsStylusHw;
 
+    @Nullable private CountDownLatch mLatchForTesting;
+
     /**
      * Binding flags for establishing connection to the {@link InputMethodService}.
      */
-    private static final int IME_CONNECTION_BIND_FLAGS =
+    @VisibleForTesting
+    static final int IME_CONNECTION_BIND_FLAGS =
             Context.BIND_AUTO_CREATE
                     | Context.BIND_NOT_VISIBLE
                     | Context.BIND_NOT_FOREGROUND
                     | Context.BIND_IMPORTANT_BACKGROUND
                     | Context.BIND_SCHEDULE_LIKE_TOP_APP;
+
+    private final int mImeConnectionBindFlags;
+
     /**
      * Binding flags used only while the {@link InputMethodService} is showing window.
      */
-    private static final int IME_VISIBLE_BIND_FLAGS =
+    @VisibleForTesting
+    static final int IME_VISIBLE_BIND_FLAGS =
             Context.BIND_AUTO_CREATE
                     | Context.BIND_TREAT_LIKE_ACTIVITY
                     | Context.BIND_FOREGROUND_SERVICE
@@ -97,12 +107,19 @@
                     | Context.BIND_SHOWING_UI;
 
     InputMethodBindingController(@NonNull InputMethodManagerService service) {
+        this(service, IME_CONNECTION_BIND_FLAGS, null /* latchForTesting */);
+    }
+
+    InputMethodBindingController(@NonNull InputMethodManagerService service,
+            int imeConnectionBindFlags, CountDownLatch latchForTesting) {
         mService = service;
         mContext = mService.mContext;
         mMethodMap = mService.mMethodMap;
         mSettings = mService.mSettings;
         mPackageManagerInternal = mService.mPackageManagerInternal;
         mWindowManagerInternal = mService.mWindowManagerInternal;
+        mImeConnectionBindFlags = imeConnectionBindFlags;
+        mLatchForTesting = latchForTesting;
     }
 
     /**
@@ -242,7 +259,7 @@
         @Override public void onBindingDied(ComponentName name) {
             synchronized (ImfLock.class) {
                 mService.invalidateAutofillSessionLocked();
-                if (mVisibleBound) {
+                if (isVisibleBound()) {
                     unbindVisibleConnection();
                 }
             }
@@ -279,7 +296,7 @@
                     if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
                     final InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
                     mSupportsStylusHw = info.supportsStylusHandwriting();
-                    mService.initializeImeLocked(mCurMethod, mCurToken, info.getConfigChanges());
+                    mService.initializeImeLocked(mCurMethod, mCurToken);
                     mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
                     mService.reRequestCurrentClientSessionLocked();
                     mService.performOnCreateInlineSuggestionsRequestLocked();
@@ -291,6 +308,10 @@
                 mService.scheduleResetStylusHandwriting();
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
+
+            if (mLatchForTesting != null) {
+                mLatchForTesting.countDown(); // Notify the finish to tests
+            }
         }
 
         @GuardedBy("ImfLock.class")
@@ -338,15 +359,15 @@
 
     @GuardedBy("ImfLock.class")
     void unbindCurrentMethod() {
-        if (mVisibleBound) {
+        if (isVisibleBound()) {
             unbindVisibleConnection();
         }
 
-        if (mHasConnection) {
+        if (hasConnection()) {
             unbindMainConnection();
         }
 
-        if (mCurToken != null) {
+        if (getCurToken() != null) {
             removeCurrentToken();
             mService.resetSystemUiLocked();
         }
@@ -448,17 +469,17 @@
 
     @GuardedBy("ImfLock.class")
     private boolean bindCurrentInputMethodService(ServiceConnection conn, int flags) {
-        if (mCurIntent == null || conn == null) {
+        if (getCurIntent() == null || conn == null) {
             Slog.e(TAG, "--- bind failed: service = " + mCurIntent + ", conn = " + conn);
             return false;
         }
-        return mContext.bindServiceAsUser(mCurIntent, conn, flags,
+        return mContext.bindServiceAsUser(getCurIntent(), conn, flags,
                 new UserHandle(mSettings.getCurrentUserId()));
     }
 
     @GuardedBy("ImfLock.class")
     private boolean bindCurrentInputMethodServiceMainConnection() {
-        mHasConnection = bindCurrentInputMethodService(mMainConnection, IME_CONNECTION_BIND_FLAGS);
+        mHasConnection = bindCurrentInputMethodService(mMainConnection, mImeConnectionBindFlags);
         return mHasConnection;
     }
 
@@ -472,7 +493,7 @@
     void setCurrentMethodVisible() {
         if (mCurMethod != null) {
             if (DEBUG) Slog.d(TAG, "setCurrentMethodVisible: mCurToken=" + mCurToken);
-            if (mHasConnection && !mVisibleBound) {
+            if (hasConnection() && !isVisibleBound()) {
                 mVisibleBound = bindCurrentInputMethodService(mVisibleConnection,
                         IME_VISIBLE_BIND_FLAGS);
             }
@@ -480,7 +501,7 @@
         }
 
         // No IME is currently connected. Reestablish the main connection.
-        if (!mHasConnection) {
+        if (!hasConnection()) {
             if (DEBUG) {
                 Slog.d(TAG, "Cannot show input: no IME bound. Rebinding.");
             }
@@ -512,7 +533,7 @@
      */
     @GuardedBy("ImfLock.class")
     void setCurrentMethodNotVisible() {
-        if (mVisibleBound) {
+        if (isVisibleBound()) {
             unbindVisibleConnection();
         }
     }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8b083bd..080d582 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2692,14 +2692,13 @@
     }
 
     @GuardedBy("ImfLock.class")
-    void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token,
-            @android.content.pm.ActivityInfo.Config int configChanges) {
+    void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token) {
         if (DEBUG) {
             Slog.v(TAG, "Sending attach of token: " + token + " for display: "
                     + mCurTokenDisplayId);
         }
         inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token),
-                configChanges, getInputMethodNavButtonFlagsLocked());
+                getInputMethodNavButtonFlagsLocked());
     }
 
     @AnyThread
diff --git a/services/core/java/com/android/server/locales/LocaleManagerService.java b/services/core/java/com/android/server/locales/LocaleManagerService.java
index 39b9f1f..783a6ae 100644
--- a/services/core/java/com/android/server/locales/LocaleManagerService.java
+++ b/services/core/java/com/android/server/locales/LocaleManagerService.java
@@ -38,6 +38,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ShellCallback;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -59,6 +60,10 @@
  */
 public class LocaleManagerService extends SystemService {
     private static final String TAG = "LocaleManagerService";
+    // The feature flag control that allows the active IME to query the locales of the foreground
+    // app.
+    private static final String PROP_ALLOW_IME_QUERY_APP_LOCALE =
+            "i18n.feature.allow_ime_query_app_locale";
     final Context mContext;
     private final LocaleManagerService.LocaleManagerBinderService mBinderService;
     private ActivityTaskManagerInternal mActivityTaskManagerInternal;
@@ -431,6 +436,10 @@
      * Checks if the calling app is the current input method.
      */
     private boolean isCallerFromCurrentInputMethod(int userId) {
+        if (!SystemProperties.getBoolean(PROP_ALLOW_IME_QUERY_APP_LOCALE, true)) {
+            return false;
+        }
+
         String currentInputMethod = Settings.Secure.getStringForUser(
                 mContext.getContentResolver(),
                 Settings.Secure.DEFAULT_INPUT_METHOD,
diff --git a/services/core/java/com/android/server/location/LocationManagerService.java b/services/core/java/com/android/server/location/LocationManagerService.java
index 2669d21..3ce51c3 100644
--- a/services/core/java/com/android/server/location/LocationManagerService.java
+++ b/services/core/java/com/android/server/location/LocationManagerService.java
@@ -28,6 +28,7 @@
 import static android.location.LocationManager.NETWORK_PROVIDER;
 import static android.location.LocationRequest.LOW_POWER_EXCEPTIONS;
 import static android.location.provider.LocationProviderBase.ACTION_FUSED_PROVIDER;
+import static android.location.provider.LocationProviderBase.ACTION_GNSS_PROVIDER;
 import static android.location.provider.LocationProviderBase.ACTION_NETWORK_PROVIDER;
 
 import static com.android.server.location.LocationPermissions.PERMISSION_COARSE;
@@ -140,9 +141,7 @@
 import com.android.server.location.provider.proxy.ProxyLocationProvider;
 import com.android.server.location.settings.LocationSettings;
 import com.android.server.location.settings.LocationUserSettings;
-import com.android.server.pm.UserManagerInternal;
 import com.android.server.pm.permission.LegacyPermissionManagerInternal;
-import com.android.server.utils.Slogf;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -310,10 +309,6 @@
         permissionManagerInternal.setLocationExtraPackagesProvider(
                 userId -> mContext.getResources().getStringArray(
                         com.android.internal.R.array.config_locationExtraPackageNames));
-
-        // TODO(b/241604546): properly handle this callback
-        LocalServices.getService(UserManagerInternal.class).addUserVisibilityListener(
-                (u, v) -> Slogf.i(TAG, "onUserVisibilityChanged(): %d -> %b", u, v));
     }
 
     @Nullable
@@ -445,9 +440,24 @@
             mGnssManagerService = new GnssManagerService(mContext, mInjector, gnssNative);
             mGnssManagerService.onSystemReady();
 
+            boolean useGnssHardwareProvider = mContext.getResources().getBoolean(
+                    com.android.internal.R.bool.config_useGnssHardwareProvider);
+            AbstractLocationProvider gnssProvider = null;
+            if (!useGnssHardwareProvider) {
+                gnssProvider = ProxyLocationProvider.create(
+                        mContext,
+                        GPS_PROVIDER,
+                        ACTION_GNSS_PROVIDER,
+                        com.android.internal.R.bool.config_useGnssHardwareProvider,
+                        com.android.internal.R.string.config_gnssLocationProviderPackageName);
+            }
+            if (gnssProvider == null) {
+                gnssProvider = mGnssManagerService.getGnssLocationProvider();
+            }
+
             LocationProviderManager gnssManager = new LocationProviderManager(mContext, mInjector,
                     GPS_PROVIDER, mPassiveManager);
-            addLocationProviderManager(gnssManager, mGnssManagerService.getGnssLocationProvider());
+            addLocationProviderManager(gnssManager, gnssProvider);
         }
 
         // bind to geocoder provider
@@ -1702,7 +1712,7 @@
 
         private final Context mContext;
 
-        private final UserInfoHelper mUserInfoHelper;
+        private final SystemUserInfoHelper mUserInfoHelper;
         private final LocationSettings mLocationSettings;
         private final AlarmHelper mAlarmHelper;
         private final SystemAppOpsHelper mAppOpsHelper;
@@ -1725,7 +1735,7 @@
         @GuardedBy("this")
         private boolean mSystemReady;
 
-        SystemInjector(Context context, UserInfoHelper userInfoHelper) {
+        SystemInjector(Context context, SystemUserInfoHelper userInfoHelper) {
             mContext = context;
 
             mUserInfoHelper = userInfoHelper;
@@ -1745,6 +1755,7 @@
         }
 
         synchronized void onSystemReady() {
+            mUserInfoHelper.onSystemReady();
             mAppOpsHelper.onSystemReady();
             mLocationPermissionsHelper.onSystemReady();
             mSettingsHelper.onSystemReady();
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 90245b5e..7f6c2d6 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -73,6 +73,7 @@
 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.ScheduledThreadPoolExecutor;
@@ -147,7 +148,6 @@
     private final ScheduledThreadPoolExecutor mDailyMetricTimer =
             new ScheduledThreadPoolExecutor(1);
 
-
     // The period of the recurring time
     private static final int PERIOD_METRIC_QUERY_DAYS = 1;
 
@@ -363,11 +363,13 @@
      */
     private void initDefaultClientMap() {
         HashMap<Integer, IContextHubClient> defaultClientMap = new HashMap<>();
-        for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
+        for (Map.Entry<Integer, ContextHubInfo> entry: mContextHubIdToInfoMap.entrySet()) {
+            int contextHubId = entry.getKey();
+            ContextHubInfo contextHubInfo = entry.getValue();
+
             mLastRestartTimestampMap.put(contextHubId,
                     new AtomicLong(SystemClock.elapsedRealtimeNanos()));
 
-            ContextHubInfo contextHubInfo = mContextHubIdToInfoMap.get(contextHubId);
             IContextHubClient client = mClientManager.registerClient(
                     contextHubInfo, createDefaultClientCallback(contextHubId),
                     /* attributionTag= */ null, mTransactionManager, mContext.getPackageName());
@@ -1133,6 +1135,26 @@
         mTransactionManager.addTransaction(transaction);
     }
 
+    @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB)
+    /**
+     * Queries for a list of preloaded nanoapp IDs from the specified Context Hub.
+     *
+     * @param hubInfo The Context Hub to query a list of nanoapps from.
+     * @return The list of 64-bit IDs of the preloaded nanoapps.
+     * @throws NullPointerException if hubInfo is null
+     */
+    @Override
+    public long[] getPreloadedNanoAppIds(ContextHubInfo hubInfo) throws RemoteException {
+        super.getPreloadedNanoAppIds_enforcePermission();
+        Objects.requireNonNull(hubInfo, "hubInfo cannot be null");
+
+        long[] nanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
+        if (nanoappIds == null) {
+            return new long[0];
+        }
+        return nanoappIds;
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -1160,6 +1182,10 @@
         mNanoAppStateManager.foreachNanoAppInstanceInfo((info) -> pw.println(info));
 
         pw.println("");
+        pw.println("=================== PRELOADED NANOAPPS ====================");
+        dumpPreloadedNanoapps(pw);
+
+        pw.println("");
         pw.println("=================== CLIENTS ====================");
         pw.println(mClientManager);
 
@@ -1201,6 +1227,21 @@
         proto.flush();
     }
 
+    /**
+     * Dumps preloaded nanoapps to the console
+     */
+    private void dumpPreloadedNanoapps(PrintWriter pw) {
+        if (mContextHubWrapper == null) {
+            return;
+        }
+
+        long[] preloadedNanoappIds = mContextHubWrapper.getPreloadedNanoappIds();
+        for (long preloadedNanoappId: preloadedNanoappIds) {
+            pw.print("ID: 0x");
+            pw.println(Long.toHexString(preloadedNanoappId));
+        }
+    }
+
     private void checkPermissions() {
         ContextHubServiceUtil.checkPermissions(mContext);
     }
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 48152b4..f55ae6e 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -359,6 +359,14 @@
     public abstract int queryNanoapps(int contextHubId) throws RemoteException;
 
     /**
+     * Provides the list of preloaded nanoapp IDs on the system. The output of this API must
+     * not change.
+     *
+     * @return The list of preloaded nanoapp IDs
+     */
+    public abstract long[] getPreloadedNanoappIds();
+
+    /**
      * Registers a callback with the Context Hub.
      *
      * @param contextHubId The ID of the Context Hub to register the callback with.
@@ -683,6 +691,20 @@
             }
         }
 
+        public long[] getPreloadedNanoappIds() {
+            android.hardware.contexthub.IContextHub hub = getHub();
+            if (hub == null) {
+                return null;
+            }
+
+            try {
+                return hub.getPreloadedNanoappIds();
+            } catch (RemoteException e) {
+                Log.e(TAG, "Exception while getting preloaded nanoapp IDs: " + e.getMessage());
+                return null;
+            }
+        }
+
         public void registerExistingCallback(int contextHubId) {
             android.hardware.contexthub.IContextHub hub = getHub();
             if (hub == null) {
@@ -863,6 +885,10 @@
                     mHub.queryApps(contextHubId));
         }
 
+        public long[] getPreloadedNanoappIds() {
+            return new long[0];
+        }
+
         public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
             mHidlCallbackMap.put(contextHubId,
                         new ContextHubWrapperHidlCallback(contextHubId, callback));
diff --git a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
index 45436e7..cb952ed 100644
--- a/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
+++ b/services/core/java/com/android/server/location/eventlog/LocationEventLog.java
@@ -110,6 +110,11 @@
         addLog(new UserSwitchedEvent(userIdFrom, userIdTo));
     }
 
+    /** Logs a user visibility changed event. */
+    public void logUserVisibilityChanged(int userId, boolean visible) {
+        addLog(new UserVisibilityChangedEvent(userId, visible));
+    }
+
     /** Logs a location enabled/disabled event. */
     public void logLocationEnabled(int userId, boolean enabled) {
         addLog(new LocationEnabledEvent(userId, enabled));
@@ -475,6 +480,22 @@
         }
     }
 
+    private static final class UserVisibilityChangedEvent {
+
+        private final int mUserId;
+        private final boolean mVisible;
+
+        UserVisibilityChangedEvent(int userId, boolean visible) {
+            mUserId = userId;
+            mVisible = visible;
+        }
+
+        @Override
+        public String toString() {
+            return "[u" + mUserId + "] " + (mVisible ? "visible" : "invisible");
+        }
+    }
+
     private static final class LocationEnabledEvent {
 
         private final int mUserId;
diff --git a/services/core/java/com/android/server/location/geofence/GeofenceManager.java b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
index 0f5e3d4..d3ceddd 100644
--- a/services/core/java/com/android/server/location/geofence/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/geofence/GeofenceManager.java
@@ -387,7 +387,7 @@
             if (!mSettingsHelper.isLocationEnabled(identity.getUserId())) {
                 return false;
             }
-            if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+            if (!mUserInfoHelper.isVisibleUserId(identity.getUserId())) {
                 return false;
             }
             if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
@@ -534,7 +534,10 @@
     }
 
     void onUserChanged(int userId, int change) {
-        if (change == UserListener.CURRENT_USER_CHANGED) {
+        // current user changes affect whether system server location requests are allowed to access
+        // location, and visibility changes affect whether any given user may access location.
+        if (change == UserListener.CURRENT_USER_CHANGED
+                || change == UserListener.USER_VISIBILITY_CHANGED) {
             updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
         }
     }
diff --git a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
index 349b94b..567d8ac 100644
--- a/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
+++ b/services/core/java/com/android/server/location/gnss/GnssListenerMultiplexer.java
@@ -317,7 +317,7 @@
                     identity.getUserId())) {
                 return false;
             }
-            if (!mUserInfoHelper.isCurrentUserId(identity.getUserId())) {
+            if (!mUserInfoHelper.isVisibleUserId(identity.getUserId())) {
                 return false;
             }
             if (mSettingsHelper.isLocationPackageBlacklisted(identity.getUserId(),
@@ -394,7 +394,10 @@
     }
 
     private void onUserChanged(int userId, int change) {
-        if (change == UserListener.CURRENT_USER_CHANGED) {
+        // current user changes affect whether system server location requests are allowed to access
+        // location, and visibility changes affect whether any given user may access location.
+        if (change == UserListener.CURRENT_USER_CHANGED
+                || change == UserListener.USER_VISIBILITY_CHANGED) {
             updateRegistrations(registration -> registration.getIdentity().getUserId() == userId);
         }
     }
diff --git a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
index 6f6b1c9..282ad57 100644
--- a/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssLocationProvider.java
@@ -81,6 +81,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.WorkSource;
 import android.os.WorkSource.WorkChain;
 import android.provider.Settings;
@@ -930,9 +931,15 @@
     }
 
     private void updateEnabled() {
-        // Generally follow location setting for current user
-        boolean enabled = mContext.getSystemService(LocationManager.class)
-                .isLocationEnabledForUser(UserHandle.CURRENT);
+        boolean enabled = false;
+
+        // Generally follow location setting for visible users
+        LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+        Set<UserHandle> visibleUserHandles =
+                mContext.getSystemService(UserManager.class).getVisibleUsers();
+        for (UserHandle visibleUserHandle : visibleUserHandles) {
+            enabled |= locationManager.isLocationEnabledForUser(visibleUserHandle);
+        }
 
         // .. but enable anyway, if there's an active bypass request (e.g. ELS or ADAS)
         enabled |= (mProviderRequest != null
diff --git a/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java b/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
index ed1e654..40dd979 100644
--- a/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
+++ b/services/core/java/com/android/server/location/injector/SystemUserInfoHelper.java
@@ -33,9 +33,11 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
 import com.android.server.LocalServices;
+import com.android.server.pm.UserManagerInternal;
 
 import java.io.FileDescriptor;
 import java.util.Arrays;
+import java.util.Objects;
 
 /**
  * Provides accessors and listeners for all user info.
@@ -50,11 +52,21 @@
     @Nullable private IActivityManager mActivityManager;
     @GuardedBy("this")
     @Nullable private UserManager mUserManager;
+    @GuardedBy("this")
+    @Nullable private UserManagerInternal mUserManagerInternal;
 
     public SystemUserInfoHelper(Context context) {
         mContext = context;
     }
 
+    /** The function should be called when PHASE_SYSTEM_SERVICES_READY. */
+    public synchronized void onSystemReady() {
+        mUserManagerInternal =
+                Objects.requireNonNull(LocalServices.getService(UserManagerInternal.class));
+        mUserManagerInternal.addUserVisibilityListener(
+                (userId, visible) -> dispatchOnVisibleUserChanged(userId, visible));
+    }
+
     @Nullable
     protected final ActivityManagerInternal getActivityManagerInternal() {
         synchronized (this) {
@@ -136,6 +148,24 @@
     }
 
     @Override
+    public boolean isVisibleUserId(@UserIdInt int userId) {
+        synchronized (this) {
+            // if you're hitting this precondition then you are invoking this before the system is
+            // ready
+            Preconditions.checkState(mUserManagerInternal != null);
+        }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                return mUserManagerInternal.isUserVisible(userId);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
+    @Override
     protected int[] getProfileIds(@UserIdInt int userId) {
         UserManager userManager = getUserManager();
 
diff --git a/services/core/java/com/android/server/location/injector/UserInfoHelper.java b/services/core/java/com/android/server/location/injector/UserInfoHelper.java
index c835370..2b9db1c 100644
--- a/services/core/java/com/android/server/location/injector/UserInfoHelper.java
+++ b/services/core/java/com/android/server/location/injector/UserInfoHelper.java
@@ -22,6 +22,7 @@
 import static com.android.server.location.injector.UserInfoHelper.UserListener.CURRENT_USER_CHANGED;
 import static com.android.server.location.injector.UserInfoHelper.UserListener.USER_STARTED;
 import static com.android.server.location.injector.UserInfoHelper.UserListener.USER_STOPPED;
+import static com.android.server.location.injector.UserInfoHelper.UserListener.USER_VISIBILITY_CHANGED;
 
 import android.annotation.IntDef;
 import android.annotation.UserIdInt;
@@ -47,8 +48,9 @@
         int CURRENT_USER_CHANGED = 1;
         int USER_STARTED = 2;
         int USER_STOPPED = 3;
+        int USER_VISIBILITY_CHANGED = 4;
 
-        @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED})
+        @IntDef({CURRENT_USER_CHANGED, USER_STARTED, USER_STOPPED, USER_VISIBILITY_CHANGED})
         @Retention(RetentionPolicy.SOURCE)
         @interface UserChange {}
 
@@ -121,6 +123,18 @@
         }
     }
 
+    protected final void dispatchOnVisibleUserChanged(@UserIdInt int userId, boolean visible) {
+        if (D) {
+            Log.d(TAG, "visibility of u" + userId + " changed to "
+                    + (visible ? "visible" : "invisible"));
+        }
+        EVENT_LOG.logUserVisibilityChanged(userId, visible);
+
+        for (UserListener listener : mListeners) {
+            listener.onUserChanged(userId, USER_VISIBILITY_CHANGED);
+        }
+    }
+
     /**
      * Returns an array of running user ids. This will include all running users, and will also
      * include any profiles of the running users. The caller must never mutate the returned
@@ -129,8 +143,8 @@
     public abstract int[] getRunningUserIds();
 
     /**
-     * Returns true if the given user id is either the current user or a profile of the current
-     * user.
+     * Returns {@code true} if the given user id is either the current user or a profile of the
+     * current user.
      */
     public abstract boolean isCurrentUserId(@UserIdInt int userId);
 
@@ -140,6 +154,13 @@
      */
     public abstract @UserIdInt int getCurrentUserId();
 
+    /**
+     * Returns {@code true} if the user is visible.
+     *
+     * <p>The visibility of a user is defined by {@link android.os.UserManager#isUserVisible()}.
+     */
+    public abstract boolean isVisibleUserId(@UserIdInt int userId);
+
     protected abstract int[] getProfileIds(@UserIdInt int userId);
 
     /**
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 338a995..7063cb8 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -661,6 +661,8 @@
                 if (!GPS_PROVIDER.equals(mName)) {
                     Log.e(TAG, "adas gnss bypass request received in non-gps provider");
                     adasGnssBypass = false;
+                } else if (!mUserHelper.isCurrentUserId(getIdentity().getUserId())) {
+                    adasGnssBypass = false;
                 } else if (!mLocationSettings.getUserSettings(
                         getIdentity().getUserId()).isAdasGnssLocationEnabled()) {
                     adasGnssBypass = false;
@@ -1712,6 +1714,8 @@
             if (!GPS_PROVIDER.equals(mName)) {
                 Log.e(TAG, "adas gnss bypass request received in non-gps provider");
                 adasGnssBypass = false;
+            } else if (!mUserHelper.isCurrentUserId(identity.getUserId())) {
+                adasGnssBypass = false;
             } else if (!mLocationSettings.getUserSettings(
                     identity.getUserId()).isAdasGnssLocationEnabled()) {
                 adasGnssBypass = false;
@@ -2193,7 +2197,7 @@
                 if (!isEnabled(identity.getUserId())) {
                     return false;
                 }
-                if (!mUserHelper.isCurrentUserId(identity.getUserId())) {
+                if (!mUserHelper.isVisibleUserId(identity.getUserId())) {
                     return false;
                 }
             }
@@ -2322,6 +2326,10 @@
 
             switch (change) {
                 case UserListener.CURRENT_USER_CHANGED:
+                    // current user changes affect whether system server location requests are
+                    // allowed to access location, and visibility changes affect whether any given
+                    // user may access location.
+                case UserListener.USER_VISIBILITY_CHANGED:
                     updateRegistrations(
                             registration -> registration.getIdentity().getUserId() == userId);
                     break;
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 25e71e8..0ae3a02 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -550,16 +550,6 @@
             return (BiometricManager) mContext.getSystemService(Context.BIOMETRIC_SERVICE);
         }
 
-        public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
-                int defaultValue) {
-            return Settings.Global.getInt(contentResolver, keyName, defaultValue);
-        }
-
-        public int settingsSecureGetInt(ContentResolver contentResolver, String keyName,
-                int defaultValue, int userId) {
-            return Settings.Secure.getIntForUser(contentResolver, keyName, defaultValue, userId);
-        }
-
         public java.security.KeyStore getJavaKeyStore() {
             try {
                 java.security.KeyStore ks = java.security.KeyStore.getInstance(
@@ -1027,9 +1017,9 @@
 
     private void enforceFrpResolved() {
         final ContentResolver cr = mContext.getContentResolver();
-        final boolean inSetupWizard = mInjector.settingsSecureGetInt(cr,
+        final boolean inSetupWizard = Settings.Secure.getIntForUser(cr,
                 Settings.Secure.USER_SETUP_COMPLETE, 0, UserHandle.USER_SYSTEM) == 0;
-        final boolean secureFrp = mInjector.settingsSecureGetInt(cr,
+        final boolean secureFrp = Settings.Secure.getIntForUser(cr,
                 Settings.Secure.SECURE_FRP_MODE, 0, UserHandle.USER_SYSTEM) == 1;
         if (inSetupWizard && secureFrp) {
             throw new SecurityException("Cannot change credential in SUW while factory reset"
@@ -2155,7 +2145,7 @@
         if (credential == null || credential.isNone()) {
             throw new IllegalArgumentException("Credential can't be null or empty");
         }
-        if (userId == USER_FRP && mInjector.settingsGlobalGetInt(mContext.getContentResolver(),
+        if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
             Slog.e(TAG, "FRP credential can only be verified prior to provisioning.");
             return VerifyCredentialResponse.ERROR;
@@ -3282,6 +3272,7 @@
             for (UserInfo user : users) {
                 if (userOwnsFrpCredential(mContext, user)) {
                     if (!isUserSecure(user.id)) {
+                        Slogf.d(TAG, "Clearing FRP credential tied to user %d", user.id);
                         mStorage.writePersistentDataBlock(PersistentData.TYPE_NONE, user.id,
                                 0, null);
                     }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
index 807ba3c..473c4b6 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java
@@ -550,7 +550,7 @@
         mCache.clear();
     }
 
-    @Nullable @VisibleForTesting
+    @Nullable
     PersistentDataBlockManagerInternal getPersistentDataBlockManager() {
         if (mPersistentDataBlockManagerInternal == null) {
             mPersistentDataBlockManagerInternal =
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 73a16fd..acd7cc1 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -32,6 +32,7 @@
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.security.GateKeeper;
 import android.security.Scrypt;
 import android.service.gatekeeper.GateKeeperResponse;
@@ -457,6 +458,11 @@
         mPasswordSlotManager = passwordSlotManager;
     }
 
+    private boolean isDeviceProvisioned() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, 0) != 0;
+    }
+
     @VisibleForTesting
     protected IWeaver getWeaverService() throws RemoteException {
         try {
@@ -770,6 +776,17 @@
     private int getNextAvailableWeaverSlot() {
         Set<Integer> usedSlots = getUsedWeaverSlots();
         usedSlots.addAll(mPasswordSlotManager.getUsedSlots());
+        // If the device is not yet provisioned, then the Weaver slot used by the FRP credential may
+        // be still needed and must not be reused yet.  (This *should* instead check "has FRP been
+        // resolved yet?", which would allow reusing the slot a bit earlier.  However, the
+        // SECURE_FRP_MODE setting gets set to 1 too late for it to be used here.)
+        if (!isDeviceProvisioned()) {
+            PersistentData persistentData = mStorage.readPersistentDataBlock();
+            if (persistentData != null && persistentData.type == PersistentData.TYPE_SP_WEAVER) {
+                int slot = persistentData.userId; // Note: field name is misleading
+                usedSlots.add(slot);
+            }
+        }
         for (int i = 0; i < mWeaverConfig.slots; i++) {
             if (!usedSlots.contains(i)) {
                 return i;
@@ -814,9 +831,14 @@
 
             protectorSecret = transformUnderWeaverSecret(stretchedLskf, weaverSecret);
         } else {
-            // Weaver is unavailable, so make the protector use Gatekeeper to verify the LSKF
-            // instead.  However, skip Gatekeeper when the LSKF is empty, since it wouldn't give any
-            // benefit in that case as Gatekeeper isn't expected to provide secure deletion.
+            // Weaver is unavailable, so make the protector use Gatekeeper (GK) to verify the LSKF.
+            //
+            // However, skip GK when the LSKF is empty.  There are two reasons for this, one
+            // performance and one correctness.  The performance reason is that GK wouldn't give any
+            // benefit with an empty LSKF anyway, since GK isn't expected to provide secure
+            // deletion.  The correctness reason is that it is unsafe to enroll a password in the
+            // 'fakeUserId' GK range on an FRP-protected device that is in the setup wizard with FRP
+            // not passed yet, as that may overwrite the enrollment used by the FRP credential.
             if (!credential.isNone()) {
                 // In case GK enrollment leaves persistent state around (in RPMB), this will nuke
                 // them to prevent them from accumulating and causing problems.
@@ -908,12 +930,40 @@
         }
     }
 
+    private static boolean isNoneCredential(PasswordData pwd) {
+        return pwd == null || pwd.credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE;
+    }
+
+    private boolean shouldSynchronizeFrpCredential(@Nullable PasswordData pwd, int userId) {
+        if (mStorage.getPersistentDataBlockManager() == null) {
+            return false;
+        }
+        UserInfo userInfo = mUserManager.getUserInfo(userId);
+        if (!LockPatternUtils.userOwnsFrpCredential(mContext, userInfo)) {
+            return false;
+        }
+        // When initializing the synthetic password of the user that will own the FRP credential,
+        // the FRP data block must not be cleared if the device isn't provisioned yet, since in this
+        // case the old value of the block may still be needed for the FRP authentication step.  The
+        // FRP data block will instead be cleared later, by
+        // LockSettingsService.DeviceProvisionedObserver.clearFrpCredentialIfOwnerNotSecure().
+        //
+        // Don't check the SECURE_FRP_MODE setting here, as it gets set to 1 too late.
+        //
+        // Don't delay anything for a nonempty credential.  A nonempty credential can be set before
+        // the device has been provisioned, but it's guaranteed to be after FRP was resolved.
+        if (isNoneCredential(pwd) && !isDeviceProvisioned()) {
+            Slog.d(TAG, "Not clearing FRP credential yet because device is not yet provisioned");
+            return false;
+        }
+        return true;
+    }
+
     private void synchronizeFrpPassword(@Nullable PasswordData pwd, int requestedQuality,
             int userId) {
-        if (mStorage.getPersistentDataBlockManager() != null
-                && LockPatternUtils.userOwnsFrpCredential(mContext,
-                mUserManager.getUserInfo(userId))) {
-            if (pwd != null && pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+        if (shouldSynchronizeFrpCredential(pwd, userId)) {
+            Slogf.d(TAG, "Syncing Gatekeeper-based FRP credential tied to user %d", userId);
+            if (!isNoneCredential(pwd)) {
                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP, userId, requestedQuality,
                         pwd.toBytes());
             } else {
@@ -924,10 +974,9 @@
 
     private void synchronizeWeaverFrpPassword(@Nullable PasswordData pwd, int requestedQuality,
             int userId, int weaverSlot) {
-        if (mStorage.getPersistentDataBlockManager() != null
-                && LockPatternUtils.userOwnsFrpCredential(mContext,
-                mUserManager.getUserInfo(userId))) {
-            if (pwd != null && pwd.credentialType != LockPatternUtils.CREDENTIAL_TYPE_NONE) {
+        if (shouldSynchronizeFrpCredential(pwd, userId)) {
+            Slogf.d(TAG, "Syncing Weaver-based FRP credential tied to user %d", userId);
+            if (!isNoneCredential(pwd)) {
                 mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, weaverSlot,
                         requestedQuality, pwd.toBytes());
             } else {
@@ -1058,7 +1107,7 @@
         AuthenticationResult result = new AuthenticationResult();
 
         if (protectorId == SyntheticPasswordManager.NULL_PROTECTOR_ID) {
-            // This should never happen, due to the migration done in LSS.bootCompleted().
+            // This should never happen, due to the migration done in LSS.onThirdPartyAppsStarted().
             Slogf.wtf(TAG, "Synthetic password not found for user %d", userId);
             result.gkResponse = VerifyCredentialResponse.ERROR;
             return result;
diff --git a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
index dcdb881..72ce38b 100644
--- a/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
+++ b/services/core/java/com/android/server/media/MediaButtonReceiverHolder.java
@@ -275,6 +275,10 @@
                 String.valueOf(mComponentType));
     }
 
+    public ComponentName getComponentName() {
+        return mComponentName;
+    }
+
     @ComponentType
     private static int getComponentType(PendingIntent pendingIntent) {
         if (pendingIntent.isBroadcast()) {
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index a6b7fe2..d6846be 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -41,6 +41,7 @@
 import android.media.MediaRoute2ProviderService;
 import android.media.MediaRouter2Manager;
 import android.media.RouteDiscoveryPreference;
+import android.media.RouteListingPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Binder;
 import android.os.Bundle;
@@ -257,6 +258,24 @@
         }
     }
 
+    public void setRouteListingPreference(
+            @NonNull IMediaRouter2 router,
+            @Nullable RouteListingPreference routeListingPreference) {
+        final long token = Binder.clearCallingIdentity();
+        try {
+            synchronized (mLock) {
+                RouterRecord routerRecord = mAllRouterRecords.get(router.asBinder());
+                if (routerRecord == null) {
+                    Slog.w(TAG, "Ignoring updating route listing of null routerRecord.");
+                    return;
+                }
+                setRouteListingPreferenceLocked(routerRecord, routeListingPreference);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     public void setRouteVolumeWithRouter2(@NonNull IMediaRouter2 router,
             @NonNull MediaRoute2Info route, int volume) {
         Objects.requireNonNull(router, "router must not be null");
@@ -648,9 +667,11 @@
                                 "userId: %d", newActiveUserId));
 
                 mCurrentActiveUserId = newActiveUserId;
-                for (int i = 0; i < mUserRecords.size(); i++) {
-                    int userId = mUserRecords.keyAt(i);
-                    UserRecord userRecord = mUserRecords.valueAt(i);
+                // disposeUserIfNeededLocked might modify the collection, hence clone
+                final var userRecords = mUserRecords.clone();
+                for (int i = 0; i < userRecords.size(); i++) {
+                    int userId = userRecords.keyAt(i);
+                    UserRecord userRecord = userRecords.valueAt(i);
                     if (isUserActiveLocked(userId)) {
                         // userId corresponds to the active user, or one of its profiles. We
                         // ensure the associated structures are initialized.
@@ -771,6 +792,31 @@
                         routerRecord.mUserRecord.mHandler));
     }
 
+    @GuardedBy("mLock")
+    private void setRouteListingPreferenceLocked(
+            RouterRecord routerRecord, @Nullable RouteListingPreference routeListingPreference) {
+        routerRecord.mRouteListingPreference = routeListingPreference;
+        String routeListingAsString =
+                routeListingPreference != null
+                        ? routeListingPreference.getItems().stream()
+                                .map(RouteListingPreference.Item::getRouteId)
+                                .collect(Collectors.joining(","))
+                        : null;
+        mEventLogger.enqueue(
+                EventLogger.StringEvent.from(
+                        "setRouteListingPreference",
+                        "router id: %d, route listing preference: [%s]",
+                        routerRecord.mRouterId,
+                        routeListingAsString));
+
+        routerRecord.mUserRecord.mHandler.sendMessage(
+                obtainMessage(
+                        UserHandler::notifyRouteListingPreferenceChangeToManagers,
+                        routerRecord.mUserRecord.mHandler,
+                        routerRecord.mPackageName,
+                        routeListingPreference));
+    }
+
     private void setRouteVolumeWithRouter2Locked(@NonNull IMediaRouter2 router,
             @NonNull MediaRoute2Info route, int volume) {
         final IBinder binder = router.asBinder();
@@ -1021,6 +1067,15 @@
         // RouteCallback#onRoutesAdded() for system MR2 will never be called with initial routes
         // due to the lack of features.
         for (RouterRecord routerRecord : userRecord.mRouterRecords) {
+            // Send route listing preferences before discovery preferences and routes to avoid an
+            // inconsistent state where there are routes to show, but the manager thinks
+            // the app has not expressed a preference for listing.
+            userRecord.mHandler.sendMessage(
+                    obtainMessage(
+                            UserHandler::notifyRouteListingPreferenceChangeToManagers,
+                            routerRecord.mUserRecord.mHandler,
+                            routerRecord.mPackageName,
+                            routerRecord.mRouteListingPreference));
             // TODO: UserRecord <-> routerRecord, why do they reference each other?
             // How about removing mUserRecord from routerRecord?
             routerRecord.mUserRecord.mHandler.sendMessage(
@@ -1400,6 +1455,7 @@
         public final int mRouterId;
 
         public RouteDiscoveryPreference mDiscoveryPreference;
+        @Nullable public RouteListingPreference mRouteListingPreference;
 
         RouterRecord(UserRecord userRecord, IMediaRouter2 router, int uid, int pid,
                 String packageName, boolean hasConfigureWifiDisplayPermission,
@@ -1688,6 +1744,9 @@
                     indexOfRouteProviderInfoByUniqueId(provider.getUniqueId(), mLastProviderInfos);
             MediaRoute2ProviderInfo oldInfo =
                     providerInfoIndex == -1 ? null : mLastProviderInfos.get(providerInfoIndex);
+            MediaRouter2ServiceImpl mediaRouter2Service = mServiceRef.get();
+            EventLogger eventLogger =
+                    mediaRouter2Service != null ? mediaRouter2Service.mEventLogger : null;
             if (oldInfo == newInfo) {
                 // Nothing to do.
                 return;
@@ -1713,6 +1772,7 @@
             }
 
             // Add new routes to the maps.
+            ArrayList<MediaRoute2Info> addedRoutes = new ArrayList<>();
             boolean hasAddedOrModifiedRoutes = false;
             for (MediaRoute2Info newRouteInfo : newRoutes) {
                 if (!newRouteInfo.isValid()) {
@@ -1727,11 +1787,14 @@
                 MediaRoute2Info oldRouteInfo =
                         mLastNotifiedRoutesToPrivilegedRouters.put(
                                 newRouteInfo.getId(), newRouteInfo);
-                hasAddedOrModifiedRoutes |=
-                        oldRouteInfo == null || !oldRouteInfo.equals(newRouteInfo);
+                hasAddedOrModifiedRoutes |= !newRouteInfo.equals(oldRouteInfo);
+                if (oldRouteInfo == null) {
+                    addedRoutes.add(newRouteInfo);
+                }
             }
 
             // Remove stale routes from the maps.
+            ArrayList<MediaRoute2Info> removedRoutes = new ArrayList<>();
             Collection<MediaRoute2Info> oldRoutes =
                     oldInfo == null ? Collections.emptyList() : oldInfo.getRoutes();
             boolean hasRemovedRoutes = false;
@@ -1741,6 +1804,26 @@
                     hasRemovedRoutes = true;
                     mLastNotifiedRoutesToPrivilegedRouters.remove(oldRouteId);
                     mLastNotifiedRoutesToNonPrivilegedRouters.remove(oldRouteId);
+                    removedRoutes.add(oldRoute);
+                }
+            }
+
+            if (eventLogger != null) {
+                if (!addedRoutes.isEmpty()) {
+                    // If routes were added, newInfo cannot be null.
+                    eventLogger.enqueue(
+                            toLoggingEvent(
+                                    /* source= */ "addProviderRoutes",
+                                    newInfo.getUniqueId(),
+                                    addedRoutes));
+                }
+                if (!removedRoutes.isEmpty()) {
+                    // If routes were removed, oldInfo cannot be null.
+                    eventLogger.enqueue(
+                            toLoggingEvent(
+                                    /* source= */ "removeProviderRoutes",
+                                    oldInfo.getUniqueId(),
+                                    removedRoutes));
                 }
             }
 
@@ -1751,6 +1834,16 @@
                     mSystemProvider.getDefaultRoute());
         }
 
+        private static EventLogger.Event toLoggingEvent(
+                String source, String providerId, ArrayList<MediaRoute2Info> routes) {
+            String routesString =
+                    routes.stream()
+                            .map(it -> String.format("%s | %s", it.getOriginalId(), it.getName()))
+                            .collect(Collectors.joining(/* delimiter= */ ", "));
+            return EventLogger.StringEvent.from(
+                    source, "provider: %s, routes: [%s]", providerId, routesString);
+        }
+
         /**
          * Dispatches the latest route updates in {@link #mLastNotifiedRoutesToPrivilegedRouters}
          * and {@link #mLastNotifiedRoutesToNonPrivilegedRouters} to registered {@link
@@ -2427,6 +2520,34 @@
             }
         }
 
+        private void notifyRouteListingPreferenceChangeToManagers(
+                String routerPackageName, @Nullable RouteListingPreference routeListingPreference) {
+            MediaRouter2ServiceImpl service = mServiceRef.get();
+            if (service == null) {
+                return;
+            }
+            List<IMediaRouter2Manager> managers = new ArrayList<>();
+            synchronized (service.mLock) {
+                for (ManagerRecord managerRecord : mUserRecord.mManagerRecords) {
+                    managers.add(managerRecord.mManager);
+                }
+            }
+            for (IMediaRouter2Manager manager : managers) {
+                try {
+                    manager.notifyRouteListingPreferenceChange(
+                            routerPackageName, routeListingPreference);
+                } catch (RemoteException ex) {
+                    Slog.w(
+                            TAG,
+                            "Failed to notify preferred features changed."
+                                    + " Manager probably died.",
+                            ex);
+                }
+            }
+            // TODO(b/238178508): In order to support privileged media router instances, we also
+            //    need to update routers other than the one making the update.
+        }
+
         private void notifyRequestFailedToManager(@NonNull IMediaRouter2Manager manager,
                 int requestId, int reason) {
             try {
@@ -2506,7 +2627,6 @@
             }
             return null;
         }
-
     }
     static final class SessionCreationRequest {
         public final RouterRecord mRouterRecord;
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index c0340b1..beab5ea 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -17,6 +17,7 @@
 package com.android.server.media;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.app.ActivityManager;
 import android.app.UserSwitchObserver;
@@ -43,6 +44,7 @@
 import android.media.RemoteDisplayState;
 import android.media.RemoteDisplayState.RemoteDisplayInfo;
 import android.media.RouteDiscoveryPreference;
+import android.media.RouteListingPreference;
 import android.media.RoutingSessionInfo;
 import android.os.Binder;
 import android.os.Bundle;
@@ -420,6 +422,14 @@
 
     // Binder call
     @Override
+    public void setRouteListingPreference(
+            @NonNull IMediaRouter2 router,
+            @Nullable RouteListingPreference routeListingPreference) {
+        mService2.setRouteListingPreference(router, routeListingPreference);
+    }
+
+    // Binder call
+    @Override
     public void setRouteVolumeWithRouter2(IMediaRouter2 router,
             MediaRoute2Info route, int volume) {
         mService2.setRouteVolumeWithRouter2(router, route, volume);
@@ -628,9 +638,11 @@
         synchronized (mLock) {
             if (mCurrentActiveUserId != newActiveUserId) {
                 mCurrentActiveUserId = newActiveUserId;
-                for (int i = 0; i < mUserRecords.size(); i++) {
-                    int userId = mUserRecords.keyAt(i);
-                    UserRecord userRecord = mUserRecords.valueAt(i);
+                // disposeUserIfNeededLocked might modify the collection, hence clone
+                final var userRecords = mUserRecords.clone();
+                for (int i = 0; i < userRecords.size(); i++) {
+                    int userId = userRecords.keyAt(i);
+                    UserRecord userRecord = userRecords.valueAt(i);
                     if (isUserActiveLocked(userId)) {
                         // userId corresponds to the active user, or one of its profiles. We
                         // ensure the associated structures are initialized.
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index 337d5e5..f2a39b8 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -24,6 +24,8 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.server.utils.EventLogger;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
@@ -38,6 +40,8 @@
     private static final boolean DEBUG = MediaSessionService.DEBUG;
     private static final String TAG = "MediaSessionStack";
 
+    private static final int DUMP_EVENTS_MAX_COUNT = 70;
+
     /**
      * Listen the change in the media button session.
      */
@@ -57,6 +61,8 @@
     private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
     private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener;
 
+    private final EventLogger mEventLogger = new EventLogger(DUMP_EVENTS_MAX_COUNT, TAG);
+
     /**
      * The media button session which receives media key events.
      * It could be null if the previous media button session is released.
@@ -80,6 +86,11 @@
      * @param record The record to add.
      */
     public void addSession(MediaSessionRecordImpl record) {
+        mEventLogger.enqueue(EventLogger.StringEvent.from(
+                "addSession() (to bottom of stack)",
+                "record: %s",
+                record
+        ));
         mSessions.add(record);
         clearCache(record.getUserId());
 
@@ -95,6 +106,11 @@
      * @param record The record to remove.
      */
     public void removeSession(MediaSessionRecordImpl record) {
+        mEventLogger.enqueue(EventLogger.StringEvent.from(
+                "removeSession()",
+                "record: %s",
+                record
+        ));
         mSessions.remove(record);
         if (mMediaButtonSession == record) {
             // When the media button session is removed, nullify the media button session and do not
@@ -140,6 +156,11 @@
     public void onPlaybackStateChanged(
             MediaSessionRecordImpl record, boolean shouldUpdatePriority) {
         if (shouldUpdatePriority) {
+            mEventLogger.enqueue(EventLogger.StringEvent.from(
+                    "onPlaybackStateChanged() - Pushing session to top",
+                    "record: %s",
+                    record
+            ));
             mSessions.remove(record);
             mSessions.add(0, record);
             clearCache(record.getUserId());
@@ -344,6 +365,8 @@
         for (MediaSessionRecordImpl record : mSessions) {
             record.dump(pw, indent);
         }
+        pw.println(prefix + "Session stack events:");
+        mEventLogger.dump(pw, indent);
     }
 
     /**
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d6b9bd5..90135ad 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3797,13 +3797,13 @@
         }
 
         private void createNotificationChannelsImpl(String pkg, int uid,
-                ParceledListSlice channelsList, boolean fromTargetApp) {
-            createNotificationChannelsImpl(pkg, uid, channelsList, fromTargetApp,
+                ParceledListSlice channelsList) {
+            createNotificationChannelsImpl(pkg, uid, channelsList,
                     ActivityTaskManager.INVALID_TASK_ID);
         }
 
         private void createNotificationChannelsImpl(String pkg, int uid,
-                ParceledListSlice channelsList, boolean fromTargetApp, int startingTaskId) {
+                ParceledListSlice channelsList, int startingTaskId) {
             List<NotificationChannel> channels = channelsList.getList();
             final int channelsSize = channels.size();
             ParceledListSlice<NotificationChannel> oldChannels =
@@ -3815,7 +3815,7 @@
                 final NotificationChannel channel = channels.get(i);
                 Objects.requireNonNull(channel, "channel in list is null");
                 needsPolicyFileChange = mPreferencesHelper.createNotificationChannel(pkg, uid,
-                        channel, fromTargetApp,
+                        channel, true /* fromTargetApp */,
                         mConditionProviders.isPackageOrComponentAllowed(
                                 pkg, UserHandle.getUserId(uid)));
                 if (needsPolicyFileChange) {
@@ -3851,7 +3851,6 @@
         @Override
         public void createNotificationChannels(String pkg, ParceledListSlice channelsList) {
             checkCallerIsSystemOrSameApp(pkg);
-            boolean fromTargetApp = !isCallerSystemOrPhone();  // if not system, it's from the app
             int taskId = ActivityTaskManager.INVALID_TASK_ID;
             try {
                 int uid = mPackageManager.getPackageUid(pkg, 0,
@@ -3860,15 +3859,14 @@
             } catch (RemoteException e) {
                 // Do nothing
             }
-            createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, fromTargetApp,
-                    taskId);
+            createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList, taskId);
         }
 
         @Override
         public void createNotificationChannelsForPackage(String pkg, int uid,
                 ParceledListSlice channelsList) {
             enforceSystemOrSystemUI("only system can call this");
-            createNotificationChannelsImpl(pkg, uid, channelsList, false /* fromTargetApp */);
+            createNotificationChannelsImpl(pkg, uid, channelsList);
         }
 
         @Override
@@ -3883,8 +3881,7 @@
                     CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId));
             conversationChannel.setConversationId(parentId, conversationId);
             createNotificationChannelsImpl(
-                    pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel)),
-                    false /* fromTargetApp */);
+                    pkg, uid, new ParceledListSlice(Arrays.asList(conversationChannel)));
             mRankingHandler.requestSort();
             handleSavePolicyFile();
         }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 444fef6..1bbcc83 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -918,7 +918,7 @@
                 throw new IllegalArgumentException("Reserved id");
             }
             NotificationChannel existing = r.channels.get(channel.getId());
-            if (existing != null) {
+            if (existing != null && fromTargetApp) {
                 // Actually modifying an existing channel - keep most of the existing settings
                 if (existing.isDeleted()) {
                     // The existing channel was deleted - undelete it.
@@ -1004,7 +1004,9 @@
                 }
                 if (fromTargetApp) {
                     channel.setLockscreenVisibility(r.visibility);
-                    channel.setAllowBubbles(NotificationChannel.DEFAULT_ALLOW_BUBBLE);
+                    channel.setAllowBubbles(existing != null
+                            ? existing.getAllowBubbles()
+                            : NotificationChannel.DEFAULT_ALLOW_BUBBLE);
                 }
                 clearLockedFieldsLocked(channel);
 
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 3421eb7..79f2b3f 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -379,6 +379,8 @@
             final String packageName = data.getSchemeSpecificPart();
 
             final boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+            final boolean systemUpdateUninstall =
+                    intent.getBooleanExtra(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, false);
 
             final int[] userIds;
             final int extraUid = intent.getIntExtra(Intent.EXTRA_UID, UserHandle.USER_NULL);
@@ -405,7 +407,7 @@
                     break;
                 case ACTION_PACKAGE_REMOVED:
                     if (replacing) {
-                        onPackageReplacing(packageName, userIds);
+                        onPackageReplacing(packageName, systemUpdateUninstall, userIds);
                     } else {
                         onPackageRemoved(packageName, userIds);
                     }
@@ -463,7 +465,7 @@
         }
 
         private void onPackageReplacing(@NonNull final String packageName,
-                @NonNull final int[] userIds) {
+                boolean systemUpdateUninstall, @NonNull final int[] userIds) {
             try {
                 traceBegin(TRACE_TAG_RRO, "OMS#onPackageReplacing " + packageName);
                 for (int userId : userIds) {
@@ -472,8 +474,8 @@
                                 packageName, userId);
                         if (pkg != null && !mPackageManager.isInstantApp(packageName, userId)) {
                             try {
-                                updateTargetPackagesLocked(
-                                        mImpl.onPackageReplacing(packageName, userId));
+                                updateTargetPackagesLocked(mImpl.onPackageReplacing(packageName,
+                                        systemUpdateUninstall, userId));
                             } catch (OperationFailedException e) {
                                 Slog.e(TAG, "onPackageReplacing internal error", e);
                             }
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 6ffe60d..9d5830c 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -21,6 +21,7 @@
 import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
 import static android.content.om.OverlayInfo.STATE_NO_IDMAP;
 import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED;
+import static android.content.om.OverlayInfo.STATE_SYSTEM_UPDATE_UNINSTALL;
 import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
 import static android.os.UserHandle.USER_SYSTEM;
 
@@ -78,6 +79,7 @@
 
     // Flags to use in conjunction with updateState.
     private static final int FLAG_OVERLAY_IS_BEING_REPLACED = 1 << 1;
+    private static final int FLAG_SYSTEM_UPDATE_UNINSTALL = 1 << 2;
 
     private final PackageManagerHelper mPackageManager;
     private final IdmapManager mIdmapManager;
@@ -275,9 +277,13 @@
     }
 
     @NonNull
-    Set<UserPackage> onPackageReplacing(@NonNull final String pkgName, final int userId)
-            throws OperationFailedException {
-        return reconcileSettingsForPackage(pkgName, userId, FLAG_OVERLAY_IS_BEING_REPLACED);
+    Set<UserPackage> onPackageReplacing(@NonNull final String pkgName,
+            boolean systemUpdateUninstall, final int userId) throws OperationFailedException {
+        int flags = FLAG_OVERLAY_IS_BEING_REPLACED;
+        if (systemUpdateUninstall) {
+            flags |= FLAG_SYSTEM_UPDATE_UNINSTALL;
+        }
+        return reconcileSettingsForPackage(pkgName, userId, flags);
     }
 
     @NonNull
@@ -840,6 +846,10 @@
             return STATE_OVERLAY_IS_BEING_REPLACED;
         }
 
+        if ((flags & FLAG_SYSTEM_UPDATE_UNINSTALL) != 0) {
+            return STATE_SYSTEM_UPDATE_UNINSTALL;
+        }
+
         if (targetPackage == null) {
             return STATE_MISSING_TARGET;
         }
diff --git a/services/core/java/com/android/server/pm/AppDataHelper.java b/services/core/java/com/android/server/pm/AppDataHelper.java
index f3cfa95..b8bdabe 100644
--- a/services/core/java/com/android/server/pm/AppDataHelper.java
+++ b/services/core/java/com/android/server/pm/AppDataHelper.java
@@ -213,7 +213,7 @@
 
         final int appId = UserHandle.getAppId(pkg.getUid());
 
-        String pkgSeInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
+        String pkgSeInfo = ps.getSeInfo();
 
         Preconditions.checkNotNull(pkgSeInfo);
 
diff --git a/services/core/java/com/android/server/pm/AppStateHelper.java b/services/core/java/com/android/server/pm/AppStateHelper.java
new file mode 100644
index 0000000..9ea350f
--- /dev/null
+++ b/services/core/java/com/android/server/pm/AppStateHelper.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pm;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.content.Context;
+import android.media.IAudioService;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.ArraySet;
+
+import com.android.internal.util.ArrayUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class to provide queries for app states concerning gentle-update.
+ */
+public class AppStateHelper {
+    private final Context mContext;
+
+    public AppStateHelper(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * True if the package is loaded into the process.
+     */
+    private static boolean isPackageLoaded(RunningAppProcessInfo info, String packageName) {
+        return ArrayUtils.contains(info.pkgList, packageName)
+                || ArrayUtils.contains(info.pkgDeps, packageName);
+    }
+
+    /**
+     * Returns the importance of the given package.
+     */
+    private int getImportance(String packageName) {
+        var am = mContext.getSystemService(ActivityManager.class);
+        return am.getPackageImportance(packageName);
+    }
+
+    /**
+     * True if the app owns the audio focus.
+     */
+    private boolean hasAudioFocus(String packageName) {
+        var audioService = IAudioService.Stub.asInterface(
+                ServiceManager.getService(Context.AUDIO_SERVICE));
+        try {
+            var focusInfos = audioService.getFocusStack();
+            int size = focusInfos.size();
+            var audioFocusPackage = (size > 0) ? focusInfos.get(size - 1).getPackageName() : null;
+            return TextUtils.equals(packageName, audioFocusPackage);
+        } catch (Exception ignore) {
+        }
+        return false;
+    }
+
+    /**
+     * True if the app is in the foreground.
+     */
+    private boolean isAppForeground(String packageName) {
+        return getImportance(packageName) <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
+    }
+
+    /**
+     * True if the app is currently at the top of the screen that the user is interacting with.
+     */
+    public boolean isAppTopVisible(String packageName) {
+        return getImportance(packageName) <= RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+    }
+
+    /**
+     * True if the app is playing/recording audio.
+     */
+    private boolean hasActiveAudio(String packageName) {
+        // TODO(b/235306967): also check recording
+        return hasAudioFocus(packageName);
+    }
+
+    /**
+     * True if the app is sending or receiving network data.
+     */
+    private boolean hasActiveNetwork(String packageName) {
+        // To be implemented
+        return false;
+    }
+
+    /**
+     * True if any app is interacting with the user.
+     */
+    public boolean hasInteractingApp(List<String> packageNames) {
+        for (var packageName : packageNames) {
+            if (hasActiveAudio(packageName)
+                    || hasActiveNetwork(packageName)
+                    || isAppTopVisible(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * True if any app is in the foreground.
+     */
+    public boolean hasForegroundApp(List<String> packageNames) {
+        for (var packageName : packageNames) {
+            if (isAppForeground(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * True if any app is top visible.
+     */
+    public boolean hasTopVisibleApp(List<String> packageNames) {
+        for (var packageName : packageNames) {
+            if (isAppTopVisible(packageName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * True if there is an ongoing phone call.
+     */
+    public boolean isInCall() {
+        // To be implemented
+        return false;
+    }
+
+    /**
+     * Returns a list of packages which depend on {@code packageNames}. These are the packages
+     * that will be affected when updating {@code packageNames} and should participate in
+     * the evaluation of install constraints.
+     *
+     * TODO(b/235306967): Also include bounded services as dependency.
+     */
+    public List<String> getDependencyPackages(List<String> packageNames) {
+        var results = new ArraySet<String>();
+        var am = mContext.getSystemService(ActivityManager.class);
+        for (var info : am.getRunningAppProcesses()) {
+            for (var packageName : packageNames) {
+                if (!isPackageLoaded(info, packageName)) {
+                    continue;
+                }
+                for (var pkg : info.pkgList) {
+                    results.add(pkg);
+                }
+            }
+        }
+        return new ArrayList<>(results);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index dd41830..cda7503 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -92,6 +92,8 @@
             new ComponentName("android", BackgroundDexOptJobService.class.getName());
 
     // Possible return codes of individual optimization steps.
+    /** Initial value. */
+    public static final int STATUS_UNSPECIFIED = -1;
     /** Ok status: Optimizations finished, All packages were processed, can continue */
     public static final int STATUS_OK = 0;
     /** Optimizations should be aborted. Job scheduler requested it. */
@@ -108,16 +110,20 @@
      * job will exclude those failed packages.
      */
     public static final int STATUS_DEX_OPT_FAILED = 5;
+    /** Encountered fatal error, such as a runtime exception. */
+    public static final int STATUS_FATAL_ERROR = 6;
 
     @IntDef(prefix = {"STATUS_"},
             value =
                     {
+                            STATUS_UNSPECIFIED,
                             STATUS_OK,
                             STATUS_ABORT_BY_CANCELLATION,
                             STATUS_ABORT_NO_SPACE_LEFT,
                             STATUS_ABORT_THERMAL,
                             STATUS_ABORT_BATTERY,
                             STATUS_DEX_OPT_FAILED,
+                            STATUS_FATAL_ERROR,
                     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface Status {}
@@ -153,7 +159,7 @@
     // True if JobScheduler invocations of dexopt have been disabled.
     @GuardedBy("mLock") private boolean mDisableJobSchedulerJobs;
 
-    @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_OK;
+    @GuardedBy("mLock") @Status private int mLastExecutionStatus = STATUS_UNSPECIFIED;
 
     @GuardedBy("mLock") private long mLastExecutionStartUptimeMs;
     @GuardedBy("mLock") private long mLastExecutionDurationMs;
@@ -561,18 +567,26 @@
     private boolean runIdleOptimization(
             PackageManagerService pm, List<String> pkgs, boolean isPostBootUpdate) {
         synchronized (mLock) {
+            mLastExecutionStatus = STATUS_UNSPECIFIED;
             mLastExecutionStartUptimeMs = SystemClock.uptimeMillis();
             mLastExecutionDurationMs = -1;
         }
-        long lowStorageThreshold = getLowStorageThreshold();
-        int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate);
-        logStatus(status);
-        synchronized (mLock) {
-            mLastExecutionStatus = status;
-            mLastExecutionDurationMs = SystemClock.uptimeMillis() - mLastExecutionStartUptimeMs;
-        }
 
-        return status == STATUS_OK || status == STATUS_DEX_OPT_FAILED;
+        int status = STATUS_UNSPECIFIED;
+        try {
+            long lowStorageThreshold = getLowStorageThreshold();
+            status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate);
+            logStatus(status);
+            return status == STATUS_OK || status == STATUS_DEX_OPT_FAILED;
+        } catch (RuntimeException e) {
+            status = STATUS_FATAL_ERROR;
+            throw e;
+        } finally {
+            synchronized (mLock) {
+                mLastExecutionStatus = status;
+                mLastExecutionDurationMs = SystemClock.uptimeMillis() - mLastExecutionStartUptimeMs;
+            }
+        }
     }
 
     /** Gets the size of the directory. It uses recursion to go over all files. */
diff --git a/services/core/java/com/android/server/pm/GentleUpdateHelper.java b/services/core/java/com/android/server/pm/GentleUpdateHelper.java
new file mode 100644
index 0000000..247ac90
--- /dev/null
+++ b/services/core/java/com/android/server/pm/GentleUpdateHelper.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pm;
+
+import android.annotation.WorkerThread;
+import android.app.ActivityThread;
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageInstaller.InstallConstraints;
+import android.content.pm.PackageInstaller.InstallConstraintsResult;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.Slog;
+
+import java.util.ArrayDeque;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A helper class to coordinate install flow for sessions with install constraints.
+ * These sessions will be pending and wait until the constraints are satisfied to
+ * resume installation.
+ */
+public class GentleUpdateHelper {
+    private static final String TAG = "GentleUpdateHelper";
+    private static final int JOB_ID = 235306967; // bug id
+    // The timeout used to determine whether the device is idle or not.
+    private static final long PENDING_CHECK_MILLIS = TimeUnit.SECONDS.toMillis(10);
+
+    /**
+     * A wrapper class used by JobScheduler to schedule jobs.
+     */
+    public static class Service extends JobService {
+        @Override
+        public boolean onStartJob(JobParameters params) {
+            try {
+                var pis = (PackageInstallerService) ActivityThread.getPackageManager()
+                        .getPackageInstaller();
+                var helper = pis.getGentleUpdateHelper();
+                helper.mHandler.post(helper::runIdleJob);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to get PackageInstallerService", e);
+            }
+            return false;
+        }
+
+        @Override
+        public boolean onStopJob(JobParameters params) {
+            return false;
+        }
+    }
+
+    private static class PendingInstallConstraintsCheck {
+        public final List<String> packageNames;
+        public final InstallConstraints constraints;
+        public final CompletableFuture<InstallConstraintsResult> future;
+        PendingInstallConstraintsCheck(List<String> packageNames,
+                InstallConstraints constraints,
+                CompletableFuture<InstallConstraintsResult> future) {
+            this.packageNames = packageNames;
+            this.constraints = constraints;
+            this.future = future;
+        }
+    }
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final AppStateHelper mAppStateHelper;
+    // Worker thread only
+    private final ArrayDeque<PendingInstallConstraintsCheck> mPendingChecks = new ArrayDeque<>();
+    private boolean mHasPendingIdleJob;
+
+    GentleUpdateHelper(Context context, Looper looper, AppStateHelper appStateHelper) {
+        mContext = context;
+        mHandler = new Handler(looper);
+        mAppStateHelper = appStateHelper;
+    }
+
+    /**
+     * Checks if install constraints are satisfied for the given packages.
+     */
+    CompletableFuture<InstallConstraintsResult> checkInstallConstraints(
+            List<String> packageNames, InstallConstraints constraints) {
+        var future = new CompletableFuture<InstallConstraintsResult>();
+        mHandler.post(() -> {
+            var pendingCheck = new PendingInstallConstraintsCheck(
+                    packageNames, constraints, future);
+            if (constraints.isRequireDeviceIdle()) {
+                mPendingChecks.add(pendingCheck);
+                // JobScheduler doesn't provide queries about whether the device is idle.
+                // We schedule 2 tasks to determine device idle. If the idle job is executed
+                // before the delayed runnable, we know the device is idle.
+                // Note #processPendingCheck will be no-op for the task executed later.
+                scheduleIdleJob();
+                mHandler.postDelayed(() -> processPendingCheck(pendingCheck, false),
+                        PENDING_CHECK_MILLIS);
+            } else {
+                processPendingCheck(pendingCheck, false);
+            }
+        });
+        return future;
+    }
+
+    @WorkerThread
+    private void scheduleIdleJob() {
+        if (mHasPendingIdleJob) {
+            // No need to schedule the job again
+            return;
+        }
+        mHasPendingIdleJob = true;
+        var componentName = new ComponentName(
+                mContext.getPackageName(), GentleUpdateHelper.Service.class.getName());
+        var jobInfo = new JobInfo.Builder(JOB_ID, componentName)
+                .setRequiresDeviceIdle(true)
+                .build();
+        var jobScheduler = mContext.getSystemService(JobScheduler.class);
+        jobScheduler.schedule(jobInfo);
+    }
+
+    @WorkerThread
+    private void runIdleJob() {
+        mHasPendingIdleJob = false;
+        processPendingChecksInIdle();
+    }
+
+    @WorkerThread
+    private void processPendingCheck(PendingInstallConstraintsCheck pendingCheck, boolean isIdle) {
+        var future = pendingCheck.future;
+        if (future.isDone()) {
+            return;
+        }
+        var constraints = pendingCheck.constraints;
+        var packageNames = mAppStateHelper.getDependencyPackages(pendingCheck.packageNames);
+        var constraintsSatisfied = (!constraints.isRequireDeviceIdle() || isIdle)
+                && (!constraints.isRequireAppNotForeground()
+                        || !mAppStateHelper.hasForegroundApp(packageNames))
+                && (!constraints.isRequireAppNotInteracting()
+                        || !mAppStateHelper.hasInteractingApp(packageNames))
+                && (!constraints.isRequireAppNotTopVisible()
+                        || !mAppStateHelper.hasTopVisibleApp(packageNames))
+                && (!constraints.isRequireNotInCall()
+                        || !mAppStateHelper.isInCall());
+        future.complete(new InstallConstraintsResult((constraintsSatisfied)));
+    }
+
+    @WorkerThread
+    private void processPendingChecksInIdle() {
+        while (!mPendingChecks.isEmpty()) {
+            processPendingCheck(mPendingChecks.remove(), true);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/pm/InstallArgs.java b/services/core/java/com/android/server/pm/InstallArgs.java
index a94a4e2..ced547c 100644
--- a/services/core/java/com/android/server/pm/InstallArgs.java
+++ b/services/core/java/com/android/server/pm/InstallArgs.java
@@ -59,6 +59,7 @@
     final boolean mForceQueryableOverride;
     final int mDataLoaderType;
     final int mPackageSource;
+    final boolean mKeepApplicationEnabledSetting;
 
     // The list of instruction sets supported by this app. This is currently
     // only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -72,7 +73,8 @@
             List<String> allowlistedRestrictedPermissions,
             int autoRevokePermissionsMode, String traceMethod, int traceCookie,
             SigningDetails signingDetails, int installReason, int installScenario,
-            boolean forceQueryableOverride, int dataLoaderType, int packageSource) {
+            boolean forceQueryableOverride, int dataLoaderType, int packageSource,
+            boolean keepApplicationEnabledSetting) {
         mOriginInfo = originInfo;
         mMoveInfo = moveInfo;
         mInstallFlags = installFlags;
@@ -93,6 +95,7 @@
         mForceQueryableOverride = forceQueryableOverride;
         mDataLoaderType = dataLoaderType;
         mPackageSource = packageSource;
+        mKeepApplicationEnabledSetting = keepApplicationEnabledSetting;
     }
 
     /**
@@ -104,7 +107,7 @@
                 null, null, instructionSets, null, null, null, MODE_DEFAULT, null, 0,
                 SigningDetails.UNKNOWN, PackageManager.INSTALL_REASON_UNKNOWN,
                 PackageManager.INSTALL_SCENARIO_DEFAULT, false, DataLoaderType.NONE,
-                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED);
+                PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED, false);
         mCodeFile = (codePath != null) ? new File(codePath) : null;
     }
 
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index b02d1a8..7553370 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -20,6 +20,7 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 import static android.content.pm.PackageManager.INSTALL_FAILED_ALREADY_EXISTS;
 import static android.content.pm.PackageManager.INSTALL_FAILED_BAD_PERMISSION_GROUP;
+import static android.content.pm.PackageManager.INSTALL_FAILED_DEPRECATED_SDK_VERSION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PACKAGE;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION;
 import static android.content.pm.PackageManager.INSTALL_FAILED_DUPLICATE_PERMISSION_GROUP;
@@ -136,6 +137,7 @@
 import android.os.incremental.IncrementalStorage;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
+import android.provider.DeviceConfig;
 import android.stats.storage.StorageEnums;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -763,7 +765,7 @@
                 || (installFlags & PackageManager.INSTALL_REQUEST_DOWNGRADE) != 0);
 
         if (ps != null && doSnapshotOrRestore) {
-            final String seInfo = AndroidPackageUtils.getSeInfo(request.getPkg(), ps);
+            final String seInfo = ps.getSeInfo();
             final RollbackManagerInternal rollbackManager =
                     mInjector.getLocalService(RollbackManagerInternal.class);
             rollbackManager.snapshotAndRestoreUserData(packageName,
@@ -1017,6 +1019,28 @@
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
+        // If the minimum installable SDK version enforcement is enabled, block the install
+        // of apps using a lower target SDK version than required. This helps improve security
+        // and privacy as malware can target older SDK versions to avoid enforcement of new API
+        // behavior.
+        if (DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                "MinInstallableTargetSdk__install_block_enabled",
+                false)) {
+            int minInstallableTargetSdk =
+                    DeviceConfig.getInt(DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE,
+                            "MinInstallableTargetSdk__min_installable_target_sdk",
+                            0);
+            if (parsedPackage.getTargetSdkVersion() < minInstallableTargetSdk) {
+                Slog.w(TAG, "App " + parsedPackage.getPackageName()
+                        + " targets deprecated sdk version");
+                throw new PrepareFailure(INSTALL_FAILED_DEPRECATED_SDK_VERSION,
+                        "App package must target at least version "
+                                + minInstallableTargetSdk);
+            }
+        } else {
+            Slog.i(TAG, "Minimum installable target sdk enforcement not enabled");
+        }
+
         // Instant apps have several additional install-time checks.
         if (instantApp) {
             if (parsedPackage.getTargetSdkVersion() < Build.VERSION_CODES.O) {
@@ -2020,7 +2044,8 @@
                         Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName);
                     }
                     // Enable system package for requested users
-                    if (installedForUsers != null) {
+                    if (installedForUsers != null
+                            && !installRequest.isKeepApplicationEnabledSetting()) {
                         for (int origUserId : installedForUsers) {
                             if (userId == UserHandle.USER_ALL || userId == origUserId) {
                                 ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT,
@@ -2070,16 +2095,22 @@
 
                 if (userId != UserHandle.USER_ALL) {
                     // It's implied that when a user requests installation, they want the app to
-                    // be installed and enabled.
+                    // be installed and enabled. The caller, however, can explicitly specify to
+                    // keep the existing enabled state.
                     ps.setInstalled(true, userId);
-                    ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId, installerPackageName);
+                    if (!installRequest.isKeepApplicationEnabledSetting()) {
+                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
+                                installerPackageName);
+                    }
                 } else if (allUsers != null) {
                     // The caller explicitly specified INSTALL_ALL_USERS flag.
                     // Thus, updating the settings to install the app for all users.
                     for (int currentUserId : allUsers) {
                         ps.setInstalled(true, currentUserId);
-                        ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, userId,
-                                installerPackageName);
+                        if (!installRequest.isKeepApplicationEnabledSetting()) {
+                            ps.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, currentUserId,
+                                    installerPackageName);
+                        }
                     }
                 }
 
@@ -2228,20 +2259,26 @@
                 incrementalStorages.add(storage);
             }
 
-            try {
-                if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) {
-                    VerityUtils.setUpFsverity(pkg.getBaseApkPath(), (byte[]) null);
-                }
-                for (String path : pkg.getSplitCodePaths()) {
-                    if (!VerityUtils.hasFsverity(path)) {
-                        VerityUtils.setUpFsverity(path, (byte[]) null);
-                    }
-                }
-            } catch (IOException e) {
-                // There's nothing we can do if the setup failed. Since fs-verity is
-                // optional, just ignore the error for now.
-                Slog.e(TAG, "Failed to fully enable fs-verity to " + packageName);
+            // Enabling fs-verity is a blocking operation. To reduce the impact to the install time,
+            // run in a background thread.
+            final ArrayList<String> apkPaths = new ArrayList<>();
+            apkPaths.add(pkg.getBaseApkPath());
+            if (pkg.getSplitCodePaths() != null) {
+                Collections.addAll(apkPaths, pkg.getSplitCodePaths());
             }
+            mInjector.getBackgroundHandler().post(() -> {
+                try {
+                    for (String path : apkPaths) {
+                        if (!VerityUtils.hasFsverity(path)) {
+                            VerityUtils.setUpFsverity(path, (byte[]) null);
+                        }
+                    }
+                } catch (IOException e) {
+                    // There's nothing we can do if the setup failed. Since fs-verity is
+                    // optional, just ignore the error for now.
+                    Slog.e(TAG, "Failed to fully enable fs-verity to " + packageName);
+                }
+            });
 
             // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088)
             mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0);
@@ -3892,13 +3929,20 @@
                 && !pkgSetting.getPathString().equals(parsedPackage.getPath());
         final boolean newPkgVersionGreater = pkgAlreadyExists
                 && parsedPackage.getLongVersionCode() > pkgSetting.getVersionCode();
+        final boolean newSharedUserSetting = pkgAlreadyExists
+                && (initialScanRequest.mOldSharedUserSetting
+                != initialScanRequest.mSharedUserSetting);
         final boolean isSystemPkgBetter = scanSystemPartition && isSystemPkgUpdated
-                && newPkgChangedPaths && newPkgVersionGreater;
+                && newPkgChangedPaths && (newPkgVersionGreater || newSharedUserSetting);
         if (isSystemPkgBetter) {
             // The version of the application on /system is greater than the version on
             // /data. Switch back to the application on /system.
             // It's safe to assume the application on /system will correctly scan. If not,
             // there won't be a working copy of the application.
+            // Also, if the sharedUserSetting of the application on /system is different
+            // from the sharedUserSetting on /data, switch back to the application on /system.
+            // We should trust the sharedUserSetting on /system, even if the application
+            // version on /system is smaller than the version on /data.
             synchronized (mPm.mLock) {
                 // just remove the loaded entries from package lists
                 mPm.mPackages.remove(pkgSetting.getPackageName());
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index 71571dc..5974a9c 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -128,7 +128,8 @@
                 params.mAutoRevokePermissionsMode,
                 params.mTraceMethod, params.mTraceCookie, params.mSigningDetails,
                 params.mInstallReason, params.mInstallScenario, params.mForceQueryableOverride,
-                params.mDataLoaderType, params.mPackageSource);
+                params.mDataLoaderType, params.mPackageSource,
+                params.mKeepApplicationEnabledSetting);
         mPackageMetrics = new PackageMetrics(this);
         mIsInstallInherit = params.mIsInherit;
         mSessionId = params.mSessionId;
@@ -498,6 +499,10 @@
         return mScanResult.mChangedAbiCodePath;
     }
 
+    public boolean isKeepApplicationEnabledSetting() {
+        return mInstallArgs == null ? false : mInstallArgs.mKeepApplicationEnabledSetting;
+    }
+
     public boolean isForceQueryableOverride() {
         return mInstallArgs != null && mInstallArgs.mForceQueryableOverride;
     }
diff --git a/services/core/java/com/android/server/pm/InstallingSession.java b/services/core/java/com/android/server/pm/InstallingSession.java
index 69ced1b..2b6398a 100644
--- a/services/core/java/com/android/server/pm/InstallingSession.java
+++ b/services/core/java/com/android/server/pm/InstallingSession.java
@@ -98,6 +98,7 @@
     final boolean mIsInherit;
     final int mSessionId;
     final int mRequireUserAction;
+    final boolean mKeepApplicationEnabledSetting;
 
     // For move install
     InstallingSession(OriginInfo originInfo, MoveInfo moveInfo, IPackageInstallObserver2 observer,
@@ -130,6 +131,7 @@
         mIsInherit = false;
         mSessionId = -1;
         mRequireUserAction = USER_ACTION_UNSPECIFIED;
+        mKeepApplicationEnabledSetting = false;
     }
 
     InstallingSession(int sessionId, File stagedDir, IPackageInstallObserver2 observer,
@@ -163,6 +165,7 @@
         mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING;
         mSessionId = sessionId;
         mRequireUserAction = sessionParams.requireUserAction;
+        mKeepApplicationEnabledSetting = sessionParams.keepApplicationEnabledSetting;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/MovePackageHelper.java b/services/core/java/com/android/server/pm/MovePackageHelper.java
index b27373e..b66c6ac 100644
--- a/services/core/java/com/android/server/pm/MovePackageHelper.java
+++ b/services/core/java/com/android/server/pm/MovePackageHelper.java
@@ -129,7 +129,7 @@
         final InstallSource installSource = packageState.getInstallSource();
         final String packageAbiOverride = packageState.getCpuAbiOverride();
         final int appId = UserHandle.getAppId(pkg.getUid());
-        final String seinfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
+        final String seinfo = packageState.getSeInfo();
         final String label = String.valueOf(pm.getApplicationLabel(
                 AndroidPackageUtils.generateAppInfoWithoutState(pkg)));
         final int targetSdkVersion = pkg.getTargetSdkVersion();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 226a27e..49f3a3c 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -493,7 +493,7 @@
             // TODO: Consider adding 2 different APIs for primary and secondary dexopt.
             // installd only uses downgrade flag for secondary dex files and ignores it for
             // primary dex files.
-            String seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
+            String seInfo = pkgSetting.getSeInfo();
             boolean completed = getInstallerLI().dexopt(path, uid, pkg.getPackageName(), isa,
                     dexoptNeeded, oatDir, dexoptFlags, compilerFilter, pkg.getVolumeUuid(),
                     classLoaderContext, seInfo, /* downgrade= */ false ,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index 653a882..409d352 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -44,6 +44,7 @@
 import android.content.pm.IPackageInstallerSession;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.InstallConstraints;
 import android.content.pm.PackageInstaller.SessionInfo;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageItemInfo;
@@ -54,12 +55,14 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
+import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SELinux;
@@ -88,6 +91,7 @@
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.util.ImageUtils;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.Preconditions;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.IoThread;
@@ -186,6 +190,7 @@
 
     private final InternalCallback mInternalCallback = new InternalCallback();
     private final PackageSessionVerifier mSessionVerifier;
+    private final GentleUpdateHelper mGentleUpdateHelper;
 
     /**
      * Used for generating session IDs. Since this is created at boot time,
@@ -272,6 +277,8 @@
         mStagingManager = new StagingManager(context);
         mSessionVerifier = new PackageSessionVerifier(context, mPm, mApexManager,
                 apexParserSupplier, mInstallThread.getLooper());
+        mGentleUpdateHelper = new GentleUpdateHelper(
+                context, mInstallThread.getLooper(), new AppStateHelper(context));
 
         LocalServices.getService(SystemServiceManager.class).startService(
                 new Lifecycle(context, this));
@@ -1233,6 +1240,33 @@
     }
 
     @Override
+    public void checkInstallConstraints(String installerPackageName, List<String> packageNames,
+            InstallConstraints constraints, RemoteCallback callback) {
+        Preconditions.checkArgument(packageNames != null);
+        Preconditions.checkArgument(constraints != null);
+        Preconditions.checkArgument(callback != null);
+
+        final var snapshot = mPm.snapshotComputer();
+        final int callingUid = Binder.getCallingUid();
+        if (!isCalledBySystemOrShell(callingUid)) {
+            for (var packageName : packageNames) {
+                var ps = snapshot.getPackageStateInternal(packageName);
+                if (ps == null || !TextUtils.equals(
+                        ps.getInstallSource().mInstallerPackageName, installerPackageName)) {
+                    throw new SecurityException("Caller has no access to package " + packageName);
+                }
+            }
+        }
+
+        var future = mGentleUpdateHelper.checkInstallConstraints(packageNames, constraints);
+        future.thenAccept(result -> {
+            var b = new Bundle();
+            b.putParcelable("result", result);
+            callback.sendResult(b);
+        });
+    }
+
+    @Override
     public void registerCallback(IPackageInstallerCallback callback, int userId) {
         final Computer snapshot = mPm.snapshotComputer();
         snapshot.enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
@@ -1265,6 +1299,11 @@
     }
 
     @Override
+    public GentleUpdateHelper getGentleUpdateHelper() {
+        return mGentleUpdateHelper;
+    }
+
+    @Override
     public void bypassNextStagedInstallerCheck(boolean value) {
         if (!isCalledBySystemOrShell(Binder.getCallingUid())) {
             throw new SecurityException("Caller not allowed to bypass staged installer check");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 2ee12bf..3983acf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -269,6 +269,8 @@
     private static final String ATTR_SIGNATURE = "signature";
     private static final String ATTR_CHECKSUM_KIND = "checksumKind";
     private static final String ATTR_CHECKSUM_VALUE = "checksumValue";
+    private static final String ATTR_KEEP_APPLICATION_ENABLED_SETTING =
+            "keepApplicationEnabledSetting";
 
     private static final String PROPERTY_NAME_INHERIT_NATIVE = "pi.inherit_native_on_dont_kill";
     private static final int[] EMPTY_CHILD_SESSION_ARRAY = EmptyArray.INT;
@@ -1098,6 +1100,7 @@
             info.requireUserAction = params.requireUserAction;
             info.installerUid = mInstallerUid;
             info.packageSource = params.packageSource;
+            info.keepApplicationEnabledSetting = params.keepApplicationEnabledSetting;
         }
         return info;
     }
@@ -4310,6 +4313,11 @@
         mPreapprovalRequested.set(true);
     }
 
+    @Override
+    public boolean isKeepApplicationEnabledSetting() {
+        return params.keepApplicationEnabledSetting;
+    }
+
     void setSessionReady() {
         synchronized (mLock) {
             // Do not allow destroyed/failed session to change state
@@ -4691,6 +4699,8 @@
             writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
             writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
             out.attributeInt(null, ATTR_INSTALL_REASON, params.installReason);
+            writeBooleanAttribute(out, ATTR_KEEP_APPLICATION_ENABLED_SETTING,
+                    params.keepApplicationEnabledSetting);
 
             final boolean isDataLoader = params.dataLoaderParams != null;
             writeBooleanAttribute(out, ATTR_IS_DATALOADER, isDataLoader);
@@ -4852,6 +4862,8 @@
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.installReason = in.getAttributeInt(null, ATTR_INSTALL_REASON);
         params.packageSource = in.getAttributeInt(null, ATTR_PACKAGE_SOURCE);
+        params.keepApplicationEnabledSetting = in.getAttributeBoolean(null,
+                ATTR_KEEP_APPLICATION_ENABLED_SETTING, false);
 
         if (in.getAttributeBoolean(null, ATTR_IS_DATALOADER, false)) {
             params.dataLoaderParams = new DataLoaderParams(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 8f8cc8a..cf59a1e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1560,7 +1560,7 @@
                 AndroidPackage pkg = packageState.getPkg();
                 SharedUserApi sharedUser = snapshot.getSharedUser(
                         packageState.getSharedUserAppId());
-                String oldSeInfo = AndroidPackageUtils.getSeInfo(pkg, packageState);
+                String oldSeInfo = packageState.getSeInfo();
 
                 if (pkg == null) {
                     Slog.e(TAG, "Failed to find package " + packageName);
@@ -7317,6 +7317,7 @@
             }
 
             consumer.accept(mPackageStateMutator);
+            mPackageStateMutator.onFinished();
             onChanged();
         }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index cc1306d..e1efc61 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -3234,6 +3234,9 @@
                 case "--skip-verification":
                     sessionParams.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION;
                     break;
+                case "--skip-enable":
+                    sessionParams.setKeepApplicationEnabledSetting();
+                    break;
                 default:
                     throw new IllegalArgumentException("Unknown option " + opt);
             }
diff --git a/services/core/java/com/android/server/pm/PackageMetrics.java b/services/core/java/com/android/server/pm/PackageMetrics.java
index 3dcf926..81f1a98 100644
--- a/services/core/java/com/android/server/pm/PackageMetrics.java
+++ b/services/core/java/com/android/server/pm/PackageMetrics.java
@@ -16,6 +16,8 @@
 
 package com.android.server.pm;
 
+import static android.os.Process.INVALID_UID;
+
 import android.annotation.IntDef;
 import android.content.pm.PackageManager;
 import android.content.pm.parsing.ApkLiteParseUtils;
@@ -209,4 +211,35 @@
                 deleteFlags, PackageManager.DELETE_SUCCEEDED, info.mIsRemovedPackageSystemUpdate,
                 !info.mRemovedForAllUsers);
     }
+
+    public static void onVerificationFailed(VerifyingSession verifyingSession) {
+        FrameworkStatsLog.write(FrameworkStatsLog.PACKAGE_INSTALLATION_SESSION_REPORTED,
+                verifyingSession.getSessionId() /* session_id */,
+                null /* package_name */,
+                INVALID_UID /* uid */,
+                null /* user_ids */,
+                null /* user_types */,
+                null /* original_user_ids */,
+                null /* original_user_types */,
+                verifyingSession.getRet() /* public_return_code */,
+                0 /* internal_error_code */,
+                0 /* apks_size_bytes */,
+                0 /* version_code */,
+                null /* install_steps */,
+                null /* step_duration_millis */,
+                0 /* total_duration_millis */,
+                0 /* install_flags */,
+                verifyingSession.getInstallerPackageUid() /* installer_package_uid */,
+                INVALID_UID /* original_installer_package_uid */,
+                verifyingSession.getDataLoaderType() /* data_loader_type */,
+                verifyingSession.getUserActionRequiredType() /* user_action_required_type */,
+                verifyingSession.isInstant() /* is_instant */,
+                false /* is_replace */,
+                false /* is_system */,
+                verifyingSession.isInherit() /* is_inherit */,
+                false /* is_installing_existing_as_user */,
+                false /* is_move_install */,
+                verifyingSession.isStaged() /* is_staged */
+        );
+    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageRemovedInfo.java b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
index 4cac115..dd580a5 100644
--- a/services/core/java/com/android/server/pm/PackageRemovedInfo.java
+++ b/services/core/java/com/android/server/pm/PackageRemovedInfo.java
@@ -115,6 +115,7 @@
         final int removedUid = mRemovedAppId >= 0  ? mRemovedAppId : mUid;
         extras.putInt(Intent.EXTRA_UID, removedUid);
         extras.putBoolean(Intent.EXTRA_DATA_REMOVED, mDataRemoved);
+        extras.putBoolean(Intent.EXTRA_SYSTEM_UPDATE_UNINSTALL, mIsRemovedPackageSystemUpdate);
         extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
         extras.putBoolean(Intent.EXTRA_USER_INITIATED, !removedBySystem);
         final boolean isReplace = mIsUpdate || mIsRemovedPackageSystemUpdate;
diff --git a/services/core/java/com/android/server/pm/PackageSessionProvider.java b/services/core/java/com/android/server/pm/PackageSessionProvider.java
index ad5cf13..79b88b3 100644
--- a/services/core/java/com/android/server/pm/PackageSessionProvider.java
+++ b/services/core/java/com/android/server/pm/PackageSessionProvider.java
@@ -29,4 +29,9 @@
     PackageInstallerSession getSession(int sessionId);
 
     PackageSessionVerifier getSessionVerifier();
+
+    /**
+     * Get the GentleUpdateHelper instance.
+     */
+    GentleUpdateHelper getGentleUpdateHelper();
 }
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 6d90593..6dcbb52 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -664,7 +664,9 @@
                 mUserStates.put(other.mUserStates.keyAt(i),
                         other.mUserStates.valueAt(i).snapshot());
             } else {
-                mUserStates.put(other.mUserStates.keyAt(i), other.mUserStates.valueAt(i));
+                var userState = other.mUserStates.valueAt(i);
+                userState.setWatchable(this);
+                mUserStates.put(other.mUserStates.keyAt(i), userState);
             }
         }
 
@@ -1358,6 +1360,17 @@
     }
 
     @Nullable
+    @Override
+    public String getSeInfo() {
+        String overrideSeInfo = getTransientState().getOverrideSeInfo();
+        if (!TextUtils.isEmpty(overrideSeInfo)) {
+            return overrideSeInfo;
+        }
+
+        return getTransientState().getSeInfo();
+    }
+
+    @Nullable
     public String getPrimaryCpuAbiLegacy() {
         return mPrimaryCpuAbi;
     }
@@ -1518,10 +1531,10 @@
     }
 
     @DataClass.Generated(
-            time = 1662666062860L,
+            time = 1665779003744L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/PackageSetting.java",
-            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getUsesLibraries()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
+            inputSignatures = "private  int mSharedUserAppId\nprivate @android.annotation.Nullable java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mimeGroups\nprivate @java.lang.Deprecated @android.annotation.Nullable java.util.Set<java.lang.String> mOldCodePaths\nprivate @android.annotation.Nullable java.lang.String[] usesSdkLibraries\nprivate @android.annotation.Nullable long[] usesSdkLibrariesVersionsMajor\nprivate @android.annotation.Nullable java.lang.String[] usesStaticLibraries\nprivate @android.annotation.Nullable long[] usesStaticLibrariesVersions\nprivate @android.annotation.Nullable @java.lang.Deprecated java.lang.String legacyNativeLibraryPath\nprivate @android.annotation.NonNull java.lang.String mName\nprivate @android.annotation.Nullable java.lang.String mRealName\nprivate  int mAppId\nprivate @android.annotation.Nullable com.android.server.pm.parsing.pkg.AndroidPackageInternal pkg\nprivate @android.annotation.NonNull java.io.File mPath\nprivate @android.annotation.NonNull java.lang.String mPathString\nprivate  float mLoadingProgress\nprivate @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate  long mLastModifiedTime\nprivate  long lastUpdateTime\nprivate  long versionCode\nprivate @android.annotation.NonNull com.android.server.pm.PackageSignatures signatures\nprivate  boolean installPermissionsFixed\nprivate @android.annotation.NonNull com.android.server.pm.PackageKeySetData keySetData\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserStateImpl> mUserStates\nprivate @android.annotation.NonNull com.android.server.pm.InstallSource installSource\nprivate @android.annotation.Nullable java.lang.String volumeUuid\nprivate  int categoryOverride\nprivate  boolean updateAvailable\nprivate  boolean forceQueryableOverride\nprivate final @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized pkgState\nprivate @android.annotation.NonNull java.util.UUID mDomainSetId\nprivate final @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.PackageSetting> makeCache()\npublic  com.android.server.pm.PackageSetting snapshot()\npublic  void dumpDebug(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\npublic  com.android.server.pm.PackageSetting setAppId(int)\npublic  com.android.server.pm.PackageSetting setCpuAbiOverride(java.lang.String)\npublic  com.android.server.pm.PackageSetting setFirstInstallTimeFromReplaced(com.android.server.pm.pkg.PackageStateInternal,int[])\npublic  com.android.server.pm.PackageSetting setFirstInstallTime(long,int)\npublic  com.android.server.pm.PackageSetting setForceQueryableOverride(boolean)\npublic  com.android.server.pm.PackageSetting setInstallerPackageName(java.lang.String)\npublic  com.android.server.pm.PackageSetting setInstallSource(com.android.server.pm.InstallSource)\n  com.android.server.pm.PackageSetting removeInstallerPackage(java.lang.String)\npublic  com.android.server.pm.PackageSetting setIsOrphaned(boolean)\npublic  com.android.server.pm.PackageSetting setKeySetData(com.android.server.pm.PackageKeySetData)\npublic  com.android.server.pm.PackageSetting setLastModifiedTime(long)\npublic  com.android.server.pm.PackageSetting setLastUpdateTime(long)\npublic  com.android.server.pm.PackageSetting setLongVersionCode(long)\npublic  boolean setMimeGroup(java.lang.String,android.util.ArraySet<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPkg(com.android.server.pm.pkg.AndroidPackage)\npublic  com.android.server.pm.PackageSetting setPkgStateLibraryFiles(java.util.Collection<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setPrimaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSecondaryCpuAbi(java.lang.String)\npublic  com.android.server.pm.PackageSetting setSignatures(com.android.server.pm.PackageSignatures)\npublic  com.android.server.pm.PackageSetting setVolumeUuid(java.lang.String)\npublic @java.lang.Override boolean isExternalStorage()\npublic  com.android.server.pm.PackageSetting setUpdateAvailable(boolean)\npublic  void setSharedUserAppId(int)\npublic @java.lang.Override int getSharedUserAppId()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override java.lang.String toString()\nprotected  void copyMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  void updateFrom(com.android.server.pm.PackageSetting)\n  com.android.server.pm.PackageSetting updateMimeGroups(java.util.Set<java.lang.String>)\npublic @java.lang.Deprecated @java.lang.Override com.android.server.pm.permission.LegacyPermissionState getLegacyPermissionState()\npublic  com.android.server.pm.PackageSetting setInstallPermissionsFixed(boolean)\npublic  boolean isPrivileged()\npublic  boolean isOem()\npublic  boolean isVendor()\npublic  boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic  boolean isSystemExt()\npublic  boolean isOdm()\npublic  boolean isSystem()\npublic  android.content.pm.SigningDetails getSigningDetails()\npublic  com.android.server.pm.PackageSetting setSigningDetails(android.content.pm.SigningDetails)\npublic  void copyPackageSetting(com.android.server.pm.PackageSetting,boolean)\n @com.android.internal.annotations.VisibleForTesting com.android.server.pm.pkg.PackageUserStateImpl modifyUserState(int)\npublic  com.android.server.pm.pkg.PackageUserStateImpl getOrCreateUserState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateInternal readUserState(int)\n  void setEnabled(int,int,java.lang.String)\n  int getEnabled(int)\n  void setInstalled(boolean,int)\n  boolean getInstalled(int)\n  int getInstallReason(int)\n  void setInstallReason(int,int)\n  int getUninstallReason(int)\n  void setUninstallReason(int,int)\n @android.annotation.NonNull android.content.pm.overlay.OverlayPaths getOverlayPaths(int)\n  boolean setOverlayPathsForLibrary(java.lang.String,android.content.pm.overlay.OverlayPaths,int)\n  boolean isAnyInstalled(int[])\n  int[] queryInstalledUsers(int[],boolean)\n  long getCeDataInode(int)\n  void setCeDataInode(long,int)\n  boolean getStopped(int)\n  void setStopped(boolean,int)\n  boolean getNotLaunched(int)\n  void setNotLaunched(boolean,int)\n  boolean getHidden(int)\n  void setHidden(boolean,int)\n  int getDistractionFlags(int)\n  void setDistractionFlags(int,int)\npublic  boolean getInstantApp(int)\n  void setInstantApp(boolean,int)\n  boolean getVirtualPreload(int)\n  void setVirtualPreload(boolean,int)\n  void setUserState(int,long,int,boolean,boolean,boolean,boolean,int,android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>,boolean,boolean,java.lang.String,android.util.ArraySet<java.lang.String>,android.util.ArraySet<java.lang.String>,int,int,java.lang.String,java.lang.String,long)\n  void setUserState(int,com.android.server.pm.pkg.PackageUserStateInternal)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponents(int)\n  com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponents(int)\n  void setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setEnabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  void setDisabledComponentsCopy(com.android.server.utils.WatchedArraySet<java.lang.String>,int)\n  com.android.server.pm.pkg.PackageUserStateImpl modifyUserStateComponents(int,boolean,boolean)\n  void addDisabledComponent(java.lang.String,int)\n  void addEnabledComponent(java.lang.String,int)\n  boolean enableComponentLPw(java.lang.String,int)\n  boolean disableComponentLPw(java.lang.String,int)\n  boolean restoreComponentLPw(java.lang.String,int)\n  int getCurrentEnabledStateLPr(java.lang.String,int)\n  void removeUser(int)\npublic  int[] getNotInstalledUserIds()\n  void writePackageUserPermissionsProto(android.util.proto.ProtoOutputStream,long,java.util.List<android.content.pm.UserInfo>,com.android.server.pm.permission.LegacyPermissionDataProvider)\nprotected  void writeUsersInfoToProto(android.util.proto.ProtoOutputStream,long)\n  com.android.server.pm.PackageSetting setPath(java.io.File)\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideNonLocalizedLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer,int)\npublic  void resetOverrideComponentLabelIcon(int)\npublic @android.annotation.Nullable java.lang.String getSplashScreenTheme(int)\npublic  boolean isLoading()\npublic  com.android.server.pm.PackageSetting setLoadingProgress(float)\npublic @android.annotation.NonNull @java.lang.Override long getVersionCode()\npublic @android.annotation.Nullable @java.lang.Override java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getMimeGroups()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String getPackageName()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.pm.pkg.AndroidPackage getAndroidPackage()\npublic @android.annotation.NonNull android.content.pm.SigningInfo getSigningInfo()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesSdkLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesSdkLibrariesVersionsMajor()\npublic @android.annotation.NonNull @java.lang.Override java.lang.String[] getUsesStaticLibraries()\npublic @android.annotation.NonNull @java.lang.Override long[] getUsesStaticLibrariesVersions()\npublic @android.annotation.NonNull @java.lang.Override java.util.List<com.android.server.pm.pkg.SharedLibrary> getUsesLibraries()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryInfo(android.content.pm.SharedLibraryInfo)\npublic @android.annotation.NonNull @java.lang.Override java.util.List<java.lang.String> getUsesLibraryFiles()\npublic @android.annotation.NonNull com.android.server.pm.PackageSetting addUsesLibraryFile(java.lang.String)\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @android.annotation.NonNull @java.lang.Override long[] getLastPackageUsageTime()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic  com.android.server.pm.PackageSetting setDomainSetId(java.util.UUID)\npublic  com.android.server.pm.PackageSetting setCategoryOverride(int)\npublic  com.android.server.pm.PackageSetting setLegacyNativeLibraryPath(java.lang.String)\npublic  com.android.server.pm.PackageSetting setMimeGroups(java.util.Map<java.lang.String,java.util.Set<java.lang.String>>)\npublic  com.android.server.pm.PackageSetting setOldCodePaths(java.util.Set<java.lang.String>)\npublic  com.android.server.pm.PackageSetting setUsesSdkLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesSdkLibrariesVersionsMajor(long[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibraries(java.lang.String[])\npublic  com.android.server.pm.PackageSetting setUsesStaticLibrariesVersions(long[])\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageStateUnserialized getTransientState()\npublic @android.annotation.NonNull android.util.SparseArray<? extends PackageUserStateInternal> getUserStates()\npublic  com.android.server.pm.PackageSetting addMimeTypes(java.lang.String,java.util.Set<java.lang.String>)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbi()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbi()\npublic @android.annotation.Nullable @java.lang.Override java.lang.String getSeInfo()\npublic @android.annotation.Nullable java.lang.String getPrimaryCpuAbiLegacy()\npublic @android.annotation.Nullable java.lang.String getSecondaryCpuAbiLegacy()\nclass PackageSetting extends com.android.server.pm.SettingBase implements [com.android.server.pm.pkg.PackageStateInternal]\n@com.android.internal.util.DataClass(genGetters=true, genConstructor=false, genSetters=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java
index a905df9..6572d7b 100644
--- a/services/core/java/com/android/server/pm/ScanPackageUtils.java
+++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java
@@ -265,8 +265,8 @@
             pkgSetting.getPkgState().setUpdatedSystemApp(true);
         }
 
-        parsedPackage.setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage, sharedUserSetting,
-                injector.getCompatibility()));
+        pkgSetting.getTransientState().setSeInfo(SELinuxMMAC.getSeInfo(parsedPackage,
+                sharedUserSetting, injector.getCompatibility()));
 
         if (parsedPackage.isSystem()) {
             configurePackageComponents(parsedPackage);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index a40d404..bc9f7b2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -102,7 +102,6 @@
 import com.android.server.backup.PreferredActivityBackupHelper;
 import com.android.server.pm.Installer.InstallerException;
 import com.android.server.pm.parsing.PackageInfoUtils;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.permission.LegacyPermissionDataProvider;
 import com.android.server.pm.permission.LegacyPermissionSettings;
 import com.android.server.pm.permission.LegacyPermissionState;
@@ -368,8 +367,12 @@
     @Watched(manual = true)
     private final RuntimePermissionPersistence mRuntimePermissionsPersistence;
 
+    // Current settings file.
     private final File mSettingsFilename;
-    private final File mBackupSettingsFilename;
+    // Previous settings file.
+    // Removed when the current settings file successfully stored.
+    private final File mPreviousSettingsFilename;
+
     private final File mPackageListFilename;
     private final File mStoppedPackagesFilename;
     private final File mBackupStoppedPackagesFilename;
@@ -636,7 +639,7 @@
         mRuntimePermissionsPersistence = null;
         mPermissionDataProvider = null;
         mSettingsFilename = null;
-        mBackupSettingsFilename = null;
+        mPreviousSettingsFilename = null;
         mPackageListFilename = null;
         mStoppedPackagesFilename = null;
         mBackupStoppedPackagesFilename = null;
@@ -707,7 +710,7 @@
                 |FileUtils.S_IROTH|FileUtils.S_IXOTH,
                 -1, -1);
         mSettingsFilename = new File(mSystemDir, "packages.xml");
-        mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
+        mPreviousSettingsFilename = new File(mSystemDir, "packages-backup.xml");
         mPackageListFilename = new File(mSystemDir, "packages.list");
         FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
 
@@ -748,7 +751,7 @@
         mLock = null;
         mRuntimePermissionsPersistence = r.mRuntimePermissionsPersistence;
         mSettingsFilename = null;
-        mBackupSettingsFilename = null;
+        mPreviousSettingsFilename = null;
         mPackageListFilename = null;
         mStoppedPackagesFilename = null;
         mBackupStoppedPackagesFilename = null;
@@ -2573,10 +2576,10 @@
             // to persist settings earlier. So preserve the older
             // backup for future reference since the current settings
             // might have been corrupted.
-            if (!mBackupSettingsFilename.exists()) {
-                if (!mSettingsFilename.renameTo(mBackupSettingsFilename)) {
+            if (!mPreviousSettingsFilename.exists()) {
+                if (!mSettingsFilename.renameTo(mPreviousSettingsFilename)) {
                     Slog.wtf(PackageManagerService.TAG,
-                            "Unable to backup package manager settings, "
+                            "Unable to store older package manager settings, "
                             + " current changes will be lost at reboot");
                     return;
                 }
@@ -2670,9 +2673,9 @@
             FileUtils.sync(fstr);
             fstr.close();
 
-            // New settings successfully written, old ones are no longer
-            // needed.
-            mBackupSettingsFilename.delete();
+            // New settings successfully written, old ones are no longer needed.
+            mPreviousSettingsFilename.delete();
+
             FileUtils.setPermissions(mSettingsFilename.toString(),
                     FileUtils.S_IRUSR|FileUtils.S_IWUSR
                     |FileUtils.S_IRGRP|FileUtils.S_IWGRP,
@@ -2900,7 +2903,7 @@
                 sb.append(isDebug ? " 1 " : " 0 ");
                 sb.append(dataPath);
                 sb.append(" ");
-                sb.append(AndroidPackageUtils.getSeInfo(pkg.getPkg(), pkg));
+                sb.append(pkg.getSeInfo());
                 sb.append(" ");
                 final int gidsSize = gids.size();
                 if (gids != null && gids.size() > 0) {
@@ -3110,16 +3113,15 @@
 
     boolean readLPw(@NonNull Computer computer, @NonNull List<UserInfo> users) {
         FileInputStream str = null;
-        if (mBackupSettingsFilename.exists()) {
+        if (mPreviousSettingsFilename.exists()) {
             try {
-                str = new FileInputStream(mBackupSettingsFilename);
+                str = new FileInputStream(mPreviousSettingsFilename);
                 mReadMessages.append("Reading from backup settings file\n");
                 PackageManagerService.reportSettingsProblem(Log.INFO,
                         "Need to read from backup settings file");
                 if (mSettingsFilename.exists()) {
-                    // If both the backup and settings file exist, we
-                    // ignore the settings since it might have been
-                    // corrupted.
+                    // If both the previous and current settings files exist,
+                    // we ignore the current since it might have been corrupted.
                     Slog.w(PackageManagerService.TAG, "Cleaning up settings file "
                             + mSettingsFilename);
                     mSettingsFilename.delete();
@@ -4359,7 +4361,7 @@
                     // (CE storage is not ready yet; the CE data directories will be created later,
                     // when the user is "unlocked".)  Accumulate all required args, and call the
                     // installer after the mPackages lock has been released.
-                    final String seInfo = AndroidPackageUtils.getSeInfo(ps.getPkg(), ps);
+                    final String seInfo = ps.getSeInfo();
                     final boolean usesSdk = !ps.getPkg().getUsesSdkLibraries().isEmpty();
                     final CreateAppDataArgs args = Installer.buildCreateAppDataArgs(
                             ps.getVolumeUuid(), ps.getPackageName(), userHandle,
@@ -5595,8 +5597,8 @@
     }
 
     private static final class RuntimePermissionPersistence {
-        // 200-400ms delay to avoid monopolizing PMS lock when written for multiple users.
-        private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 300;
+        // 700-1300ms delay to avoid monopolizing PMS lock when written for multiple users.
+        private static final long WRITE_PERMISSIONS_DELAY_MILLIS = 1000;
         private static final double WRITE_PERMISSIONS_DELAY_JITTER = 0.3;
 
         private static final long MAX_WRITE_PERMISSIONS_DELAY_MILLIS = 2000;
@@ -5614,8 +5616,7 @@
 
         // Low-priority handlers running on SystemBg thread.
         private final Handler mAsyncHandler = new MyHandler();
-        private final Handler mPersistenceHandler = new Handler(
-                BackgroundThread.getHandler().getLooper());
+        private final Handler mPersistenceHandler = new PersistenceHandler();
 
         private final Object mLock = new Object();
 
@@ -5762,20 +5763,22 @@
                 @NonNull WatchedArrayMap<String, SharedUserSetting> sharedUsers,
                 @Nullable Handler pmHandler, @NonNull Object pmLock,
                 boolean sync) {
-            final int version;
-            final String fingerprint;
-            final boolean isLegacyPermissionStateStale;
             synchronized (mLock) {
                 mAsyncHandler.removeMessages(userId);
                 mWriteScheduled.delete(userId);
-
-                version = mVersions.get(userId, INITIAL_VERSION);
-                fingerprint = mFingerprints.get(userId);
-                isLegacyPermissionStateStale = mIsLegacyPermissionStateStale;
-                mIsLegacyPermissionStateStale = false;
             }
 
             Runnable writer = () -> {
+                final int version;
+                final String fingerprint;
+                final boolean isLegacyPermissionStateStale;
+                synchronized (mLock) {
+                    version = mVersions.get(userId, INITIAL_VERSION);
+                    fingerprint = mFingerprints.get(userId);
+                    isLegacyPermissionStateStale = mIsLegacyPermissionStateStale;
+                    mIsLegacyPermissionStateStale = false;
+                }
+
                 final RuntimePermissionsState runtimePermissions;
                 synchronized (pmLock) {
                     if (sync || isLegacyPermissionStateStale) {
@@ -5824,7 +5827,7 @@
                 }
                 if (pmHandler != null) {
                     // Async version.
-                    mPersistenceHandler.post(() -> writePendingStates());
+                    mPersistenceHandler.obtainMessage(userId).sendToTarget();
                 } else {
                     // Sync version.
                     writePendingStates();
@@ -6100,6 +6103,17 @@
                 }
             }
         }
+
+        private final class PersistenceHandler extends Handler {
+            PersistenceHandler() {
+                super(BackgroundThread.getHandler().getLooper());
+            }
+
+            @Override
+            public void handleMessage(Message message) {
+                writePendingStates();
+            }
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 1da442b..74594cc 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -53,7 +53,6 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
-import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
 import com.android.server.pm.pkg.AndroidPackage;
 import com.android.server.pm.pkg.PackageStateInternal;
 import com.android.server.pm.pkg.PackageStateUtils;
@@ -347,7 +346,7 @@
             // an update, and hence need to restore data for all installed users.
             final int[] installedUsers = PackageStateUtils.queryInstalledUsers(ps, allUsers, true);
 
-            final String seInfo = AndroidPackageUtils.getSeInfo(pkg, ps);
+            final String seInfo = ps.getSeInfo();
             rm.snapshotAndRestoreUserData(packageName, UserHandle.toUserHandles(installedUsers),
                     appId, ceDataInode, seInfo, 0 /*token*/);
         }
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index 1027f4c..0f920c6 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -435,10 +435,20 @@
     /** Removes a {@link UserVisibilityListener}. */
     public abstract void removeUserVisibilityListener(UserVisibilityListener listener);
 
-    /** TODO(b/244333150): temporary method until UserVisibilityMediator handles that logic */
-    public abstract void onUserVisibilityChanged(@UserIdInt int userId, boolean visible);
+    // TODO(b/242195409): remove this method if not needed anymore
+    /** Notify {@link UserVisibilityListener listeners} that the visibility of the
+     * {@link android.os.UserHandle#USER_SYSTEM} changed. */
+    public abstract void onSystemUserVisibilityChanged(boolean visible);
 
     /** Return the integer types of the given user IDs. Only used for reporting metrics to statsd.
      */
     public abstract int[] getUserTypesForStatsd(@UserIdInt int[] userIds);
+
+    /**
+     * Returns the user id of the main user, or {@link android.os.UserHandle#USER_NULL} if there is
+     * no main user.
+     *
+     * @see UserManager#isMainUser()
+     */
+    public abstract @UserIdInt int getMainUserId();
 }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 88e12fa..3234e87 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -97,7 +97,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AtomicFile;
-import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
 import android.util.Slog;
@@ -126,7 +125,6 @@
 import com.android.server.LocalServices;
 import com.android.server.LockGuard;
 import com.android.server.SystemService;
-import com.android.server.am.EventLogTags;
 import com.android.server.am.UserState;
 import com.android.server.pm.UserManagerInternal.UserLifecycleListener;
 import com.android.server.pm.UserManagerInternal.UserRestrictionsListener;
@@ -191,6 +189,7 @@
     private static final String ATTR_CREATION_TIME = "created";
     private static final String ATTR_LAST_LOGGED_IN_TIME = "lastLoggedIn";
     private static final String ATTR_LAST_LOGGED_IN_FINGERPRINT = "lastLoggedInFingerprint";
+    private static final String ATTR_LAST_ENTERED_FOREGROUND_TIME = "lastEnteredForeground";
     private static final String ATTR_SERIAL_NO = "serialNumber";
     private static final String ATTR_NEXT_SERIAL_NO = "nextSerialNumber";
     private static final String ATTR_PARTIAL = "partial";
@@ -341,6 +340,9 @@
         /** Elapsed realtime since boot when the user was unlocked. */
         long unlockRealtime;
 
+        /** Wall clock time in millis when the user last entered the foreground. */
+        long mLastEnteredForegroundTimeMillis;
+
         private long mLastRequestQuietModeEnabledMillis;
 
         /**
@@ -508,10 +510,6 @@
     @GuardedBy("mUserLifecycleListeners")
     private final ArrayList<UserLifecycleListener> mUserLifecycleListeners = new ArrayList<>();
 
-    // TODO(b/244333150): temporary array, should belong to UserVisibilityMediator
-    @GuardedBy("mUserVisibilityListeners")
-    private final ArrayList<UserVisibilityListener> mUserVisibilityListeners = new ArrayList<>();
-
     private final LockPatternUtils mLockPatternUtils;
 
     private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
@@ -680,6 +678,10 @@
                 final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
                 if (user != null) {
                     user.startRealtime = SystemClock.elapsedRealtime();
+                    if (targetUser.getUserIdentifier() == UserHandle.USER_SYSTEM
+                            && targetUser.isFull()) {
+                        mUms.setLastEnteredForegroundTimeToNow(user);
+                    }
                 }
             }
         }
@@ -695,6 +697,16 @@
         }
 
         @Override
+        public void onUserSwitching(@NonNull TargetUser from, @NonNull TargetUser to) {
+            synchronized (mUms.mUsersLock) {
+                final UserData user = mUms.getUserDataLU(to.getUserIdentifier());
+                if (user != null) {
+                    mUms.setLastEnteredForegroundTimeToNow(user);
+                }
+            }
+        }
+
+        @Override
         public void onUserStopping(@NonNull TargetUser targetUser) {
             synchronized (mUms.mUsersLock) {
                 final UserData user = mUms.getUserDataLU(targetUser.getUserIdentifier());
@@ -901,6 +913,49 @@
         return null;
     }
 
+    @Override
+    public @UserIdInt int getMainUserId() {
+        checkQueryOrCreateUsersPermission("get main user id");
+        return getMainUserIdUnchecked();
+    }
+
+    private @UserIdInt int getMainUserIdUnchecked() {
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                final UserInfo user = mUsers.valueAt(i).info;
+                if (user.isMain() && !mRemovingUserIds.get(user.id)) {
+                    return user.id;
+                }
+            }
+        }
+        return UserHandle.USER_NULL;
+    }
+
+    @Override
+    public int getPreviousFullUserToEnterForeground() {
+        checkQueryOrCreateUsersPermission("get previous user");
+        int previousUser = UserHandle.USER_NULL;
+        long latestEnteredTime = 0;
+        final int currentUser = getCurrentUserId();
+        synchronized (mUsersLock) {
+            final int userSize = mUsers.size();
+            for (int i = 0; i < userSize; i++) {
+                final UserData userData = mUsers.valueAt(i);
+                final int userId = userData.info.id;
+                if (userId != currentUser && userData.info.isFull() && !userData.info.partial
+                        && !mRemovingUserIds.get(userId)) {
+                    final long userEnteredTime = userData.mLastEnteredForegroundTimeMillis;
+                    if (userEnteredTime > latestEnteredTime) {
+                        latestEnteredTime = userEnteredTime;
+                        previousUser = userId;
+                    }
+                }
+            }
+        }
+        return previousUser;
+    }
+
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
         return getUsers(/*excludePartial= */ true, excludeDying, /* excludePreCreated= */
                 true);
@@ -3339,13 +3394,13 @@
                     Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): no system user data");
                     return;
                 }
+                final int oldMainUserId = getMainUserIdUnchecked();
                 final int oldFlags = systemUserData.info.flags;
                 final int newFlags;
                 final String newUserType;
-                // TODO(b/256624031): Also handle FLAG_MAIN
                 if (newHeadlessSystemUserMode) {
                     newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
-                    newFlags = oldFlags & ~UserInfo.FLAG_FULL;
+                    newFlags = oldFlags & ~UserInfo.FLAG_FULL & ~UserInfo.FLAG_MAIN;
                 } else {
                     newUserType = UserManager.USER_TYPE_FULL_SYSTEM;
                     newFlags = oldFlags | UserInfo.FLAG_FULL;
@@ -3360,9 +3415,38 @@
                         + "%s, flags changed from %s to %s",
                         systemUserData.info.userType, newUserType,
                         UserInfo.flagsToString(oldFlags), UserInfo.flagsToString(newFlags));
+
                 systemUserData.info.userType = newUserType;
                 systemUserData.info.flags = newFlags;
                 writeUserLP(systemUserData);
+
+                // Switch the MainUser to a reasonable choice if needed.
+                // (But if there was no MainUser, we deliberately continue to have no MainUser.)
+                final UserData oldMain = getUserDataNoChecks(oldMainUserId);
+                if (newHeadlessSystemUserMode) {
+                    if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) != 0) {
+                        // System was MainUser. So we need a new choice for Main. Pick the oldest.
+                        // If no oldest, don't set any. Let the BootUserInitializer do that later.
+                        final UserInfo newMainUser = getEarliestCreatedFullUser();
+                        if (newMainUser != null) {
+                            Slogf.i(LOG_TAG, "Designating user " + newMainUser.id + " to be Main");
+                            newMainUser.flags |= UserInfo.FLAG_MAIN;
+                            writeUserLP(getUserDataNoChecks(newMainUser.id));
+                        }
+                    }
+                } else {
+                    // TODO(b/256624031): For now, we demand the Main user (if there is one) is
+                    //  always the system in non-HSUM. In the future, when we relax this, change how
+                    //  we handle MAIN.
+                    if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) == 0) {
+                        // Someone else was the MainUser; transfer it to System.
+                        Slogf.i(LOG_TAG, "Transferring Main to user 0 from " + oldMain.info.id);
+                        oldMain.info.flags &= ~UserInfo.FLAG_MAIN;
+                        systemUserData.info.flags |= UserInfo.FLAG_MAIN;
+                        writeUserLP(oldMain);
+                        writeUserLP(systemUserData);
+                    }
+                }
             }
         }
 
@@ -3639,8 +3723,10 @@
             // Add FLAG_MAIN
             if (isHeadlessSystemUserMode()) {
                 final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
-                earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
-                userIdsToWrite.add(earliestCreatedUser.id);
+                if (earliestCreatedUser != null) {
+                    earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
+                    userIdsToWrite.add(earliestCreatedUser.id);
+                }
             } else {
                 synchronized (mUsersLock) {
                     final UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
@@ -3780,13 +3866,14 @@
         userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
     }
 
-    private UserInfo getEarliestCreatedFullUser() {
+    /** Returns the oldest Full Admin user, or null is if there none. */
+    private @Nullable UserInfo getEarliestCreatedFullUser() {
         final List<UserInfo> users = getUsersInternal(true, true, true);
-        UserInfo earliestUser = users.get(0);
-        long earliestCreationTime = earliestUser.creationTime;
+        UserInfo earliestUser = null;
+        long earliestCreationTime = Long.MAX_VALUE;
         for (int i = 0; i < users.size(); i++) {
             final UserInfo info = users.get(i);
-            if (info.isFull() && info.isAdmin() && info.creationTime > 0
+            if (info.isFull() && info.isAdmin() && info.creationTime >= 0
                     && info.creationTime < earliestCreationTime) {
                 earliestCreationTime = info.creationTime;
                 earliestUser = info;
@@ -3922,6 +4009,8 @@
             serializer.attribute(null, ATTR_LAST_LOGGED_IN_FINGERPRINT,
                     userInfo.lastLoggedInFingerprint);
         }
+        serializer.attributeLong(
+                null, ATTR_LAST_ENTERED_FOREGROUND_TIME, userData.mLastEnteredForegroundTimeMillis);
         if (userInfo.iconPath != null) {
             serializer.attribute(null,  ATTR_ICON_PATH, userInfo.iconPath);
         }
@@ -4095,6 +4184,7 @@
         long lastLoggedInTime = 0L;
         long lastRequestQuietModeEnabledTimestamp = 0L;
         String lastLoggedInFingerprint = null;
+        long lastEnteredForegroundTime = 0L;
         int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
         int profileBadge = 0;
         int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
@@ -4140,6 +4230,8 @@
             lastLoggedInTime = parser.getAttributeLong(null, ATTR_LAST_LOGGED_IN_TIME, 0);
             lastLoggedInFingerprint = parser.getAttributeValue(null,
                     ATTR_LAST_LOGGED_IN_FINGERPRINT);
+            lastEnteredForegroundTime =
+                    parser.getAttributeLong(null, ATTR_LAST_ENTERED_FOREGROUND_TIME, 0L);
             profileGroupId = parser.getAttributeInt(null, ATTR_PROFILE_GROUP_ID,
                     UserInfo.NO_PROFILE_GROUP_ID);
             profileBadge = parser.getAttributeInt(null, ATTR_PROFILE_BADGE, 0);
@@ -4234,6 +4326,7 @@
         userData.seedAccountOptions = seedAccountOptions;
         userData.userProperties = userProperties;
         userData.setLastRequestQuietModeEnabledMillis(lastRequestQuietModeEnabledTimestamp);
+        userData.mLastEnteredForegroundTimeMillis = lastEnteredForegroundTime;
         if (ignorePrepareStorageErrors) {
             userData.setIgnorePrepareStorageErrors();
         }
@@ -6153,6 +6246,11 @@
                         || someUserHasSeedAccountNoChecks(accountName, accountType));
     }
 
+    private void setLastEnteredForegroundTimeToNow(@NonNull UserData userData) {
+        userData.mLastEnteredForegroundTimeMillis = System.currentTimeMillis();
+        scheduleWriteUser(userData);
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out,
             FileDescriptor err, String[] args, ShellCallback callback,
@@ -6279,9 +6377,6 @@
         synchronized (mUserLifecycleListeners) {
             pw.println("  user lifecycle events: " + mUserLifecycleListeners.size());
         }
-        synchronized (mUserVisibilityListeners) {
-            pw.println("  user visibility events: " + mUserVisibilityListeners.size());
-        }
 
         // Dump UserTypes
         pw.println();
@@ -6377,6 +6472,9 @@
         pw.print("    Unlock time: ");
         dumpTimeAgo(pw, tempStringBuilder, nowRealtime, userData.unlockRealtime);
 
+        pw.print("    Last entered foreground: ");
+        dumpTimeAgo(pw, tempStringBuilder, now, userData.mLastEnteredForegroundTimeMillis);
+
         pw.print("    Has profile owner: ");
         pw.println(mIsUserManaged.get(userId));
         pw.println("    Restrictions:");
@@ -6854,31 +6952,17 @@
 
         @Override
         public void addUserVisibilityListener(UserVisibilityListener listener) {
-            synchronized (mUserVisibilityListeners) {
-                mUserVisibilityListeners.add(listener);
-            }
+            mUserVisibilityMediator.addListener(listener);
         }
 
         @Override
         public void removeUserVisibilityListener(UserVisibilityListener listener) {
-            synchronized (mUserVisibilityListeners) {
-                mUserVisibilityListeners.remove(listener);
-            }
+            mUserVisibilityMediator.removeListener(listener);
         }
 
         @Override
-        public void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
-            EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
-            mHandler.post(() -> {
-                UserVisibilityListener[] listeners;
-                synchronized (mUserVisibilityListeners) {
-                    listeners = new UserVisibilityListener[mUserVisibilityListeners.size()];
-                    mUserVisibilityListeners.toArray(listeners);
-                }
-                for (UserVisibilityListener listener : listeners) {
-                    listener.onUserVisibilityChanged(userId, visible);
-                }
-            });
+        public void onSystemUserVisibilityChanged(boolean visible) {
+            mUserVisibilityMediator.onSystemUserVisibilityChanged(visible);
         }
 
         @Override
@@ -6898,6 +6982,12 @@
             }
             return userTypes;
         }
+
+        @Override
+        public @UserIdInt int getMainUserId() {
+            return getMainUserIdUnchecked();
+        }
+
     } // class LocalService
 
 
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index 9c4187b..9b9ca10 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -32,6 +32,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Dumpable;
+import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
 import android.util.SparseIntArray;
@@ -40,6 +41,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
+import com.android.server.am.EventLogTags;
 import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
 import com.android.server.pm.UserManagerInternal.UserVisibilityListener;
 import com.android.server.utils.Slogf;
@@ -68,6 +70,7 @@
 public final class UserVisibilityMediator implements Dumpable {
 
     private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
+    private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
 
     private static final String TAG = UserVisibilityMediator.class.getSimpleName();
 
@@ -381,8 +384,8 @@
     public boolean isUserVisible(@UserIdInt int userId) {
         // First check current foreground user and their profiles (on main display)
         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
-            if (DBG) {
-                Slogf.d(TAG, "isUserVisible(%d): true to current user or profile", userId);
+            if (VERBOSE) {
+                Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
             }
             return true;
         }
@@ -413,41 +416,12 @@
         if (displayId == Display.INVALID_DISPLAY) {
             return false;
         }
-        if (!mUsersOnSecondaryDisplaysEnabled) {
-            return isCurrentUserOrRunningProfileOfCurrentUser(userId);
-        }
 
-        // TODO(b/256242848): temporary workaround to let WM use this API without breaking current
-        // behavior - return true for current user / profile for any display (other than those
-        // explicitly assigned to another users), otherwise they wouldn't be able to launch
-        // activities on other non-passenger displays, like cluster).
-        // In the long-term, it should rely just on mUsersOnSecondaryDisplays, which
-        // would be updated by CarService to allow additional mappings.
-        if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
-            synchronized (mLock) {
-                boolean assignedToUser = false;
-                boolean assignedToAnotherUser = false;
-                for (int i = 0; i < mUsersOnSecondaryDisplays.size(); i++) {
-                    if (mUsersOnSecondaryDisplays.valueAt(i) == displayId) {
-                        if (mUsersOnSecondaryDisplays.keyAt(i) == userId) {
-                            assignedToUser = true;
-                            break;
-                        } else {
-                            assignedToAnotherUser = true;
-                            // Cannot break because it could be assigned to a profile of the user
-                            // (and we better not assume that the iteration will check for the
-                            // parent user before its profiles)
-                        }
-                    }
-                }
-                if (DBG) {
-                    Slogf.d(TAG, "isUserVisibleOnDisplay(%d, %d): assignedToUser=%b, "
-                            + "assignedToAnotherUser=%b, mUsersOnSecondaryDisplays=%s",
-                            userId, displayId, assignedToUser, assignedToAnotherUser,
-                            mUsersOnSecondaryDisplays);
-                }
-                return assignedToUser || !assignedToAnotherUser;
-            }
+        if (!mUsersOnSecondaryDisplaysEnabled || displayId == Display.DEFAULT_DISPLAY) {
+            // TODO(b/245939659): will need to move the displayId == Display.DEFAULT_DISPLAY outside
+            // once it supports background users on DEFAULT_DISPLAY (for example, passengers in a
+            // no-driver configuration)
+            return isCurrentUserOrRunningProfileOfCurrentUser(userId);
         }
 
         synchronized (mLock) {
@@ -546,6 +520,14 @@
         }
     }
 
+    // TODO(b/242195409): remove this method if not needed anymore
+    /**
+     * Nofify all listeners that the system user visibility changed.
+     */
+    void onSystemUserVisibilityChanged(boolean visible) {
+        dispatchVisibilityChanged(mListeners, USER_SYSTEM, visible);
+    }
+
     /**
      * Nofify all listeners about the visibility changes from before / after a change of state.
      */
@@ -563,7 +545,7 @@
             Slogf.d(TAG,
                     "dispatchVisibilityChanged(): visibleUsersBefore=%s, visibleUsersAfter=%s, "
                     + "%d listeners (%s)", visibleUsersBefore, visibleUsersAfter, listeners.size(),
-                    mListeners);
+                    listeners);
         }
         for (int i = 0; i < visibleUsersBefore.size(); i++) {
             int userId = visibleUsersBefore.get(i);
@@ -581,13 +563,14 @@
 
     private void dispatchVisibilityChanged(CopyOnWriteArrayList<UserVisibilityListener> listeners,
             @UserIdInt int userId, boolean visible) {
+        EventLog.writeEvent(EventLogTags.UM_USER_VISIBILITY_CHANGED, userId, visible ? 1 : 0);
         if (DBG) {
             Slogf.d(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %d listeners",
                     userId, visible, listeners.size());
         }
         for (int i = 0; i < mListeners.size(); i++) {
             UserVisibilityListener listener =  mListeners.get(i);
-            if (DBG) {
+            if (VERBOSE) {
                 Slogf.v(TAG, "dispatchVisibilityChanged(%d -> %b): sending to %s",
                         userId, visible, listener);
             }
@@ -604,9 +587,7 @@
             ipw.println(mCurrentUserId);
 
             ipw.print("Visible users: ");
-            // TODO: merge 2 lines below if/when IntArray implements toString()...
-            IntArray visibleUsers = getVisibleUsers();
-            ipw.println(java.util.Arrays.toString(visibleUsers.toArray()));
+            ipw.println(getVisibleUsers());
 
             dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group",
                     "u", "pg");
diff --git a/services/core/java/com/android/server/pm/VerificationUtils.java b/services/core/java/com/android/server/pm/VerificationUtils.java
index e1026b4..30f2132 100644
--- a/services/core/java/com/android/server/pm/VerificationUtils.java
+++ b/services/core/java/com/android/server/pm/VerificationUtils.java
@@ -112,7 +112,7 @@
 
         VerificationUtils.broadcastPackageVerified(verificationId, originUri,
                 verificationCode, null,
-                verifyingSession.mDataLoaderType, verifyingSession.getUser(),
+                verifyingSession.getDataLoaderType(), verifyingSession.getUser(),
                 pms.mContext);
 
         if (state.isInstallAllowed()) {
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index 6160519..a54f526 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -19,6 +19,7 @@
 import static android.content.Intent.EXTRA_LONG_VERSION_CODE;
 import static android.content.Intent.EXTRA_PACKAGE_NAME;
 import static android.content.Intent.EXTRA_VERSION_CODE;
+import static android.content.pm.PackageInstaller.SessionParams.MODE_INHERIT_EXISTING;
 import static android.content.pm.PackageManager.EXTRA_VERIFICATION_ID;
 import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
@@ -114,30 +115,32 @@
 
     final OriginInfo mOriginInfo;
     final IPackageInstallObserver2 mObserver;
-    final int mInstallFlags;
+    private final int mInstallFlags;
     @NonNull
-    final InstallSource mInstallSource;
-    final String mPackageAbiOverride;
-    final VerificationInfo mVerificationInfo;
-    final SigningDetails mSigningDetails;
+    private final InstallSource mInstallSource;
+    private final String mPackageAbiOverride;
+    private final VerificationInfo mVerificationInfo;
+    private final SigningDetails mSigningDetails;
     @Nullable
     MultiPackageVerifyingSession mParentVerifyingSession;
-    final long mRequiredInstalledVersionCode;
-    final int mDataLoaderType;
-    final int mSessionId;
-    final boolean mUserActionRequired;
-
+    private final long mRequiredInstalledVersionCode;
+    private final int mDataLoaderType;
+    private final int mSessionId;
+    private final boolean mUserActionRequired;
+    private final int mUserActionRequiredType;
     private boolean mWaitForVerificationToComplete;
     private boolean mWaitForIntegrityVerificationToComplete;
     private boolean mWaitForEnableRollbackToComplete;
     private int mRet = PackageManager.INSTALL_SUCCEEDED;
     private String mErrorMessage = null;
+    private final boolean mIsInherit;
+    private final boolean mIsStaged;
 
-    final PackageLite mPackageLite;
+    private final PackageLite mPackageLite;
     private final UserHandle mUser;
     @NonNull
-    final PackageManagerService mPm;
-    final InstallPackageHelper mInstallPackageHelper;
+    private final PackageManagerService mPm;
+    private final InstallPackageHelper mInstallPackageHelper;
 
     VerifyingSession(UserHandle user, File stagedDir, IPackageInstallObserver2 observer,
             PackageInstaller.SessionParams sessionParams, InstallSource installSource,
@@ -164,6 +167,9 @@
         mSessionId = sessionId;
         mPackageLite = lite;
         mUserActionRequired = userActionRequired;
+        mUserActionRequiredType = sessionParams.requireUserAction;
+        mIsInherit = sessionParams.mode == MODE_INHERIT_EXISTING;
+        mIsStaged = sessionParams.isStaged;
     }
 
     @Override
@@ -186,7 +192,7 @@
         // Perform package verification and enable rollback (unless we are simply moving the
         // package).
         if (!mOriginInfo.mExisting) {
-            if ((mInstallFlags & PackageManager.INSTALL_APEX) == 0) {
+            if (!isApex()) {
                 // TODO(b/182426975): treat APEX as APK when APK verification is concerned
                 sendApkVerificationRequest(pkgLite);
             }
@@ -674,10 +680,9 @@
         }
 
         final int installerUid = mVerificationInfo == null ? -1 : mVerificationInfo.mInstallerUid;
-        final int installFlags = mInstallFlags;
 
         // Check if installing from ADB
-        if ((installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
+        if ((mInstallFlags & PackageManager.INSTALL_FROM_ADB) != 0) {
             boolean requestedDisableVerification =
                     (mInstallFlags & PackageManager.INSTALL_DISABLE_VERIFICATION) != 0;
             return isAdbVerificationEnabled(pkgInfoLite, userId, requestedDisableVerification);
@@ -685,8 +690,7 @@
 
         // only when not installed from ADB, skip verification for instant apps when
         // the installer and verifier are the same.
-        if ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0
-                && mPm.mInstantAppInstallerActivity != null) {
+        if (isInstant() && mPm.mInstantAppInstallerActivity != null) {
             String installerPackage = mPm.mInstantAppInstallerActivity.packageName;
             for (String requiredVerifierPackage : requiredVerifierPackages) {
                 if (installerPackage.equals(requiredVerifierPackage)) {
@@ -818,6 +822,9 @@
             return;
         }
         sendVerificationCompleteNotification();
+        if (mRet != INSTALL_SUCCEEDED) {
+            PackageMetrics.onVerificationFailed(this);
+        }
     }
 
     private void sendVerificationCompleteNotification() {
@@ -865,4 +872,28 @@
     public UserHandle getUser() {
         return mUser;
     }
+    public int getSessionId() {
+        return mSessionId;
+    }
+    public int getDataLoaderType() {
+        return mDataLoaderType;
+    }
+    public int getUserActionRequiredType() {
+        return mUserActionRequiredType;
+    }
+    public boolean isInstant() {
+        return (mInstallFlags & PackageManager.INSTALL_INSTANT_APP) != 0;
+    }
+    public boolean isInherit() {
+        return mIsInherit;
+    }
+    public int getInstallerPackageUid() {
+        return mInstallSource.mInstallerPackageUid;
+    }
+    public boolean isApex() {
+        return (mInstallFlags & PackageManager.INSTALL_APEX) != 0;
+    }
+    public boolean isStaged() {
+        return mIsStaged;
+    }
 }
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 0bdd980..046db92 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -320,15 +320,13 @@
 
         switch (profileType) {
             case ArtManager.PROFILE_APPS :
-                return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
+                return true;
             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) &&
-                        profileBootClassPath;
+                return (Build.IS_USERDEBUG || Build.IS_ENG) && profileBootClassPath;
             default:
                 throw new IllegalArgumentException("Invalid profile type:" + profileType);
         }
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 1407530..9f21097 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -298,12 +298,15 @@
                     dexMetadataType,
                     apkType,
                     ISA_MAP.getOrDefault(isa,
-                            ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN));
+                            ArtStatsLog.ART_DATUM_REPORTED__ISA__ART_ISA_UNKNOWN),
+                    ArtStatsLog.ART_DATUM_REPORTED__GC__ART_GC_COLLECTOR_TYPE_UNKNOWN);
         }
     }
 
     private static final Map<Integer, Integer> STATUS_MAP =
-            Map.of(BackgroundDexOptService.STATUS_OK,
+            Map.of(BackgroundDexOptService.STATUS_UNSPECIFIED,
+                    ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_UNKNOWN,
+                    BackgroundDexOptService.STATUS_OK,
                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED,
                     BackgroundDexOptService.STATUS_ABORT_BY_CANCELLATION,
                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BY_CANCELLATION,
@@ -314,7 +317,9 @@
                     BackgroundDexOptService.STATUS_ABORT_BATTERY,
                     ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_ABORT_BATTERY,
                     BackgroundDexOptService.STATUS_DEX_OPT_FAILED,
-                    ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED);
+                    ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_JOB_FINISHED,
+                    BackgroundDexOptService.STATUS_FATAL_ERROR,
+                    ArtStatsLog.BACKGROUND_DEXOPT_JOB_ENDED__STATUS__STATUS_FATAL_ERROR);
 
     /** Helper class to write background dexopt job stats to statsd. */
     public static class BackgroundDexoptJobStatsLogger {
diff --git a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
index a7d4cea..a3fa25d 100644
--- a/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/PackageInfoUtils.java
@@ -452,7 +452,7 @@
             info.category = pkgSetting.getCategoryOverride();
         }
 
-        info.seInfo = AndroidPackageUtils.getSeInfo(pkg, pkgSetting);
+        info.seInfo = pkgSetting.getSeInfo();
         info.primaryCpuAbi = pkgSetting.getPrimaryCpuAbi();
         info.secondaryCpuAbi = pkgSetting.getSecondaryCpuAbi();
 
@@ -533,7 +533,7 @@
             ai.metaData = null;
         }
         ai.applicationInfo = applicationInfo;
-        ai.targetDisplayCategory = a.getTargetDisplayCategory();
+        ai.requiredDisplayCategory = a.getRequiredDisplayCategory();
         ai.setKnownActivityEmbeddingCerts(a.getKnownActivityEmbeddingCerts());
         assignFieldsComponentInfoParsedMainComponent(ai, a, pkgSetting, userId);
         return ai;
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
index 944e4ad..876bf17 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageHidden.java
@@ -40,13 +40,6 @@
     String getPrimaryCpuAbi();
 
     /**
-     * @see ApplicationInfo#seInfo
-     * TODO: This field is deriveable and might not have to be cached here.
-     */
-    @Nullable
-    String getSeInfo();
-
-    /**
      * @see ApplicationInfo#secondaryCpuAbi
      */
     @Nullable
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
index 5b0cc51..c76b129 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/AndroidPackageUtils.java
@@ -27,7 +27,6 @@
 import android.content.pm.parsing.result.ParseResult;
 import android.content.pm.parsing.result.ParseTypeImpl;
 import android.os.incremental.IncrementalManager;
-import android.text.TextUtils;
 
 import com.android.internal.content.NativeLibraryHelper;
 import com.android.internal.util.ArrayUtils;
@@ -288,16 +287,6 @@
         return ((AndroidPackageHidden) pkg).getSecondaryCpuAbi();
     }
 
-    public static String getSeInfo(AndroidPackage pkg, @Nullable PackageStateInternal pkgSetting) {
-        if (pkgSetting != null) {
-            String overrideSeInfo = pkgSetting.getTransientState().getOverrideSeInfo();
-            if (!TextUtils.isEmpty(overrideSeInfo)) {
-                return overrideSeInfo;
-            }
-        }
-        return ((AndroidPackageHidden) pkg).getSeInfo();
-    }
-
     @Deprecated
     @NonNull
     public static ApplicationInfo generateAppInfoWithoutState(AndroidPackage pkg) {
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
index a43b979..ba36ab7 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/PackageImpl.java
@@ -462,10 +462,6 @@
     @DataClass.ParcelWith(ForInternedString.class)
     protected String secondaryNativeLibraryDir;
 
-    @Nullable
-    @DataClass.ParcelWith(ForInternedString.class)
-    protected String seInfo;
-
     /**
      * This is an appId, the uid if the userId is == USER_SYSTEM
      */
@@ -1339,6 +1335,11 @@
     }
 
     @Override
+    public UUID getStorageUuid() {
+        return mStorageUuid;
+    }
+
+    @Override
     public int getTargetSandboxVersion() {
         return targetSandboxVersion;
     }
@@ -2905,12 +2906,6 @@
     }
 
     @Override
-    public PackageImpl setSeInfo(@Nullable String seInfo) {
-        this.seInfo = TextUtils.safeIntern(seInfo);
-        return this;
-    }
-
-    @Override
     public PackageImpl setSplitCodePaths(@Nullable String[] splitCodePaths) {
         this.splitCodePaths = splitCodePaths;
         if (splitCodePaths != null) {
@@ -2993,7 +2988,6 @@
         appInfo.primaryCpuAbi = primaryCpuAbi;
         appInfo.secondaryCpuAbi = secondaryCpuAbi;
         appInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
-        appInfo.seInfo = seInfo;
         appInfo.seInfoUser = SELinuxUtil.COMPLETE_STR;
         appInfo.uid = uid;
         return appInfo;
@@ -3147,7 +3141,6 @@
         sForInternedString.parcel(this.primaryCpuAbi, dest, flags);
         sForInternedString.parcel(this.secondaryCpuAbi, dest, flags);
         dest.writeString(this.secondaryNativeLibraryDir);
-        dest.writeString(this.seInfo);
         dest.writeInt(this.uid);
         dest.writeLong(this.mBooleans);
         dest.writeLong(this.mBooleans2);
@@ -3307,7 +3300,6 @@
         this.primaryCpuAbi = sForInternedString.unparcel(in);
         this.secondaryCpuAbi = sForInternedString.unparcel(in);
         this.secondaryNativeLibraryDir = in.readString();
-        this.seInfo = in.readString();
         this.uid = in.readInt();
         this.mBooleans = in.readLong();
         this.mBooleans2 = in.readLong();
@@ -3377,12 +3369,6 @@
         return secondaryNativeLibraryDir;
     }
 
-    @Nullable
-    @Override
-    public String getSeInfo() {
-        return seInfo;
-    }
-
     @Override
     public boolean isCoreApp() {
         return getBoolean(Booleans.CORE_APP);
diff --git a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
index d306341..aeaff6d 100644
--- a/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
+++ b/services/core/java/com/android/server/pm/parsing/pkg/ParsedPackage.java
@@ -103,8 +103,6 @@
 
     ParsedPackage setRestrictUpdateHash(byte[] restrictUpdateHash);
 
-    ParsedPackage setSeInfo(String seInfo);
-
     ParsedPackage setSecondaryNativeLibraryDir(String secondaryNativeLibraryDir);
 
     /**
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 9ec63fc..cefe9cd 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -467,7 +467,7 @@
 
     @Override
     public PermissionInfo getPermissionInfo(String permissionName, String packageName, int flags) {
-        return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, packageName, flags);
+        return mPermissionManagerServiceImpl.getPermissionInfo(permissionName, flags, packageName);
     }
 
     @Override
@@ -792,14 +792,14 @@
 
         @NonNull
         @Override
-        public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+        public List<PermissionInfo> getAllPermissionsWithProtection(
                 @PermissionInfo.Protection int protection) {
             return mPermissionManagerServiceImpl.getAllPermissionsWithProtection(protection);
         }
 
         @NonNull
         @Override
-        public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+        public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
                 @PermissionInfo.ProtectionFlags int protectionFlags) {
             return mPermissionManagerServiceImpl
                     .getAllPermissionsWithProtectionFlags(protectionFlags);
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index 5ffbbdc..e56edeb 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -559,8 +559,8 @@
 
     @Override
     @Nullable
-    public PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
-            @PackageManager.PermissionInfoFlags int flags) {
+    public PermissionInfo getPermissionInfo(@NonNull String permName,
+            @PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName) {
         final int callingUid = Binder.getCallingUid();
         if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) {
             return null;
@@ -2127,7 +2127,7 @@
             for (int i = 0; i < numRequestedPermissions; i++) {
                 PermissionInfo permInfo = getPermissionInfo(
                         newPackage.getRequestedPermissions().get(i),
-                        newPackage.getPackageName(), 0);
+                        0, newPackage.getPackageName());
                 if (permInfo == null) {
                     continue;
                 }
@@ -5204,9 +5204,9 @@
 
     @NonNull
     @Override
-    public ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+    public List<PermissionInfo> getAllPermissionsWithProtection(
             @PermissionInfo.Protection int protection) {
-        ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+        List<PermissionInfo> matchingPermissions = new ArrayList<>();
 
         synchronized (mLock) {
             for (final Permission permission : mRegistry.getPermissions()) {
@@ -5221,9 +5221,9 @@
 
     @NonNull
     @Override
-    public ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+    public List<PermissionInfo> getAllPermissionsWithProtectionFlags(
             @PermissionInfo.ProtectionFlags int protectionFlags) {
-        ArrayList<PermissionInfo> matchingPermissions = new ArrayList<>();
+        List<PermissionInfo> matchingPermissions = new ArrayList<>();
 
         synchronized (mLock) {
             for (final Permission permission : mRegistry.getPermissions()) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
index 930936b..d9caec7 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInterface.java
@@ -32,7 +32,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -77,8 +76,8 @@
      * @return a {@link PermissionInfo} containing information about the permission, or {@code null}
      *         if not found
      */
-    PermissionInfo getPermissionInfo(@NonNull String permName, @NonNull String opPackageName,
-            @PackageManager.PermissionInfoFlags int flags);
+    PermissionInfo getPermissionInfo(@NonNull String permName,
+            @PackageManager.PermissionInfoFlags int flags, @NonNull String opPackageName);
 
     /**
      * Query for all of the permissions associated with a particular group.
@@ -487,11 +486,11 @@
 
     /** Get all permissions that have a certain protection */
     @NonNull
-    ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+    List<PermissionInfo> getAllPermissionsWithProtection(
             @PermissionInfo.Protection int protection);
 
     /** Get all permissions that have certain protection flags */
-    @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+    @NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
             @PermissionInfo.ProtectionFlags int protectionFlags);
 
     /**
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 f20620e..97ac749 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -164,11 +164,12 @@
 
     /** Get all permissions that have a certain protection */
     @NonNull
-    ArrayList<PermissionInfo> getAllPermissionsWithProtection(
+    List<PermissionInfo> getAllPermissionsWithProtection(
             @PermissionInfo.Protection int protection);
 
-    /** Get all permissions that have certain protection flags */
-    @NonNull ArrayList<PermissionInfo> getAllPermissionsWithProtectionFlags(
+    /** Get all permissions that have certain protection flags
+     * @return*/
+    @NonNull List<PermissionInfo> getAllPermissionsWithProtectionFlags(
             @PermissionInfo.ProtectionFlags int protectionFlags);
 
     /**
diff --git a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
index e3dad45..84907a5 100644
--- a/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
+++ b/services/core/java/com/android/server/pm/pkg/AndroidPackage.java
@@ -34,6 +34,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.SigningDetails;
 import android.os.Bundle;
+import android.os.storage.StorageManager;
 import android.processor.immutability.Immutable;
 import android.util.ArraySet;
 import android.util.Pair;
@@ -58,6 +59,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 
 /**
  * The representation of an application on disk, as parsed from its split APKs' manifests.
@@ -111,6 +113,13 @@
     String getStaticSharedLibraryName();
 
     /**
+     * @return The {@link UUID} for use with {@link StorageManager} APIs identifying where this
+     * package was installed.
+     */
+    @NonNull
+    UUID getStorageUuid();
+
+    /**
      * @see ApplicationInfo#targetSdkVersion
      * @see R.styleable#AndroidManifestUsesSdk_targetSdkVersion
      */
diff --git a/services/core/java/com/android/server/pm/pkg/PackageState.java b/services/core/java/com/android/server/pm/pkg/PackageState.java
index 3c79cdf..e8d0640 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageState.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageState.java
@@ -131,6 +131,14 @@
     String getSecondaryCpuAbi();
 
     /**
+     * @see ApplicationInfo#seInfo
+     * @return The SE info for this package, which may be overridden by a system configured value,
+     * or null if the package isn't available.
+     */
+    @Nullable
+    String getSeInfo();
+
+    /**
      * @see AndroidPackage#isPrivileged()
      */
     boolean isPrivileged();
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
index c6ce40e..e552a34 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java
@@ -129,6 +129,8 @@
     private final String mPrimaryCpuAbi;
     @Nullable
     private final String mSecondaryCpuAbi;
+    @Nullable
+    private final String mSeInfo;
     private final boolean mHasSharedUser;
     private final int mSharedUserAppId;
     @NonNull
@@ -175,6 +177,7 @@
         mPath = pkgState.getPath();
         mPrimaryCpuAbi = pkgState.getPrimaryCpuAbi();
         mSecondaryCpuAbi = pkgState.getSecondaryCpuAbi();
+        mSeInfo = pkgState.getSeInfo();
         mHasSharedUser = pkgState.hasSharedUser();
         mSharedUserAppId = pkgState.getSharedUserAppId();
         mUsesSdkLibraries = pkgState.getUsesSdkLibraries();
@@ -542,7 +545,7 @@
         }
 
         @DataClass.Generated(
-                time = 1661977809886L,
+                time = 1665778832625L,
                 codegenVersion = "1.0.23",
                 sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
                 inputSignatures = "private  int mBooleans\nprivate final  long mCeDataInode\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mDisabledComponents\nprivate final @android.content.pm.PackageManager.DistractionRestriction int mDistractionFlags\nprivate final @android.annotation.NonNull android.util.ArraySet<java.lang.String> mEnabledComponents\nprivate final  int mEnabledState\nprivate final @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate final @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate final @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate final @android.annotation.NonNull android.content.pm.overlay.OverlayPaths mOverlayPaths\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate final @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate final @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate final  long mFirstInstallTime\npublic static  com.android.server.pm.pkg.PackageUserState copy(com.android.server.pm.pkg.PackageUserState)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isHidden()\npublic @java.lang.Override boolean isInstalled()\npublic @java.lang.Override boolean isInstantApp()\npublic @java.lang.Override boolean isNotLaunched()\npublic @java.lang.Override boolean isStopped()\npublic @java.lang.Override boolean isSuspended()\npublic @java.lang.Override boolean isVirtualPreload()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\nclass UserStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageUserState]\nprivate static final  int HIDDEN\nprivate static final  int INSTALLED\nprivate static final  int INSTANT_APP\nprivate static final  int NOT_LAUNCHED\nprivate static final  int STOPPED\nprivate static final  int SUSPENDED\nprivate static final  int VIRTUAL_PRELOAD\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
@@ -641,6 +644,11 @@
     }
 
     @DataClass.Generated.Member
+    public @Nullable String getSeInfo() {
+        return mSeInfo;
+    }
+
+    @DataClass.Generated.Member
     public boolean isHasSharedUser() {
         return mHasSharedUser;
     }
@@ -697,10 +705,10 @@
     }
 
     @DataClass.Generated(
-            time = 1661977809932L,
+            time = 1665778832668L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateImpl.java",
-            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibrary> mUsesLibraries\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nprivate static final  int APK_IN_UPDATED_APEX\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
+            inputSignatures = "private  int mBooleans\nprivate final @android.annotation.Nullable com.android.server.pm.pkg.AndroidPackage mAndroidPackage\nprivate final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.Nullable java.lang.String mVolumeUuid\nprivate final  int mAppId\nprivate final  int mCategoryOverride\nprivate final @android.annotation.Nullable java.lang.String mCpuAbiOverride\nprivate final  long mLastModifiedTime\nprivate final  long mLastUpdateTime\nprivate final  long mLongVersionCode\nprivate final @android.annotation.NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>> mMimeGroups\nprivate final @android.annotation.NonNull java.io.File mPath\nprivate final @android.annotation.Nullable java.lang.String mPrimaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSecondaryCpuAbi\nprivate final @android.annotation.Nullable java.lang.String mSeInfo\nprivate final  boolean mHasSharedUser\nprivate final  int mSharedUserAppId\nprivate final @android.annotation.NonNull java.lang.String[] mUsesSdkLibraries\nprivate final @android.annotation.NonNull long[] mUsesSdkLibrariesVersionsMajor\nprivate final @android.annotation.NonNull java.lang.String[] mUsesStaticLibraries\nprivate final @android.annotation.NonNull long[] mUsesStaticLibrariesVersions\nprivate final @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibrary> mUsesLibraries\nprivate final @android.annotation.NonNull java.util.List<java.lang.String> mUsesLibraryFiles\nprivate final @android.annotation.NonNull long[] mLastPackageUsageTime\nprivate final @android.annotation.NonNull android.content.pm.SigningInfo mSigningInfo\nprivate final @android.annotation.NonNull android.util.SparseArray<com.android.server.pm.pkg.PackageUserState> mUserStates\npublic static  com.android.server.pm.pkg.PackageState copy(com.android.server.pm.pkg.PackageStateInternal)\nprivate  void setBoolean(int,boolean)\nprivate  boolean getBoolean(int)\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserState getStateForUser(android.os.UserHandle)\npublic @java.lang.Override boolean isExternalStorage()\npublic @java.lang.Override boolean isForceQueryableOverride()\npublic @java.lang.Override boolean isHiddenUntilInstalled()\npublic @java.lang.Override boolean isInstallPermissionsFixed()\npublic @java.lang.Override boolean isOdm()\npublic @java.lang.Override boolean isOem()\npublic @java.lang.Override boolean isPrivileged()\npublic @java.lang.Override boolean isProduct()\npublic @java.lang.Override boolean isRequiredForSystemUser()\npublic @java.lang.Override boolean isSystem()\npublic @java.lang.Override boolean isSystemExt()\npublic @java.lang.Override boolean isUpdateAvailable()\npublic @java.lang.Override boolean isUpdatedSystemApp()\npublic @java.lang.Override boolean isApkInUpdatedApex()\npublic @java.lang.Override boolean isVendor()\npublic @java.lang.Override long getVersionCode()\npublic @java.lang.Override boolean hasSharedUser()\npublic @java.lang.Override int getSharedUserAppId()\nclass PackageStateImpl extends java.lang.Object implements [com.android.server.pm.pkg.PackageState]\nprivate static final  int SYSTEM\nprivate static final  int EXTERNAL_STORAGE\nprivate static final  int PRIVILEGED\nprivate static final  int OEM\nprivate static final  int VENDOR\nprivate static final  int PRODUCT\nprivate static final  int SYSTEM_EXT\nprivate static final  int REQUIRED_FOR_SYSTEM_USER\nprivate static final  int ODM\nprivate static final  int FORCE_QUERYABLE_OVERRIDE\nprivate static final  int HIDDEN_UNTIL_INSTALLED\nprivate static final  int INSTALL_PERMISSIONS_FIXED\nprivate static final  int UPDATE_AVAILABLE\nprivate static final  int UPDATED_SYSTEM_APP\nprivate static final  int APK_IN_UPDATED_APEX\nclass Booleans extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
index b22c038..57fbfe9 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java
@@ -22,6 +22,7 @@
 import android.annotation.Nullable;
 import android.content.pm.PackageManager;
 import android.content.pm.SharedLibraryInfo;
+import android.text.TextUtils;
 
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.DataClass;
@@ -62,6 +63,9 @@
     @Nullable
     private String overrideSeInfo;
 
+    @NonNull
+    private String seInfo;
+
     // TODO: Remove in favor of finer grained change notification
     @NonNull
     private final PackageSetting mPackageSetting;
@@ -138,6 +142,7 @@
         this.apkInUpdatedApex = other.apkInUpdatedApex;
         this.lastPackageUsageTimeInMills = other.lastPackageUsageTimeInMills;
         this.overrideSeInfo = other.overrideSeInfo;
+        this.seInfo = other.seInfo;
         mPackageSetting.onChanged();
     }
 
@@ -206,6 +211,13 @@
         return this;
     }
 
+    @NonNull
+    public PackageStateUnserialized setSeInfo(@NonNull String value) {
+        seInfo = TextUtils.safeIntern(value);
+        mPackageSetting.onChanged();
+        return this;
+    }
+
 
 
     // Code below generated by codegen v1.0.23.
@@ -271,15 +283,20 @@
     }
 
     @DataClass.Generated.Member
+    public @NonNull String getSeInfo() {
+        return seInfo;
+    }
+
+    @DataClass.Generated.Member
     public @NonNull PackageSetting getPackageSetting() {
         return mPackageSetting;
     }
 
     @DataClass.Generated(
-            time = 1661373697219L,
+            time = 1666291743725L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageStateUnserialized.java",
-            inputSignatures = "private  boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibraryWrapper> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate  boolean updatedSystemApp\nprivate  boolean apkInApex\nprivate  boolean apkInUpdatedApex\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate final @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryInfo(com.android.server.pm.pkg.SharedLibraryWrapper)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryFile(java.lang.String)\nprivate  long[] lazyInitLastPackageUsageTimeInMills()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic  long getLatestPackageUseTimeInMills()\npublic  long getLatestForegroundPackageUseTimeInMills()\npublic  void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInUpdatedApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
+            inputSignatures = "private  boolean hiddenUntilInstalled\nprivate @android.annotation.NonNull java.util.List<com.android.server.pm.pkg.SharedLibraryWrapper> usesLibraryInfos\nprivate @android.annotation.NonNull java.util.List<java.lang.String> usesLibraryFiles\nprivate  boolean updatedSystemApp\nprivate  boolean apkInApex\nprivate  boolean apkInUpdatedApex\nprivate volatile @android.annotation.NonNull long[] lastPackageUsageTimeInMills\nprivate @android.annotation.Nullable java.lang.String overrideSeInfo\nprivate @android.annotation.NonNull java.lang.String seInfo\nprivate final @android.annotation.NonNull com.android.server.pm.PackageSetting mPackageSetting\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryInfo(com.android.server.pm.pkg.SharedLibraryWrapper)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized addUsesLibraryFile(java.lang.String)\nprivate  long[] lazyInitLastPackageUsageTimeInMills()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(int,long)\npublic  long getLatestPackageUseTimeInMills()\npublic  long getLatestForegroundPackageUseTimeInMills()\npublic  void updateFrom(com.android.server.pm.pkg.PackageStateUnserialized)\npublic @android.annotation.NonNull java.util.List<android.content.pm.SharedLibraryInfo> getNonNativeUsesLibraryInfos()\npublic  com.android.server.pm.pkg.PackageStateUnserialized setHiddenUntilInstalled(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryInfos(java.util.List<android.content.pm.SharedLibraryInfo>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUsesLibraryFiles(java.util.List<java.lang.String>)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setUpdatedSystemApp(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setApkInUpdatedApex(boolean)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setLastPackageUsageTimeInMills(long)\npublic  com.android.server.pm.pkg.PackageStateUnserialized setOverrideSeInfo(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageStateUnserialized setSeInfo(java.lang.String)\nclass PackageStateUnserialized extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genSetters=true, genConstructor=false, genBuilder=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
index a536f90..b3deb1c 100644
--- a/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java
@@ -44,7 +44,7 @@
 /** @hide */
 @DataClass(genConstructor = false, genBuilder = false, genEqualsHashCode = true)
 @DataClass.Suppress({"mOverlayPathsLock", "mOverlayPaths", "mSharedLibraryOverlayPathsLock",
-        "mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths"})
+        "mSharedLibraryOverlayPaths", "setOverlayPaths", "setCachedOverlayPaths", "getWatchable"})
 public class PackageUserStateImpl extends WatchableImpl implements PackageUserStateInternal,
         Snappable {
 
@@ -92,8 +92,9 @@
 
     private long mFirstInstallTime;
 
+    // TODO(b/239050028): Remove, enforce notifying parent through PMS commit method
     @Nullable
-    private final Watchable mWatchable;
+    private Watchable mWatchable;
 
     @NonNull
     final SnapshotCache<PackageUserStateImpl> mSnapshot;
@@ -550,71 +551,30 @@
                 ? Collections.emptyMap() : mSharedLibraryOverlayPaths;
     }
 
-    @Override
-    public boolean equals(@Nullable Object o) {
-        // You can override field equality logic by defining either of the methods like:
-        // boolean fieldNameEquals(PackageUserStateImpl other) { ... }
-        // boolean fieldNameEquals(FieldType otherValue) { ... }
-
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        @SuppressWarnings("unchecked")
-        PackageUserStateImpl that = (PackageUserStateImpl) o;
-        //noinspection PointlessBooleanExpression
-        return Objects.equals(mDisabledComponentsWatched, that.mDisabledComponentsWatched)
-                && Objects.equals(mEnabledComponentsWatched, that.mEnabledComponentsWatched)
-                && mCeDataInode == that.mCeDataInode
-                && mInstalled == that.mInstalled
-                && mStopped == that.mStopped
-                && mNotLaunched == that.mNotLaunched
-                && mHidden == that.mHidden
-                && mDistractionFlags == that.mDistractionFlags
-                && mInstantApp == that.mInstantApp
-                && mVirtualPreload == that.mVirtualPreload
-                && mEnabledState == that.mEnabledState
-                && mInstallReason == that.mInstallReason
-                && mUninstallReason == that.mUninstallReason
-                && Objects.equals(mHarmfulAppWarning, that.mHarmfulAppWarning)
-                && Objects.equals(mLastDisableAppCaller, that.mLastDisableAppCaller)
-                && Objects.equals(mOverlayPaths, that.mOverlayPaths)
-                && Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
-                && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
-                && Objects.equals(mSuspendParams, that.mSuspendParams)
-                && Objects.equals(mComponentLabelIconOverrideMap,
-                        that.mComponentLabelIconOverrideMap)
-                && mFirstInstallTime == that.mFirstInstallTime
-                && Objects.equals(mWatchable, that.mWatchable);
+    @NonNull
+    public PackageUserStateImpl setWatchable(@NonNull Watchable watchable) {
+        mWatchable = watchable;
+        return this;
     }
 
-    @Override
-    public int hashCode() {
-        // You can override field hashCode logic by defining methods like:
-        // int fieldNameHashCode() { ... }
+    private boolean watchableEquals(Watchable other) {
+        // Ignore the Watchable for equality
+        return true;
+    }
 
-        int _hash = 1;
-        _hash = 31 * _hash + Objects.hashCode(mDisabledComponentsWatched);
-        _hash = 31 * _hash + Objects.hashCode(mEnabledComponentsWatched);
-        _hash = 31 * _hash + Long.hashCode(mCeDataInode);
-        _hash = 31 * _hash + Boolean.hashCode(mInstalled);
-        _hash = 31 * _hash + Boolean.hashCode(mStopped);
-        _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
-        _hash = 31 * _hash + Boolean.hashCode(mHidden);
-        _hash = 31 * _hash + mDistractionFlags;
-        _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
-        _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
-        _hash = 31 * _hash + mEnabledState;
-        _hash = 31 * _hash + mInstallReason;
-        _hash = 31 * _hash + mUninstallReason;
-        _hash = 31 * _hash + Objects.hashCode(mHarmfulAppWarning);
-        _hash = 31 * _hash + Objects.hashCode(mLastDisableAppCaller);
-        _hash = 31 * _hash + Objects.hashCode(mOverlayPaths);
-        _hash = 31 * _hash + Objects.hashCode(mSharedLibraryOverlayPaths);
-        _hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
-        _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
-        _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
-        _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
-        _hash = 31 * _hash + Objects.hashCode(mWatchable);
-        return _hash;
+    private int watchableHashCode() {
+        // Ignore the Watchable for equality
+        return 0;
+    }
+
+    private boolean snapshotEquals(SnapshotCache<PackageUserStateImpl> other) {
+        // Ignore the SnapshotCache for equality
+        return true;
+    }
+
+    private int snapshotHashCode() {
+        // Ignore the SnapshotCache for equality
+        return 0;
     }
 
 
@@ -736,11 +696,6 @@
     }
 
     @DataClass.Generated.Member
-    public @Nullable Watchable getWatchable() {
-        return mWatchable;
-    }
-
-    @DataClass.Generated.Member
     public @NonNull SnapshotCache<PackageUserStateImpl> getSnapshot() {
         return mSnapshot;
     }
@@ -778,11 +733,82 @@
         return this;
     }
 
+    @Override
+    @DataClass.Generated.Member
+    public boolean equals(@Nullable Object o) {
+        // You can override field equality logic by defining either of the methods like:
+        // boolean fieldNameEquals(PackageUserStateImpl other) { ... }
+        // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        @SuppressWarnings("unchecked")
+        PackageUserStateImpl that = (PackageUserStateImpl) o;
+        //noinspection PointlessBooleanExpression
+        return true
+                && Objects.equals(mDisabledComponentsWatched, that.mDisabledComponentsWatched)
+                && Objects.equals(mEnabledComponentsWatched, that.mEnabledComponentsWatched)
+                && mCeDataInode == that.mCeDataInode
+                && mInstalled == that.mInstalled
+                && mStopped == that.mStopped
+                && mNotLaunched == that.mNotLaunched
+                && mHidden == that.mHidden
+                && mDistractionFlags == that.mDistractionFlags
+                && mInstantApp == that.mInstantApp
+                && mVirtualPreload == that.mVirtualPreload
+                && mEnabledState == that.mEnabledState
+                && mInstallReason == that.mInstallReason
+                && mUninstallReason == that.mUninstallReason
+                && Objects.equals(mHarmfulAppWarning, that.mHarmfulAppWarning)
+                && Objects.equals(mLastDisableAppCaller, that.mLastDisableAppCaller)
+                && Objects.equals(mOverlayPaths, that.mOverlayPaths)
+                && Objects.equals(mSharedLibraryOverlayPaths, that.mSharedLibraryOverlayPaths)
+                && Objects.equals(mSplashScreenTheme, that.mSplashScreenTheme)
+                && Objects.equals(mSuspendParams, that.mSuspendParams)
+                && Objects.equals(mComponentLabelIconOverrideMap, that.mComponentLabelIconOverrideMap)
+                && mFirstInstallTime == that.mFirstInstallTime
+                && watchableEquals(that.mWatchable)
+                && snapshotEquals(that.mSnapshot);
+    }
+
+    @Override
+    @DataClass.Generated.Member
+    public int hashCode() {
+        // You can override field hashCode logic by defining methods like:
+        // int fieldNameHashCode() { ... }
+
+        int _hash = 1;
+        _hash = 31 * _hash + Objects.hashCode(mDisabledComponentsWatched);
+        _hash = 31 * _hash + Objects.hashCode(mEnabledComponentsWatched);
+        _hash = 31 * _hash + Long.hashCode(mCeDataInode);
+        _hash = 31 * _hash + Boolean.hashCode(mInstalled);
+        _hash = 31 * _hash + Boolean.hashCode(mStopped);
+        _hash = 31 * _hash + Boolean.hashCode(mNotLaunched);
+        _hash = 31 * _hash + Boolean.hashCode(mHidden);
+        _hash = 31 * _hash + mDistractionFlags;
+        _hash = 31 * _hash + Boolean.hashCode(mInstantApp);
+        _hash = 31 * _hash + Boolean.hashCode(mVirtualPreload);
+        _hash = 31 * _hash + mEnabledState;
+        _hash = 31 * _hash + mInstallReason;
+        _hash = 31 * _hash + mUninstallReason;
+        _hash = 31 * _hash + Objects.hashCode(mHarmfulAppWarning);
+        _hash = 31 * _hash + Objects.hashCode(mLastDisableAppCaller);
+        _hash = 31 * _hash + Objects.hashCode(mOverlayPaths);
+        _hash = 31 * _hash + Objects.hashCode(mSharedLibraryOverlayPaths);
+        _hash = 31 * _hash + Objects.hashCode(mSplashScreenTheme);
+        _hash = 31 * _hash + Objects.hashCode(mSuspendParams);
+        _hash = 31 * _hash + Objects.hashCode(mComponentLabelIconOverrideMap);
+        _hash = 31 * _hash + Long.hashCode(mFirstInstallTime);
+        _hash = 31 * _hash + watchableHashCode();
+        _hash = 31 * _hash + snapshotHashCode();
+        return _hash;
+    }
+
     @DataClass.Generated(
-            time = 1645040852569L,
+            time = 1668033772891L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/PackageUserStateImpl.java",
-            inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate  long mFirstInstallTime\nprivate final @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate  void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
+            inputSignatures = "protected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mDisabledComponentsWatched\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArraySet<java.lang.String> mEnabledComponentsWatched\nprivate  long mCeDataInode\nprivate  boolean mInstalled\nprivate  boolean mStopped\nprivate  boolean mNotLaunched\nprivate  boolean mHidden\nprivate  int mDistractionFlags\nprivate  boolean mInstantApp\nprivate  boolean mVirtualPreload\nprivate  int mEnabledState\nprivate @android.content.pm.PackageManager.InstallReason int mInstallReason\nprivate @android.content.pm.PackageManager.UninstallReason int mUninstallReason\nprivate @android.annotation.Nullable java.lang.String mHarmfulAppWarning\nprivate @android.annotation.Nullable java.lang.String mLastDisableAppCaller\nprivate @android.annotation.Nullable android.content.pm.overlay.OverlayPaths mOverlayPaths\nprotected @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths> mSharedLibraryOverlayPaths\nprivate @android.annotation.Nullable java.lang.String mSplashScreenTheme\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams> mSuspendParams\nprivate @android.annotation.Nullable com.android.server.utils.WatchedArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>> mComponentLabelIconOverrideMap\nprivate  long mFirstInstallTime\nprivate @android.annotation.Nullable com.android.server.utils.Watchable mWatchable\nfinal @android.annotation.NonNull com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> mSnapshot\nprivate  com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl> makeCache()\nprivate  void onChanged()\npublic @android.annotation.NonNull @java.lang.Override com.android.server.pm.pkg.PackageUserStateImpl snapshot()\npublic @android.annotation.Nullable boolean setOverlayPaths(android.content.pm.overlay.OverlayPaths)\npublic  boolean setSharedLibraryOverlayPaths(java.lang.String,android.content.pm.overlay.OverlayPaths)\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getDisabledComponentsNoCopy()\npublic @android.annotation.Nullable @java.lang.Override com.android.server.utils.WatchedArraySet<java.lang.String> getEnabledComponentsNoCopy()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getDisabledComponents()\npublic @android.annotation.NonNull @java.lang.Override android.util.ArraySet<java.lang.String> getEnabledComponents()\npublic @java.lang.Override boolean isComponentEnabled(java.lang.String)\npublic @java.lang.Override boolean isComponentDisabled(java.lang.String)\npublic @java.lang.Override android.content.pm.overlay.OverlayPaths getAllOverlayPaths()\npublic @com.android.internal.annotations.VisibleForTesting boolean overrideLabelAndIcon(android.content.ComponentName,java.lang.String,java.lang.Integer)\npublic  void resetOverrideComponentLabelIcon()\npublic @android.annotation.Nullable android.util.Pair<java.lang.String,java.lang.Integer> getOverrideLabelIconForComponent(android.content.ComponentName)\npublic @java.lang.Override boolean isSuspended()\npublic  com.android.server.pm.pkg.PackageUserStateImpl putSuspendParams(java.lang.String,com.android.server.pm.pkg.SuspendParams)\npublic  com.android.server.pm.pkg.PackageUserStateImpl removeSuspension(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(android.util.ArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDisabledComponents(com.android.server.utils.WatchedArraySet<java.lang.String>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setCeDataInode(long)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstalled(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setStopped(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setNotLaunched(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHidden(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setDistractionFlags(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstantApp(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setVirtualPreload(boolean)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setEnabledState(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setInstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setUninstallReason(int)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setHarmfulAppWarning(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setLastDisableAppCaller(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSharedLibraryOverlayPaths(android.util.ArrayMap<java.lang.String,android.content.pm.overlay.OverlayPaths>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSplashScreenTheme(java.lang.String)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setSuspendParams(android.util.ArrayMap<java.lang.String,com.android.server.pm.pkg.SuspendParams>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setComponentLabelIconOverrideMap(android.util.ArrayMap<android.content.ComponentName,android.util.Pair<java.lang.String,java.lang.Integer>>)\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setFirstInstallTime(long)\npublic @android.annotation.NonNull @java.lang.Override java.util.Map<java.lang.String,android.content.pm.overlay.OverlayPaths> getSharedLibraryOverlayPaths()\npublic @android.annotation.NonNull com.android.server.pm.pkg.PackageUserStateImpl setWatchable(com.android.server.utils.Watchable)\nprivate  boolean watchableEquals(com.android.server.utils.Watchable)\nprivate  int watchableHashCode()\nprivate  boolean snapshotEquals(com.android.server.utils.SnapshotCache<com.android.server.pm.pkg.PackageUserStateImpl>)\nprivate  int snapshotHashCode()\nclass PackageUserStateImpl extends com.android.server.utils.WatchableImpl implements [com.android.server.pm.pkg.PackageUserStateInternal, com.android.server.utils.Snappable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=false, genEqualsHashCode=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
index e019215..1826f7a 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivity.java
@@ -98,8 +98,8 @@
     boolean isSupportsSizeChanges();
 
     /**
-     * Gets the category of the target display this activity is supposed to run on.
+     * Gets the required category of the display this activity is supposed to run on.
      */
     @Nullable
-    String getTargetDisplayCategory();
+    String getRequiredDisplayCategory();
 }
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
index 278e547..68d5428 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java
@@ -97,7 +97,7 @@
     private ActivityInfo.WindowLayout windowLayout;
 
     @Nullable
-    private String mTargetDisplayCategory;
+    private String mRequiredDisplayCategory;
 
     public ParsedActivityImpl(ParsedActivityImpl other) {
         super(other);
@@ -125,7 +125,7 @@
         this.colorMode = other.colorMode;
         this.windowLayout = other.windowLayout;
         this.mKnownActivityEmbeddingCerts = other.mKnownActivityEmbeddingCerts;
-        this.mTargetDisplayCategory = other.mTargetDisplayCategory;
+        this.mRequiredDisplayCategory = other.mRequiredDisplayCategory;
     }
 
     /**
@@ -193,7 +193,7 @@
         alias.requestedVrComponent = target.getRequestedVrComponent();
         alias.setDirectBootAware(target.isDirectBootAware());
         alias.setProcessName(target.getProcessName());
-        alias.setTargetDisplayCategory(target.getTargetDisplayCategory());
+        alias.setRequiredDisplayCategory(target.getRequiredDisplayCategory());
         return alias;
 
         // Not all attributes from the target ParsedActivity are copied to the alias.
@@ -321,7 +321,7 @@
             dest.writeBoolean(false);
         }
         sForStringSet.parcel(this.mKnownActivityEmbeddingCerts, dest, flags);
-        dest.writeString8(this.mTargetDisplayCategory);
+        dest.writeString8(this.mRequiredDisplayCategory);
     }
 
     public ParsedActivityImpl() {
@@ -356,7 +356,7 @@
             windowLayout = new ActivityInfo.WindowLayout(in);
         }
         this.mKnownActivityEmbeddingCerts = sForStringSet.unparcel(in);
-        this.mTargetDisplayCategory = in.readString8();
+        this.mRequiredDisplayCategory = in.readString8();
     }
 
     @NonNull
@@ -414,7 +414,7 @@
             int rotationAnimation,
             int colorMode,
             @Nullable ActivityInfo.WindowLayout windowLayout,
-            @Nullable String targetDisplayCategory) {
+            @Nullable String requiredDisplayCategory) {
         this.theme = theme;
         this.uiOptions = uiOptions;
         this.targetActivity = targetActivity;
@@ -439,7 +439,7 @@
         this.rotationAnimation = rotationAnimation;
         this.colorMode = colorMode;
         this.windowLayout = windowLayout;
-        this.mTargetDisplayCategory = targetDisplayCategory;
+        this.mRequiredDisplayCategory = requiredDisplayCategory;
 
         // onConstructed(); // You can define this method to get a callback
     }
@@ -560,8 +560,8 @@
     }
 
     @DataClass.Generated.Member
-    public @Nullable String getTargetDisplayCategory() {
-        return mTargetDisplayCategory;
+    public @Nullable String getRequiredDisplayCategory() {
+        return mRequiredDisplayCategory;
     }
 
     @DataClass.Generated.Member
@@ -691,16 +691,16 @@
     }
 
     @DataClass.Generated.Member
-    public @NonNull ParsedActivityImpl setTargetDisplayCategory(@NonNull String value) {
-        mTargetDisplayCategory = value;
+    public @NonNull ParsedActivityImpl setRequiredDisplayCategory(@NonNull String value) {
+        mRequiredDisplayCategory = value;
         return this;
     }
 
     @DataClass.Generated(
-            time = 1664805688714L,
+            time = 1669437519576L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/services/core/java/com/android/server/pm/pkg/component/ParsedActivityImpl.java",
-            inputSignatures = "private  int theme\nprivate  int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate  int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate  int launchMode\nprivate  int documentLaunchMode\nprivate  int maxRecents\nprivate  int configChanges\nprivate  int softInputMode\nprivate  int persistableMode\nprivate  int lockTaskLaunchMode\nprivate  int screenOrientation\nprivate  int resizeMode\nprivate  float maxAspectRatio\nprivate  float minAspectRatio\nprivate  boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate  int rotationAnimation\nprivate  int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mTargetDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.server.pm.pkg.component.ParsedActivity)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic  void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic  java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.server.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
+            inputSignatures = "private  int theme\nprivate  int uiOptions\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String targetActivity\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String parentActivityName\nprivate @android.annotation.Nullable java.lang.String taskAffinity\nprivate  int privateFlags\nprivate @android.annotation.Nullable @com.android.internal.util.DataClass.ParcelWith(com.android.internal.util.Parcelling.BuiltIn.ForInternedString.class) java.lang.String permission\nprivate @android.annotation.Nullable java.util.Set<java.lang.String> mKnownActivityEmbeddingCerts\nprivate  int launchMode\nprivate  int documentLaunchMode\nprivate  int maxRecents\nprivate  int configChanges\nprivate  int softInputMode\nprivate  int persistableMode\nprivate  int lockTaskLaunchMode\nprivate  int screenOrientation\nprivate  int resizeMode\nprivate  float maxAspectRatio\nprivate  float minAspectRatio\nprivate  boolean supportsSizeChanges\nprivate @android.annotation.Nullable java.lang.String requestedVrComponent\nprivate  int rotationAnimation\nprivate  int colorMode\nprivate @android.annotation.Nullable android.content.pm.ActivityInfo.WindowLayout windowLayout\nprivate @android.annotation.Nullable java.lang.String mRequiredDisplayCategory\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<com.android.server.pm.pkg.component.ParsedActivityImpl> CREATOR\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAppDetailsActivity(java.lang.String,java.lang.String,int,java.lang.String,boolean)\nstatic @android.annotation.NonNull com.android.server.pm.pkg.component.ParsedActivityImpl makeAlias(java.lang.String,com.android.server.pm.pkg.component.ParsedActivity)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setMaxAspectRatio(int,float)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setMinAspectRatio(int,float)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setTargetActivity(java.lang.String)\npublic  com.android.server.pm.pkg.component.ParsedActivityImpl setPermission(java.lang.String)\npublic @android.annotation.NonNull @java.lang.Override java.util.Set<java.lang.String> getKnownActivityEmbeddingCerts()\npublic  void setKnownActivityEmbeddingCerts(java.util.Set<java.lang.String>)\npublic  java.lang.String toString()\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\nclass ParsedActivityImpl extends com.android.server.pm.pkg.component.ParsedMainComponentImpl implements [com.android.server.pm.pkg.component.ParsedActivity, android.os.Parcelable]\n@com.android.internal.util.DataClass(genGetters=true, genSetters=true, genBuilder=false, genParcelable=false)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
index 305062b..ea791e1 100644
--- a/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/component/ParsedActivityUtils.java
@@ -220,17 +220,17 @@
                 pkg.setVisibleToInstantApps(true);
             }
 
-            String targetDisplayCategory = sa.getNonConfigurationString(
-                    R.styleable.AndroidManifestActivity_targetDisplayCategory, 0);
+            String requiredDisplayCategory = sa.getNonConfigurationString(
+                    R.styleable.AndroidManifestActivity_requiredDisplayCategory, 0);
 
-            if (targetDisplayCategory != null
-                    && FrameworkParsingPackageUtils.validateName(targetDisplayCategory,
+            if (requiredDisplayCategory != null
+                    && FrameworkParsingPackageUtils.validateName(requiredDisplayCategory,
                     false /* requireSeparator */, false /* requireFilename */) != null) {
-                return input.error("targetDisplayCategory attribute can only consists of "
-                        + "alphanumeric characters, '_', and '.'");
+                return input.error("requiredDisplayCategory attribute can only consist "
+                        + "of alphanumeric characters, '_', and '.'");
             }
 
-            activity.setTargetDisplayCategory(targetDisplayCategory);
+            activity.setRequiredDisplayCategory(requiredDisplayCategory);
 
             return parseActivityOrAlias(activity, pkg, tag, parser, res, sa, receiver,
                     false /*isAlias*/, visibleToEphemeral, input,
diff --git a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
index e736f43..4a8ef96 100644
--- a/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
+++ b/services/core/java/com/android/server/pm/pkg/mutate/PackageStateMutator.java
@@ -40,6 +40,8 @@
     private final Function<String, PackageSetting> mActiveStateFunction;
     private final Function<String, PackageSetting> mDisabledStateFunction;
 
+    private final ArraySet<PackageSetting> mChangedStates = new ArraySet<>();
+
     public PackageStateMutator(@NonNull Function<String, PackageSetting> activeStateFunction,
             @NonNull Function<String, PackageSetting> disabledStateFunction) {
         mActiveStateFunction = activeStateFunction;
@@ -52,23 +54,23 @@
 
     @NonNull
     public PackageStateWrite forPackage(@NonNull String packageName) {
-        return mStateWrite.setState(mActiveStateFunction.apply(packageName));
+        return setState(mActiveStateFunction.apply(packageName));
     }
 
     @Nullable
     public PackageStateWrite forPackageNullable(@NonNull String packageName) {
         final PackageSetting packageState = mActiveStateFunction.apply(packageName);
-        mStateWrite.setState(packageState);
+        setState(packageState);
         if (packageState == null) {
             return null;
         }
 
-        return mStateWrite.setState(packageState);
+        return setState(packageState);
     }
 
     @NonNull
     public PackageStateWrite forDisabledSystemPackage(@NonNull String packageName) {
-        return mStateWrite.setState(mDisabledStateFunction.apply(packageName));
+        return setState(mDisabledStateFunction.apply(packageName));
     }
 
     @Nullable
@@ -78,7 +80,7 @@
             return null;
         }
 
-        return mStateWrite.setState(packageState);
+        return setState(packageState);
     }
 
     @NonNull
@@ -109,6 +111,21 @@
         }
     }
 
+    public void onFinished() {
+        for (int index = 0; index < mChangedStates.size(); index++) {
+            mChangedStates.valueAt(index).onChanged();
+        }
+    }
+
+    @NonNull
+    private StateWriteWrapper setState(@Nullable PackageSetting state) {
+        // State can be nullable because this infrastructure no-ops on non-existent states
+        if (state != null) {
+            mChangedStates.add(state);
+        }
+        return mStateWrite.setState(state);
+    }
+
     public static class InitialState {
 
         private final int mPackageSequence;
@@ -173,8 +190,11 @@
         @NonNull
         @Override
         public PackageUserStateWrite userState(int userId) {
-            return mUserStateWrite.setStates(
-                    mState == null ? null : mState.getOrCreateUserState(userId));
+            var userState = mState == null ? null : mState.getOrCreateUserState(userId);
+            if (userState != null) {
+                userState.setWatchable(mState);
+            }
+            return mUserStateWrite.setStates(userState);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index e61effa..d6cac33 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -232,7 +232,7 @@
             }
         };
 
-        final ArrayList<PermissionInfo> dangerousPerms =
+        final List<PermissionInfo> dangerousPerms =
                 mPermissionManagerInternal.getAllPermissionsWithProtection(
                         PermissionInfo.PROTECTION_DANGEROUS);
         try {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 3aa333a..9d58a73 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -151,6 +151,7 @@
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.service.dreams.DreamManagerInternal;
 import android.service.dreams.DreamService;
 import android.service.dreams.IDreamManager;
@@ -516,6 +517,7 @@
     int mDoublePressOnStemPrimaryBehavior;
     int mTriplePressOnStemPrimaryBehavior;
     int mLongPressOnStemPrimaryBehavior;
+    boolean mStylusButtonsDisabled = false;
     boolean mHasSoftInput = false;
     boolean mHapticTextHandleEnabled;
     boolean mUseTvRouting;
@@ -771,6 +773,9 @@
             resolver.registerContentObserver(Settings.Global.getUriFor(
                     Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE), false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.STYLUS_BUTTONS_DISABLED), false, this,
+                    UserHandle.USER_ALL);
             updateSettings();
         }
 
@@ -2560,6 +2565,9 @@
                     Settings.Global.KEY_CHORD_POWER_VOLUME_UP,
                     mContext.getResources().getInteger(
                             com.android.internal.R.integer.config_keyChordPowerVolumeUp));
+
+            mStylusButtonsDisabled = Settings.Secure.getIntForUser(resolver,
+                    Secure.STYLUS_BUTTONS_DISABLED, 0, UserHandle.USER_CURRENT) == 1;
         }
         if (updateRotation) {
             updateRotation(true);
@@ -4183,7 +4191,9 @@
             case KeyEvent.KEYCODE_DEMO_APP_3:
             case KeyEvent.KEYCODE_DEMO_APP_4: {
                 // TODO(b/254604589): Dispatch KeyEvent to System UI.
-                sendSystemKeyToStatusBarAsync(keyCode);
+                if (!mStylusButtonsDisabled) {
+                    sendSystemKeyToStatusBarAsync(keyCode);
+                }
 
                 // Just drop if keys are not intercepted for direct key.
                 result &= ~ACTION_PASS_TO_USER;
@@ -4208,11 +4218,13 @@
             wakeUpFromWakeKey(event);
         }
 
-        if ((result & ACTION_PASS_TO_USER) != 0) {
+        if ((result & ACTION_PASS_TO_USER) != 0 && !mPerDisplayFocusEnabled
+                && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
             // If the key event is targeted to a specific display, then the user is interacting with
-            // that display. Therefore, give focus to the display that the user is interacting with.
-            if (!mPerDisplayFocusEnabled
-                    && displayId != INVALID_DISPLAY && displayId != mTopFocusedDisplayId) {
+            // that display. Therefore, give focus to the display that the user is interacting with,
+            // unless that display maintains its own focus.
+            Display display = mDisplayManager.getDisplay(displayId);
+            if ((display.getFlags() & Display.FLAG_OWN_FOCUS) == 0) {
                 // An event is targeting a non-focused display. Move the display to top so that
                 // it can become the focused display to interact with the user.
                 // This should be done asynchronously, once the focus logic is fully moved to input
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 7737421..85f1357 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -200,6 +200,9 @@
             if (!mKeyguardState.enabled) {
                 mKeyguardService.setKeyguardEnabled(mKeyguardState.enabled);
             }
+            if (mKeyguardState.dreaming) {
+                mKeyguardService.onDreamingStarted();
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/power/PowerGroup.java b/services/core/java/com/android/server/power/PowerGroup.java
index 431cf38..1c4e143 100644
--- a/services/core/java/com/android/server/power/PowerGroup.java
+++ b/services/core/java/com/android/server/power/PowerGroup.java
@@ -324,11 +324,6 @@
         return mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DIM;
     }
 
-    public boolean isPolicyVrLocked() {
-        return mDisplayPowerRequest.isVr();
-
-    }
-
     public boolean isBrightOrDimLocked() {
         return mDisplayPowerRequest.isBrightOrDim();
     }
@@ -382,7 +377,7 @@
 
     @VisibleForTesting
     int getDesiredScreenPolicyLocked(boolean quiescent, boolean dozeAfterScreenOff,
-            boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress) {
+            boolean bootCompleted, boolean screenBrightnessBoostInProgress) {
         final int wakefulness = getWakefulnessLocked();
         final int wakeLockSummary = getWakeLockSummaryLocked();
         if (wakefulness == WAKEFULNESS_ASLEEP || quiescent) {
@@ -398,13 +393,6 @@
             // doze after screen off.  This causes the screen off transition to be skipped.
         }
 
-        // It is important that POLICY_VR check happens after the wakefulness checks above so
-        // that VR-mode does not prevent displays from transitioning to the correct state when
-        // dozing or sleeping.
-        if (vrModeEnabled) {
-            return DisplayPowerRequest.POLICY_VR;
-        }
-
         if ((wakeLockSummary & WAKE_LOCK_SCREEN_BRIGHT) != 0
                 || !bootCompleted
                 || (getUserActivitySummaryLocked() & USER_ACTIVITY_SCREEN_BRIGHT) != 0
@@ -423,10 +411,10 @@
             boolean useProximitySensor, boolean boostScreenBrightness, int dozeScreenState,
             float dozeScreenBrightness, boolean overrideDrawWakeLock,
             PowerSaveState powerSaverState, boolean quiescent, boolean dozeAfterScreenOff,
-            boolean vrModeEnabled, boolean bootCompleted, boolean screenBrightnessBoostInProgress,
+            boolean bootCompleted, boolean screenBrightnessBoostInProgress,
             boolean waitForNegativeProximity) {
         mDisplayPowerRequest.policy = getDesiredScreenPolicyLocked(quiescent, dozeAfterScreenOff,
-                vrModeEnabled, bootCompleted, screenBrightnessBoostInProgress);
+                bootCompleted, screenBrightnessBoostInProgress);
         mDisplayPowerRequest.screenBrightnessOverride = screenBrightnessOverride;
         mDisplayPowerRequest.useAutoBrightness = autoBrightness;
         mDisplayPowerRequest.useProximitySensor = useProximitySensor;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9281f4b..6e3c827 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -90,8 +90,6 @@
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.dreams.DreamManagerInternal;
-import android.service.vr.IVrManager;
-import android.service.vr.IVrStateCallbacks;
 import android.sysprop.InitProperties;
 import android.sysprop.PowerProperties;
 import android.util.ArrayMap;
@@ -196,8 +194,6 @@
     private static final int DIRTY_SCREEN_BRIGHTNESS_BOOST = 1 << 11;
     // Dirty bit: sQuiescent changed
     private static final int DIRTY_QUIESCENT = 1 << 12;
-    // Dirty bit: VR Mode enabled changed
-    private static final int DIRTY_VR_MODE_CHANGED = 1 << 13;
     // Dirty bit: attentive timer may have timed out
     private static final int DIRTY_ATTENTIVE = 1 << 14;
     // Dirty bit: display group wakefulness has changed
@@ -580,9 +576,6 @@
     public final float mScreenBrightnessDefault;
     public final float mScreenBrightnessDoze;
     public final float mScreenBrightnessDim;
-    public final float mScreenBrightnessMinimumVr;
-    public final float mScreenBrightnessMaximumVr;
-    public final float mScreenBrightnessDefaultVr;
 
     // Value we store for tracking face down behavior.
     private boolean mIsFaceDown = false;
@@ -666,9 +659,6 @@
     // True if double tap to wake is enabled
     private boolean mDoubleTapWakeEnabled;
 
-    // True if we are currently in VR Mode.
-    private boolean mIsVrModeEnabled;
-
     // True if we in the process of performing a forceSuspend
     private boolean mForceSuspendActive;
 
@@ -1145,29 +1135,6 @@
             mScreenBrightnessDim = dim;
         }
 
-        final float vrMin = mContext.getResources().getFloat(com.android.internal.R.dimen
-                .config_screenBrightnessSettingForVrMinimumFloat);
-        final float vrMax = mContext.getResources().getFloat(com.android.internal.R.dimen
-                .config_screenBrightnessSettingForVrMaximumFloat);
-        final float vrDef = mContext.getResources().getFloat(com.android.internal.R.dimen
-                .config_screenBrightnessSettingForVrDefaultFloat);
-        if (vrMin == INVALID_BRIGHTNESS_IN_CONFIG || vrMax == INVALID_BRIGHTNESS_IN_CONFIG
-                || vrDef == INVALID_BRIGHTNESS_IN_CONFIG) {
-            mScreenBrightnessMinimumVr = BrightnessSynchronizer.brightnessIntToFloat(
-                    mContext.getResources().getInteger(com.android.internal.R.integer
-                            .config_screenBrightnessForVrSettingMinimum));
-            mScreenBrightnessMaximumVr = BrightnessSynchronizer.brightnessIntToFloat(
-                    mContext.getResources().getInteger(com.android.internal.R.integer
-                            .config_screenBrightnessForVrSettingMaximum));
-            mScreenBrightnessDefaultVr = BrightnessSynchronizer.brightnessIntToFloat(
-                    mContext.getResources().getInteger(com.android.internal.R.integer
-                            .config_screenBrightnessForVrSettingDefault));
-        } else {
-            mScreenBrightnessMinimumVr = vrMin;
-            mScreenBrightnessMaximumVr = vrMax;
-            mScreenBrightnessDefaultVr = vrDef;
-        }
-
         synchronized (mLock) {
             mBootingSuspendBlocker =
                     mInjector.createSuspendBlocker(this, "PowerManagerService.Booting");
@@ -1373,14 +1340,6 @@
         resolver.registerContentObserver(Settings.Global.getUriFor(
                 Settings.Global.DEVICE_DEMO_MODE),
                 false, mSettingsObserver, UserHandle.USER_SYSTEM);
-        IVrManager vrManager = IVrManager.Stub.asInterface(getBinderService(Context.VR_SERVICE));
-        if (vrManager != null) {
-            try {
-                vrManager.registerListener(mVrStateCallbacks);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to register VR mode state listener: " + e);
-            }
-        }
 
         // Register for broadcasts from other components of the system.
         IntentFilter filter = new IntentFilter();
@@ -2204,6 +2163,15 @@
                     if (sQuiescent) {
                         mDirty |= DIRTY_QUIESCENT;
                     }
+                    PowerGroup defaultGroup = mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP);
+                    if (defaultGroup.getWakefulnessLocked() == WAKEFULNESS_DOZING) {
+                        // Workaround for b/187231320 where the AOD can get stuck in a "half on /
+                        // half off" state when a non-default-group VirtualDisplay causes the global
+                        // wakefulness to change to awake, even though the default display is
+                        // dozing. We set sandman summoned to restart dreaming to get it unstuck.
+                        // TODO(b/255688811) - fix this so that AOD never gets interrupted at all.
+                        defaultGroup.setSandmanSummonedLocked(true);
+                    }
                     break;
 
                 case WAKEFULNESS_ASLEEP:
@@ -2839,7 +2807,7 @@
                         >= powerGroup.getLastWakeTimeLocked()) {
                     groupNextTimeout = lastUserActivityTimeNoChangeLights + screenOffTimeout;
                     if (now < groupNextTimeout) {
-                        if (powerGroup.isPolicyBrightLocked() || powerGroup.isPolicyVrLocked()) {
+                        if (powerGroup.isPolicyBrightLocked()) {
                             groupUserActivitySummary = USER_ACTIVITY_SCREEN_BRIGHT;
                         } else if (powerGroup.isPolicyDimLocked()) {
                             groupUserActivitySummary = USER_ACTIVITY_SCREEN_DIM;
@@ -3406,7 +3374,6 @@
                 || !mDreamsSupportedConfig
                 || !mDreamsEnabledSetting
                 || !(powerGroup.isBrightOrDimLocked())
-                || powerGroup.isPolicyVrLocked()
                 || (powerGroup.getUserActivitySummaryLocked() & (USER_ACTIVITY_SCREEN_BRIGHT
                 | USER_ACTIVITY_SCREEN_DIM | USER_ACTIVITY_SCREEN_DREAM)) == 0) {
             return false;
@@ -3451,8 +3418,8 @@
         final boolean oldPowerGroupsReady = areAllPowerGroupsReadyLocked();
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_WAKEFULNESS
                 | DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED | DIRTY_BOOT_COMPLETED
-                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST | DIRTY_VR_MODE_CHANGED |
-                DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_WAKEFULNESS)) != 0) {
+                | DIRTY_SETTINGS | DIRTY_SCREEN_BRIGHTNESS_BOOST
+                | DIRTY_QUIESCENT | DIRTY_DISPLAY_GROUP_WAKEFULNESS)) != 0) {
             if ((dirty & DIRTY_QUIESCENT) != 0) {
                 if (areAllPowerGroupsReadyLocked()) {
                     sQuiescent = false;
@@ -3487,7 +3454,7 @@
                         mDozeScreenBrightnessOverrideFromDreamManagerFloat,
                         mDrawWakeLockOverrideFromSidekick,
                         mBatterySaverPolicy.getBatterySaverPolicy(ServiceType.SCREEN_BRIGHTNESS),
-                        sQuiescent, mDozeAfterScreenOff, mIsVrModeEnabled, mBootCompleted,
+                        sQuiescent, mDozeAfterScreenOff, mBootCompleted,
                         mScreenBrightnessBoostInProgress, mRequestWaitForNegativeProximity);
                 int wakefulness = powerGroup.getWakefulnessLocked();
                 if (DEBUG_SPEW) {
@@ -3505,7 +3472,6 @@
                             + ", useAutoBrightness=" + autoBrightness
                             + ", mScreenBrightnessBoostInProgress="
                             + mScreenBrightnessBoostInProgress
-                            + ", mIsVrModeEnabled= " + mIsVrModeEnabled
                             + ", sQuiescent=" + sQuiescent);
                 }
 
@@ -3553,7 +3519,7 @@
     }
 
     private boolean shouldBoostScreenBrightness() {
-        return !mIsVrModeEnabled && mScreenBrightnessBoostInProgress;
+        return mScreenBrightnessBoostInProgress;
     }
 
     private static boolean isValidBrightness(float value) {
@@ -3564,7 +3530,7 @@
     @GuardedBy("mLock")
     int getDesiredScreenPolicyLocked(int groupId) {
         return mPowerGroups.get(groupId).getDesiredScreenPolicyLocked(sQuiescent,
-                mDozeAfterScreenOff, mIsVrModeEnabled, mBootCompleted,
+                mDozeAfterScreenOff, mBootCompleted,
                 mScreenBrightnessBoostInProgress);
     }
 
@@ -3645,8 +3611,7 @@
     @GuardedBy("mLock")
     private boolean shouldUseProximitySensorLocked() {
         // Use default display group for proximity sensor.
-        return !mIsVrModeEnabled
-                && (mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).getWakeLockSummaryLocked()
+        return (mPowerGroups.get(Display.DEFAULT_DISPLAY_GROUP).getWakeLockSummaryLocked()
                         & WAKE_LOCK_PROXIMITY_SCREEN_OFF) != 0;
     }
 
@@ -4270,11 +4235,6 @@
         }
     }
 
-    @VisibleForTesting
-    void setVrModeEnabled(boolean enabled) {
-        mIsVrModeEnabled = enabled;
-    }
-
     private void setPowerBoostInternal(int boost, int durationMs) {
         // Maybe filter the event.
         mNativeWrapper.nativeSetPowerBoost(boost, durationMs);
@@ -4544,7 +4504,6 @@
             pw.println("  mScreenBrightnessMaximum=" + mScreenBrightnessMaximum);
             pw.println("  mScreenBrightnessDefault=" + mScreenBrightnessDefault);
             pw.println("  mDoubleTapWakeEnabled=" + mDoubleTapWakeEnabled);
-            pw.println("  mIsVrModeEnabled=" + mIsVrModeEnabled);
             pw.println("  mForegroundProfile=" + mForegroundProfile);
             pw.println("  mUserId=" + mUserId);
 
@@ -4955,9 +4914,6 @@
             proto.write(
                     PowerServiceSettingsAndConfigurationDumpProto.IS_DOUBLE_TAP_WAKE_ENABLED,
                     mDoubleTapWakeEnabled);
-            proto.write(
-                    PowerServiceSettingsAndConfigurationDumpProto.IS_VR_MODE_ENABLED,
-                    mIsVrModeEnabled);
             proto.end(settingsAndConfigurationToken);
 
             final long attentiveTimeout = getAttentiveTimeoutLocked();
@@ -5086,21 +5042,6 @@
         }
     }
 
-    private final IVrStateCallbacks mVrStateCallbacks = new IVrStateCallbacks.Stub() {
-        @Override
-        public void onVrStateChanged(boolean enabled) {
-            setPowerModeInternal(Mode.VR, enabled);
-
-            synchronized (mLock) {
-                if (mIsVrModeEnabled != enabled) {
-                    setVrModeEnabled(enabled);
-                    mDirty |= DIRTY_VR_MODE_CHANGED;
-                    updatePowerStateLocked();
-                }
-            }
-        }
-    };
-
     private final AmbientDisplaySuppressionChangedCallback mAmbientSuppressionChangedCallback =
             new AmbientDisplaySuppressionChangedCallback() {
                 @Override
@@ -5828,12 +5769,6 @@
                     return mScreenBrightnessDim;
                 case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DOZE:
                     return mScreenBrightnessDoze;
-                case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MINIMUM_VR:
-                    return mScreenBrightnessMinimumVr;
-                case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_MAXIMUM_VR:
-                    return mScreenBrightnessMaximumVr;
-                case PowerManager.BRIGHTNESS_CONSTRAINT_TYPE_DEFAULT_VR:
-                    return mScreenBrightnessDefaultVr;
                 default:
                     return PowerManager.BRIGHTNESS_INVALID_FLOAT;
             }
@@ -6617,7 +6552,6 @@
                 case Display.STATE_DOZE_SUSPEND:
                 case Display.STATE_ON_SUSPEND:
                 case Display.STATE_ON:
-                case Display.STATE_VR:
                     break;
                 default:
                     screenState = Display.STATE_UNKNOWN;
diff --git a/services/core/java/com/android/server/powerstats/PowerStatsService.java b/services/core/java/com/android/server/powerstats/PowerStatsService.java
index 9953ca8..1358417 100644
--- a/services/core/java/com/android/server/powerstats/PowerStatsService.java
+++ b/services/core/java/com/android/server/powerstats/PowerStatsService.java
@@ -83,6 +83,9 @@
     @Nullable
     @GuardedBy("this")
     private Looper mLooper;
+    @Nullable
+    @GuardedBy("this")
+    private EnergyConsumer[] mEnergyConsumers = null;
 
     @VisibleForTesting
     static class Injector {
@@ -260,6 +263,15 @@
         }
     }
 
+    private EnergyConsumer[] getEnergyConsumerInfo() {
+        synchronized (this) {
+            if (mEnergyConsumers == null) {
+                mEnergyConsumers = getPowerStatsHal().getEnergyConsumerInfo();
+            }
+            return mEnergyConsumers;
+        }
+    }
+
     public PowerStatsService(Context context) {
         this(context, new Injector());
     }
@@ -327,7 +339,69 @@
 
     private void getEnergyConsumedAsync(CompletableFuture<EnergyConsumerResult[]> future,
             int[] energyConsumerIds) {
-        future.complete(getPowerStatsHal().getEnergyConsumed(energyConsumerIds));
+        EnergyConsumerResult[] results = getPowerStatsHal().getEnergyConsumed(energyConsumerIds);
+
+        // STOPSHIP(253292374): Remove once missing EnergyConsumer results issue is resolved.
+        EnergyConsumer[] energyConsumers = getEnergyConsumerInfo();
+        if (energyConsumers != null) {
+            final int expectedLength;
+            if (energyConsumerIds.length == 0) {
+                // Empty request is a request for all available EnergyConsumers.
+                expectedLength = energyConsumers.length;
+            } else {
+                expectedLength = energyConsumerIds.length;
+            }
+
+            if (results == null || expectedLength != results.length) {
+                // Mismatch in requested/received energy consumer data.
+                StringBuilder sb = new StringBuilder();
+                sb.append("Requested ids:");
+                if (energyConsumerIds.length == 0) {
+                    sb.append("ALL");
+                }
+                sb.append("[");
+                for (int i = 0; i < expectedLength; i++) {
+                    final int id = energyConsumerIds[i];
+                    sb.append(id);
+                    sb.append("(type:");
+                    sb.append(energyConsumers[id].type);
+                    sb.append(",ord:");
+                    sb.append(energyConsumers[id].ordinal);
+                    sb.append(",name:");
+                    sb.append(energyConsumers[id].name);
+                    sb.append(")");
+                    if (i != expectedLength - 1) {
+                        sb.append(", ");
+                    }
+                }
+                sb.append("]");
+
+                sb.append(", Received result ids:");
+                if (results == null) {
+                    sb.append("null");
+                } else {
+                    sb.append("[");
+                    final int resultLength = results.length;
+                    for (int i = 0; i < resultLength; i++) {
+                        final int id = results[i].id;
+                        sb.append(id);
+                        sb.append("(type:");
+                        sb.append(energyConsumers[id].type);
+                        sb.append(",ord:");
+                        sb.append(energyConsumers[id].ordinal);
+                        sb.append(",name:");
+                        sb.append(energyConsumers[id].name);
+                        sb.append(")");
+                        if (i != resultLength - 1) {
+                            sb.append(", ");
+                        }
+                    }
+                    sb.append("]");
+                }
+                Slog.wtf(TAG, "Missing result from getEnergyConsumedAsync call. " + sb);
+            }
+        }
+        future.complete(results);
     }
 
     private void getStateResidencyAsync(CompletableFuture<StateResidencyResult[]> future,
diff --git a/services/core/java/com/android/server/sensors/SensorManagerInternal.java b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
index fbb6644..f17e5e7 100644
--- a/services/core/java/com/android/server/sensors/SensorManagerInternal.java
+++ b/services/core/java/com/android/server/sensors/SensorManagerInternal.java
@@ -43,6 +43,43 @@
     public abstract void removeProximityActiveListener(@NonNull ProximityActiveListener listener);
 
     /**
+     * Creates a sensor that is registered at runtime by the system with the sensor service.
+     *
+     * The runtime sensors created here are different from the
+     * <a href="https://source.android.com/docs/core/interaction/sensors/sensors-hal2#dynamic-sensors">
+     * dynamic sensor support in the HAL</a>. These sensors have no HAL dependency and correspond to
+     * sensors that belong to an external (virtual) device.
+     *
+     * @param deviceId The identifier of the device this sensor is associated with.
+     * @param type The generic type of the sensor.
+     * @param name The name of the sensor.
+     * @param vendor The vendor string of the sensor.
+     * @param callback The callback to get notified when the sensor listeners have changed.
+     * @return The sensor handle.
+     */
+    public abstract int createRuntimeSensor(int deviceId, int type, @NonNull String name,
+            @NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback);
+
+    /**
+     * Unregisters the sensor with the given handle from the framework.
+     */
+    public abstract void removeRuntimeSensor(int handle);
+
+    /**
+     * Sends an event for the runtime sensor with the given handle to the framework.
+     *
+     * Only relevant for sending runtime sensor events. @see #createRuntimeSensor.
+     *
+     * @param handle The sensor handle.
+     * @param type The type of the sensor.
+     * @param timestampNanos When the event occurred.
+     * @param values The values of the event.
+     * @return Whether the event injection was successful.
+     */
+    public abstract boolean sendSensorEvent(int handle, int type, long timestampNanos,
+            @NonNull float[] values);
+
+    /**
      * Listener for proximity sensor state changes.
      */
     public interface ProximityActiveListener {
@@ -52,4 +89,17 @@
          */
         void onProximityActive(boolean isActive);
     }
+
+    /**
+     * Callback for runtime sensor state changes. Only relevant to sensors created via
+     * {@link #createRuntimeSensor}, i.e. the dynamic sensors created via the dynamic sensor HAL are
+     * not covered.
+     */
+    public interface RuntimeSensorStateChangeCallback {
+        /**
+         * Invoked when the listeners of the runtime sensor have changed.
+         */
+        void onStateChanged(boolean enabled, int samplingPeriodMicros,
+                int batchReportLatencyMicros);
+    }
 }
diff --git a/services/core/java/com/android/server/sensors/SensorService.java b/services/core/java/com/android/server/sensors/SensorService.java
index 8fe2d52..d8e3bdd 100644
--- a/services/core/java/com/android/server/sensors/SensorService.java
+++ b/services/core/java/com/android/server/sensors/SensorService.java
@@ -29,7 +29,9 @@
 import com.android.server.SystemService;
 import com.android.server.utils.TimingsTraceAndSlog;
 
+import java.util.HashSet;
 import java.util.Objects;
+import java.util.Set;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Future;
 
@@ -40,6 +42,8 @@
     private final ArrayMap<ProximityActiveListener, ProximityListenerProxy> mProximityListeners =
             new ArrayMap<>();
     @GuardedBy("mLock")
+    private final Set<Integer> mRuntimeSensorHandles = new HashSet<>();
+    @GuardedBy("mLock")
     private Future<?> mSensorServiceStart;
     @GuardedBy("mLock")
     private long mPtr;
@@ -51,6 +55,12 @@
     private static native void registerProximityActiveListenerNative(long ptr);
     private static native void unregisterProximityActiveListenerNative(long ptr);
 
+    private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type,
+            String name, String vendor,
+            SensorManagerInternal.RuntimeSensorStateChangeCallback callback);
+    private static native void unregisterRuntimeSensorNative(long ptr, int handle);
+    private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type,
+            long timestampNanos, float[] values);
 
     public SensorService(Context ctx) {
         super(ctx);
@@ -85,6 +95,38 @@
 
     class LocalService extends SensorManagerInternal {
         @Override
+        public int createRuntimeSensor(int deviceId, int type, @NonNull String name,
+                @NonNull String vendor, @NonNull RuntimeSensorStateChangeCallback callback) {
+            synchronized (mLock) {
+                int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor,
+                        callback);
+                mRuntimeSensorHandles.add(handle);
+                return handle;
+            }
+        }
+
+        @Override
+        public void removeRuntimeSensor(int handle) {
+            synchronized (mLock) {
+                if (mRuntimeSensorHandles.contains(handle)) {
+                    mRuntimeSensorHandles.remove(handle);
+                    unregisterRuntimeSensorNative(mPtr, handle);
+                }
+            }
+        }
+
+        @Override
+        public boolean sendSensorEvent(int handle, int type, long timestampNanos,
+                @NonNull float[] values) {
+            synchronized (mLock) {
+                if (!mRuntimeSensorHandles.contains(handle)) {
+                    return false;
+                }
+                return sendRuntimeSensorEventNative(mPtr, handle, type, timestampNanos, values);
+            }
+        }
+
+        @Override
         public void addProximityActiveListener(@NonNull Executor executor,
                 @NonNull ProximityActiveListener listener) {
             Objects.requireNonNull(executor, "executor must not be null");
diff --git a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
index 0409a84..111b4f6 100644
--- a/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
+++ b/services/core/java/com/android/server/timezonedetector/ConfigurationInternal.java
@@ -109,7 +109,7 @@
      * testing only. See {@link #isGeoDetectionExecutionEnabled()} and {@link #getDetectionMode()}
      * for details.
      */
-    boolean getGeoDetectionRunInBackgroundEnabled() {
+    boolean getGeoDetectionRunInBackgroundEnabledSetting() {
         return mGeoDetectionRunInBackgroundEnabled;
     }
 
@@ -132,7 +132,7 @@
      * from the raw setting value.
      */
     public boolean getAutoDetectionEnabledBehavior() {
-        return isAutoDetectionSupported() && mAutoDetectionEnabledSetting;
+        return isAutoDetectionSupported() && getAutoDetectionEnabledSetting();
     }
 
     /** Returns the ID of the user this configuration is associated with. */
@@ -171,27 +171,55 @@
      * time zone.
      */
     public @DetectionMode int getDetectionMode() {
-        if (!getAutoDetectionEnabledBehavior()) {
+        if (!isAutoDetectionSupported()) {
+            // Handle the easy case first: No auto detection algorithms supported must mean manual.
             return DETECTION_MODE_MANUAL;
-        } else if (isGeoDetectionSupported() && getLocationEnabledSetting()
-                && getGeoDetectionEnabledSetting()) {
+        } else if (!getAutoDetectionEnabledSetting()) {
+            // Auto detection algorithms are supported, but disabled by the user.
+            return DETECTION_MODE_MANUAL;
+        } else if (getGeoDetectionEnabledBehavior()) {
             return DETECTION_MODE_GEO;
-        } else {
+        } else if (isTelephonyDetectionSupported()) {
             return DETECTION_MODE_TELEPHONY;
+        } else {
+            // On devices with telephony detection support, telephony is used instead of geo when
+            // geo cannot be used. This "unknown" case can occur on devices with only the location
+            // detection algorithm supported when the user's master location setting prevents its
+            // use.
+            return DETECTION_MODE_UNKNOWN;
         }
     }
 
+    private boolean getGeoDetectionEnabledBehavior() {
+        // isAutoDetectionSupported() should already have been checked before calling this method.
+        if (isGeoDetectionSupported() && getLocationEnabledSetting()) {
+            if (isTelephonyDetectionSupported()) {
+                // This is the "normal" case for smartphones that have both telephony and geo
+                // detection: the user chooses which type of detection to use.
+                return getGeoDetectionEnabledSetting();
+            } else {
+                // When only geo detection is supported then there is no choice for the user to
+                // make between detection modes, so no user setting is consulted.
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Returns true if geolocation time zone detection behavior can execute. Typically, this will
      * agree with {@link #getDetectionMode()}, but under rare circumstances the geolocation detector
-     * may be run in the background if the user's settings allow. See also {@link
-     * #getGeoDetectionRunInBackgroundEnabled()}.
+     * may be run in the background if the user's settings allow.
      */
     public boolean isGeoDetectionExecutionEnabled() {
+        return getDetectionMode() == DETECTION_MODE_GEO
+                || getGeoDetectionRunInBackgroundEnabledBehavior();
+    }
+
+    private boolean getGeoDetectionRunInBackgroundEnabledBehavior() {
         return isGeoDetectionSupported()
                 && getLocationEnabledSetting()
-                && ((mAutoDetectionEnabledSetting && getGeoDetectionEnabledSetting())
-                || getGeoDetectionRunInBackgroundEnabled());
+                && getGeoDetectionRunInBackgroundEnabledSetting();
     }
 
     @NonNull
@@ -216,11 +244,19 @@
         builder.setConfigureAutoDetectionEnabledCapability(configureAutoDetectionEnabledCapability);
 
         boolean deviceHasLocationTimeZoneDetection = isGeoDetectionSupported();
+        boolean deviceHasTelephonyDetection = isTelephonyDetectionSupported();
+
         // Note: allowConfigDateTime does not restrict the ability to change location time zone
         // detection enabled. This is intentional as it has user privacy implications and so it
-        // makes sense to leave this under a user's control.
+        // makes sense to leave this under a user's control. The only time this is not true is
+        // on devices that only support location-based detection and the main auto detection setting
+        // is used to influence whether location can be used.
         final @CapabilityState int configureGeolocationDetectionEnabledCapability;
-        if (!deviceHasLocationTimeZoneDetection) {
+        if (!deviceHasLocationTimeZoneDetection || !deviceHasTelephonyDetection) {
+            // If the device doesn't have geolocation detection support OR it ONLY has geolocation
+            // detection support (no telephony) then the user doesn't need the ability to toggle the
+            // location-based detection on and off (the auto detection toggle is considered
+            // sufficient).
             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_SUPPORTED;
         } else if (!mAutoDetectionEnabledSetting || !getLocationEnabledSetting()) {
             configureGeolocationDetectionEnabledCapability = CAPABILITY_NOT_APPLICABLE;
diff --git a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
index aad5359..59691f8 100644
--- a/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
+++ b/services/core/java/com/android/server/timezonedetector/MetricsTimeZoneDetectorState.java
@@ -136,7 +136,7 @@
      * testing only.
      */
     public boolean getGeoDetectionRunInBackgroundEnabled() {
-        return mConfigurationInternal.getGeoDetectionRunInBackgroundEnabled();
+        return mConfigurationInternal.getGeoDetectionRunInBackgroundEnabledSetting();
     }
 
     /** Returns true if enhanced metric collection is enabled. */
diff --git a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
index 295c5c8a..6ebaf14c 100644
--- a/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/ServiceConfigAccessorImpl.java
@@ -279,15 +279,18 @@
             final boolean autoDetectionEnabled = configuration.isAutoDetectionEnabled();
             setAutoDetectionEnabledIfRequired(autoDetectionEnabled);
 
-            // Avoid writing the geo detection enabled setting for devices with settings that
-            // are currently overridden by server flags: otherwise we might overwrite a droidfood
-            // user's real setting permanently.
-            // Also avoid writing the geo detection enabled setting for devices that do not support
-            // geo time zone detection: if we wrote it down then we'd set the value explicitly,
-            // which would prevent detecting "default" later. That might influence what happens on
-            // later releases that start to support geo detection on the same hardware.
+            // Only write the geo detection enabled setting when its values is used, e.g.:
+            // 1) Devices with a setting value that is not currently overridden by server flags
+            // 2) Devices that support both telephony and location detection algorithms
+            //
+            // If we wrote a setting value down when it's not used then we'd be setting the value
+            // explicitly, which would prevent detecting the setting is in "default" state later.
+            // Not being able to detect if the user has actually expressed a preference could
+            // influence what happens on later releases that start to support geo detection on the
+            // user's same hardware.
             if (!getGeoDetectionSettingEnabledOverride().isPresent()
-                    && isGeoTimeZoneDetectionFeatureSupported()) {
+                    && isGeoTimeZoneDetectionFeatureSupported()
+                    && isTelephonyTimeZoneDetectionFeatureSupported()) {
                 final boolean geoDetectionEnabledSetting = configuration.isGeoDetectionEnabled();
                 setGeoDetectionEnabledSettingIfRequired(userId, geoDetectionEnabledSetting);
             }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
index f8c1c92..10cd5d1 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorService.java
@@ -91,7 +91,7 @@
             deviceActivityMonitor.addListener(new DeviceActivityMonitor.Listener() {
                 @Override
                 public void onFlightComplete() {
-                    timeZoneDetectorStrategy.enableTelephonyTimeZoneFallback();
+                    timeZoneDetectorStrategy.enableTelephonyTimeZoneFallback("onFlightComplete()");
                 }
             });
 
@@ -402,9 +402,9 @@
      * Sends a signal to enable telephony fallback. Provided for command-line access for use
      * during tests. This is not exposed as a binder API.
      */
-    void enableTelephonyFallback() {
+    void enableTelephonyFallback(@NonNull String reason) {
         enforceManageTimeZoneDetectorPermission();
-        mTimeZoneDetectorStrategy.enableTelephonyTimeZoneFallback();
+        mTimeZoneDetectorStrategy.enableTelephonyTimeZoneFallback(reason);
     }
 
     /**
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
index 69274db..ab68e83 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorShellCommand.java
@@ -189,7 +189,7 @@
     }
 
     private int runEnableTelephonyFallback() {
-        mInterface.enableTelephonyFallback();
+        mInterface.enableTelephonyFallback("Command line");
         return 0;
     }
 
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index 5768a6b..37e67c9 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -35,13 +35,13 @@
  * <p>Devices can have zero, one or two automatic time zone detection algorithms available at any
  * point in time.
  *
- * <p>The two automatic detection algorithms supported are "telephony" and "geolocation". Algorithm
+ * <p>The two automatic detection algorithms supported are "telephony" and "location". Algorithm
  * availability and use depends on several factors:
  * <ul>
  * <li>Telephony is only available on devices with a telephony stack.
- * <li>Geolocation is also optional and configured at image creation time. When enabled on a
- * device, its availability depends on the current user's settings, so switching between users can
- * change the automatic algorithm used by the device.</li>
+ * <li>Location is also optional and configured at image creation time. When enabled on a device,
+ * its availability depends on the current user's settings, so switching between users can change
+ * the automatic detection algorithm used by the device.</li>
  * </ul>
  *
  * <p>If there are no automatic time zone detections algorithms available then the user can usually
@@ -56,14 +56,14 @@
  * slotIndexes must have an empty suggestion submitted in order to "withdraw" their previous
  * suggestion otherwise it will remain in use.
  *
- * <p>Geolocation detection is dependent on the current user and their settings. The device retains
- * at most one geolocation suggestion. Generally, use of a device's location is dependent on the
- * user's "location toggle", but even when that is enabled the user may choose to enable / disable
- * the use of geolocation for device time zone detection. If the current user changes to one that
- * does not have geolocation detection enabled, or the user turns off geolocation detection, then
- * the strategy discards the latest geolocation suggestion. Devices that lose a location fix must
- * have an empty suggestion submitted in order to "withdraw" their previous suggestion otherwise it
- * will remain in use.
+ * <p>Location-based detection is dependent on the current user and their settings. The device
+ * retains at most one geolocation suggestion. Generally, use of a device's location is dependent on
+ * the user's "location toggle", but even when that is enabled the user may choose to enable /
+ * disable the use of location for device time zone detection. If the current user changes to one
+ * that does not have location-based detection enabled, or the user turns off the location-based
+ * detection, then the strategy will be sent an event that clears the latest suggestion. Devices
+ * that lose their location fix must have an empty suggestion submitted in order to "withdraw" their
+ * previous suggestion otherwise it will remain in use.
  *
  * <p>The strategy uses only one algorithm at a time and does not attempt consensus even when
  * more than one is available on a device. This "use only one" behavior is deliberate as different
@@ -72,25 +72,27 @@
  * users enter areas without the necessary signals. Ultimately, with no perfect algorithm available,
  * the user is left to choose which algorithm works best for their circumstances.
  *
- * <p>When geolocation detection is supported and enabled, in certain circumstances, such as during
- * international travel, it makes sense to prioritize speed of detection via telephony (when
- * available) Vs waiting for the geolocation algorithm to reach certainty. Geolocation detection can
- * sometimes be slow to get a location fix and can require network connectivity (which cannot be
- * assumed when users are travelling) for server-assisted location detection or time zone lookup.
- * Therefore, as a restricted form of prioritization between geolocation and telephony algorithms,
- * the strategy provides "telephony fallback" behavior, which can be set to "supported" via device
- * config. Fallback mode is toggled on at runtime via {@link #enableTelephonyTimeZoneFallback()} in
- * response to signals outside of the scope of this class. Telephony fallback allows the use of
- * telephony suggestions to help with faster detection but only until geolocation detection
- * provides a concrete, "certain" suggestion. After geolocation has made the first certain
- * suggestion, telephony fallback is disabled until the next call to {@link
- * #enableTelephonyTimeZoneFallback()}.
+ * <p>When the location detection algorithm is supported and enabled, in certain circumstances, such
+ * as during international travel, it makes sense to prioritize speed of detection via telephony
+ * (when available) Vs waiting for the location-based detection algorithm to reach certainty.
+ * Location-based detection can sometimes be slow to get a location fix and can require network
+ * connectivity (which cannot be assumed when users are travelling) for server-assisted location
+ * detection or time zone lookup. Therefore, as a restricted form of prioritization between location
+ * and telephony algorithms, the strategy provides "telephony fallback mode" behavior, which can be
+ * set to "supported" via device config. Fallback mode is entered at runtime in response to signals
+ * from outside of the strategy, e.g. from a call to {@link
+ * #enableTelephonyTimeZoneFallback(String)}, or from information in the latest {@link
+ * LocationAlgorithmEvent}. For telephony fallback mode to actually use a telephony suggestion, the
+ * location algorithm <em>must</em> report it is uncertain. Telephony fallback allows the use of
+ * telephony suggestions to help with faster detection but only until the location algorithm
+ * provides a concrete, "certain" suggestion. After the location algorithm has made a certain
+ * suggestion, telephony fallback mode is disabled.
  *
  * <p>Threading:
  *
  * <p>Implementations of this class must be thread-safe as calls calls like {@link
  * #generateMetricsState()} and {@link #dump(IndentingPrintWriter, String[])} may be called on
- * differents thread concurrently with other operations.
+ * different threads concurrently with other operations.
  *
  * @hide
  */
@@ -181,11 +183,11 @@
     void suggestTelephonyTimeZone(@NonNull TelephonyTimeZoneSuggestion suggestion);
 
     /**
-     * Tells the strategy that it can fall back to telephony detection while geolocation detection
-     * remains uncertain. {@link #handleLocationAlgorithmEvent(LocationAlgorithmEvent)} can
-     * disable it again. See {@link TimeZoneDetectorStrategy} for details.
+     * Tells the strategy that it can fall back to telephony detection while the location detection
+     * algorithm remains uncertain. {@link #handleLocationAlgorithmEvent(LocationAlgorithmEvent)}
+     * can disable it again. See {@link TimeZoneDetectorStrategy} for details.
      */
-    void enableTelephonyTimeZoneFallback();
+    void enableTelephonyTimeZoneFallback(@NonNull String reason);
 
     /** Generates a state snapshot for metrics. */
     @NonNull
@@ -194,6 +196,6 @@
     /** Returns {@code true} if the device supports telephony time zone detection. */
     boolean isTelephonyTimeZoneDetectionSupported();
 
-    /** Returns {@code true} if the device supports geolocation time zone detection. */
+    /** Returns {@code true} if the device supports location-based time zone detection. */
     boolean isGeoTimeZoneDetectionSupported();
 }
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
index 3424251..e0e3565 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategyImpl.java
@@ -47,6 +47,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.SystemTimeZone.TimeZoneConfidence;
+import com.android.server.timezonedetector.ConfigurationInternal.DetectionMode;
 
 import java.io.PrintWriter;
 import java.time.Duration;
@@ -62,12 +63,8 @@
 public final class TimeZoneDetectorStrategyImpl implements TimeZoneDetectorStrategy {
 
     /**
-     * Used by {@link TimeZoneDetectorStrategyImpl} to interact with device configuration / settings
-     * / system properties. It can be faked for testing.
-     *
-     * <p>Note: Because the settings / system properties-derived values can currently be modified
-     * independently and from different threads (and processes!), their use is prone to race
-     * conditions.
+     * Used by {@link TimeZoneDetectorStrategyImpl} to interact with device state besides that
+     * available from {@link #mServiceConfigAccessor}. It can be faked for testing.
      */
     @VisibleForTesting
     public interface Environment {
@@ -233,7 +230,7 @@
      * allows).
      *
      * <p>This field is only actually used when telephony time zone fallback is supported, but the
-     * value is maintained even when it isn't supported as it can be turned on at any time via
+     * value is maintained even when it isn't supported as support can be turned on at any time via
      * server flags. The elapsed realtime when the mode last changed is used to help ordering
      * between fallback mode switches and suggestions.
      *
@@ -420,10 +417,15 @@
             notifyStateChangeListenersAsynchronously();
         }
 
-        // Update the mTelephonyTimeZoneFallbackEnabled state if needed: a certain suggestion
-        // will usually disable telephony fallback mode if it is currently enabled.
-        // TODO(b/236624675)Some provider status codes can be used to enable telephony fallback.
-        disableTelephonyFallbackIfNeeded();
+        // Manage telephony fallback state.
+        if (event.getAlgorithmStatus().couldEnableTelephonyFallback()) {
+            // An event may trigger entry into telephony fallback mode if the status
+            // indicates the location algorithm cannot work and is likely to stay not working.
+            enableTelephonyTimeZoneFallback("handleLocationAlgorithmEvent(), event=" + event);
+        } else {
+            // A certain suggestion will exit telephony fallback mode.
+            disableTelephonyFallbackIfNeeded();
+        }
 
         // Now perform auto time zone detection. The new event may be used to modify the time zone
         // setting.
@@ -496,38 +498,41 @@
     }
 
     @Override
-    public synchronized void enableTelephonyTimeZoneFallback() {
-        // Only do any work if fallback is currently not enabled.
+    public synchronized void enableTelephonyTimeZoneFallback(@NonNull String reason) {
+        // Only do any work to enter fallback mode if fallback is currently not already enabled.
         if (!mTelephonyTimeZoneFallbackEnabled.getValue()) {
             ConfigurationInternal currentUserConfig = mCurrentConfigurationInternal;
             final boolean fallbackEnabled = true;
             mTelephonyTimeZoneFallbackEnabled = new TimestampedValue<>(
                     mEnvironment.elapsedRealtimeMillis(), fallbackEnabled);
 
-            String logMsg = "enableTelephonyTimeZoneFallbackMode: "
-                    + " currentUserConfig=" + currentUserConfig
-                    + ", mTelephonyTimeZoneFallbackEnabled="
-                    + mTelephonyTimeZoneFallbackEnabled;
+            String logMsg = "enableTelephonyTimeZoneFallback: "
+                    + " reason=" + reason
+                    + ", currentUserConfig=" + currentUserConfig
+                    + ", mTelephonyTimeZoneFallbackEnabled=" + mTelephonyTimeZoneFallbackEnabled;
             logTimeZoneDebugInfo(logMsg);
 
             // mTelephonyTimeZoneFallbackEnabled and mLatestLocationAlgorithmEvent interact.
-            // If the latest event contains a "certain" geolocation suggestion, then the telephony
-            // fallback value needs to be considered after changing it.
+            // If the latest location algorithm event contains a "certain" geolocation suggestion,
+            // then the telephony fallback mode needs to be (re)considered after changing it.
+            //
             // With the way that the mTelephonyTimeZoneFallbackEnabled time is currently chosen
             // above, and the fact that geolocation suggestions should never have a time in the
-            // future, the following call will be a no-op, and telephony fallback will remain
-            // enabled. This comment / call is left as a reminder that it is possible for there to
-            // be a current, "certain" geolocation suggestion when this signal arrives and it is
-            // intentional that fallback stays enabled in this case. The choice to do this
-            // is mostly for symmetry WRT the case where fallback is enabled and an old "certain"
-            // geolocation is received; that would also leave telephony fallback enabled.
-            // This choice means that telephony fallback will remain enabled until a new "certain"
-            // geolocation suggestion is received. If, instead, the next geolocation is "uncertain",
-            // then telephony fallback will occur.
+            // future, the following call will usually be a no-op, and telephony fallback mode will
+            // remain enabled. This comment / call is left as a reminder that it is possible in some
+            // cases for there to be a current, "certain" geolocation suggestion when an attempt is
+            // made to enable telephony fallback mode and it is intentional that fallback mode stays
+            // enabled in this case. The choice to do this is mostly for symmetry WRT the case where
+            // fallback is enabled and then an old "certain" geolocation suggestion is received;
+            // that would also leave telephony fallback mode enabled.
+            //
+            // This choice means that telephony fallback mode remains enabled if there is an
+            // existing "certain" suggestion until a new "certain" geolocation suggestion is
+            // received. If, instead, the next geolocation suggestion is "uncertain", then telephony
+            // fallback, i.e. the use of a telephony suggestion, will actually occur.
             disableTelephonyFallbackIfNeeded();
 
             if (currentUserConfig.isTelephonyFallbackSupported()) {
-                String reason = "enableTelephonyTimeZoneFallbackMode";
                 doAutoTimeZoneDetection(currentUserConfig, reason);
             }
         }
@@ -597,9 +602,10 @@
     @GuardedBy("this")
     private void doAutoTimeZoneDetection(
             @NonNull ConfigurationInternal currentUserConfig, @NonNull String detectionReason) {
-        // Use the correct algorithm based on the user's current configuration. If it changes, then
-        // detection will be re-run.
-        switch (currentUserConfig.getDetectionMode()) {
+        // Use the correct detection algorithm based on the device's config and the user's current
+        // configuration. If user config changes, then detection will be re-run.
+        @DetectionMode int detectionMode = currentUserConfig.getDetectionMode();
+        switch (detectionMode) {
             case ConfigurationInternal.DETECTION_MODE_MANUAL:
                 // No work to do.
                 break;
@@ -635,9 +641,14 @@
             case ConfigurationInternal.DETECTION_MODE_TELEPHONY:
                 doTelephonyTimeZoneDetection(detectionReason);
                 break;
+            case ConfigurationInternal.DETECTION_MODE_UNKNOWN:
+                // The "DETECTION_MODE_UNKNOWN" state can occur on devices with only location
+                // detection algorithm support and when the user's master location toggle is off.
+                Slog.i(LOG_TAG, "Unknown detection mode: " + detectionMode + ", is location off?");
+                break;
             default:
-                Slog.wtf(LOG_TAG, "Unknown detection mode: "
-                        + currentUserConfig.getDetectionMode());
+                // Coding error
+                Slog.wtf(LOG_TAG, "Unknown detection mode: " + detectionMode);
         }
     }
 
@@ -1043,15 +1054,31 @@
         TelephonyTimeZoneAlgorithmStatus telephonyAlgorithmStatus =
                 createTelephonyAlgorithmStatus(currentConfigurationInternal);
 
-        LocationTimeZoneAlgorithmStatus locationAlgorithmStatus =
-                latestLocationAlgorithmEvent == null ? LocationTimeZoneAlgorithmStatus.UNKNOWN
-                        : latestLocationAlgorithmEvent.getAlgorithmStatus();
+        LocationTimeZoneAlgorithmStatus locationAlgorithmStatus = createLocationAlgorithmStatus(
+                currentConfigurationInternal, latestLocationAlgorithmEvent);
 
         return new TimeZoneDetectorStatus(
                 detectorStatus, telephonyAlgorithmStatus, locationAlgorithmStatus);
     }
 
     @NonNull
+    private static LocationTimeZoneAlgorithmStatus createLocationAlgorithmStatus(
+            ConfigurationInternal currentConfigurationInternal,
+            LocationAlgorithmEvent latestLocationAlgorithmEvent) {
+        LocationTimeZoneAlgorithmStatus locationAlgorithmStatus;
+        if (latestLocationAlgorithmEvent != null) {
+            locationAlgorithmStatus = latestLocationAlgorithmEvent.getAlgorithmStatus();
+        } else if (!currentConfigurationInternal.isGeoDetectionSupported()) {
+            locationAlgorithmStatus = LocationTimeZoneAlgorithmStatus.NOT_SUPPORTED;
+        } else if (currentConfigurationInternal.isGeoDetectionExecutionEnabled()) {
+            locationAlgorithmStatus = LocationTimeZoneAlgorithmStatus.RUNNING_NOT_REPORTED;
+        } else {
+            locationAlgorithmStatus = LocationTimeZoneAlgorithmStatus.NOT_RUNNING;
+        }
+        return locationAlgorithmStatus;
+    }
+
+    @NonNull
     private static TelephonyTimeZoneAlgorithmStatus createTelephonyAlgorithmStatus(
             @NonNull ConfigurationInternal currentConfigurationInternal) {
         int algorithmStatus;
diff --git a/services/core/java/com/android/server/trust/TrustAgentWrapper.java b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
index 0b1f6b9..f971db9 100644
--- a/services/core/java/com/android/server/trust/TrustAgentWrapper.java
+++ b/services/core/java/com/android/server/trust/TrustAgentWrapper.java
@@ -107,6 +107,7 @@
     // Trust state
     private boolean mTrusted;
     private boolean mWaitingForTrustableDowngrade = false;
+    private boolean mWithinSecurityLockdownWindow = false;
     private boolean mTrustable;
     private CharSequence mMessage;
     private boolean mDisplayTrustGrantedMessage;
@@ -160,6 +161,7 @@
                     mDisplayTrustGrantedMessage = (flags & FLAG_GRANT_TRUST_DISPLAY_MESSAGE) != 0;
                     if ((flags & FLAG_GRANT_TRUST_TEMPORARY_AND_RENEWABLE) != 0) {
                         mWaitingForTrustableDowngrade = true;
+                        setSecurityWindowTimer();
                     } else {
                         mWaitingForTrustableDowngrade = false;
                     }
@@ -452,6 +454,9 @@
             if (mBound) {
                 scheduleRestart();
             }
+            if (mWithinSecurityLockdownWindow) {
+                mTrustManagerService.lockUser(mUserId);
+            }
             // mTrustDisabledByDpm maintains state
         }
     };
@@ -673,6 +678,22 @@
         }
     }
 
+    private void setSecurityWindowTimer() {
+        mWithinSecurityLockdownWindow = true;
+        long expiration = SystemClock.elapsedRealtime() + (15 * 1000); // timer for 15 seconds
+        mAlarmManager.setExact(
+                AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                expiration,
+                TAG,
+                new AlarmManager.OnAlarmListener() {
+                    @Override
+                    public void onAlarm() {
+                        mWithinSecurityLockdownWindow = false;
+                    }
+                },
+                Handler.getMain());
+    }
+
     public boolean isManagingTrust() {
         return mManagingTrust && !mTrustDisabledByDpm;
     }
@@ -691,7 +712,6 @@
 
     public void destroy() {
         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
-
         if (!mBound) {
             return;
         }
diff --git a/services/core/java/com/android/server/utils/EventLogger.java b/services/core/java/com/android/server/utils/EventLogger.java
index 770cb72..4772bbf 100644
--- a/services/core/java/com/android/server/utils/EventLogger.java
+++ b/services/core/java/com/android/server/utils/EventLogger.java
@@ -36,8 +36,11 @@
  */
 public class EventLogger {
 
+    /** Prefix for the title added at the beginning of a {@link #dump(PrintWriter)} operation */
+    private static final String DUMP_TITLE_PREFIX = "Events log: ";
+
     /** Identifies the source of events. */
-    private final String mTag;
+    @Nullable private final String mTag;
 
     /** Stores the events using a ring buffer. */
     private final ArrayDeque<Event> mEvents;
@@ -55,7 +58,7 @@
      * @param size the maximum number of events to keep in log
      * @param tag the string displayed before the recorded log
      */
-    public EventLogger(int size, String tag) {
+    public EventLogger(int size, @Nullable String tag) {
         mEvents = new ArrayDeque<>(size);
         mMemSize = size;
         mTag = tag;
@@ -64,10 +67,10 @@
     /** Enqueues {@code event} to be logged. */
     public synchronized void enqueue(Event event) {
         if (mEvents.size() >= mMemSize) {
-            mEvents.removeLast();
+            mEvents.removeFirst();
         }
 
-        mEvents.addFirst(event);
+        mEvents.addLast(event);
     }
 
     /**
@@ -91,13 +94,19 @@
         dump(pw, "" /* prefix */);
     }
 
+    protected String getDumpTitle() {
+        if (mTag == null) {
+            return DUMP_TITLE_PREFIX;
+        }
+        return DUMP_TITLE_PREFIX + mTag;
+    }
+
     /** Dumps events using {@link PrintWriter} with a certain indent. */
     public synchronized void dump(PrintWriter pw, String indent) {
-        pw.println(indent + "Events log: " + mTag);
+        pw.println(getDumpTitle());
 
-        String childrenIndention = indent + "  ";
         for (Event evt : mEvents) {
-            pw.println(childrenIndention + evt.toString());
+            pw.println(indent + evt.toString());
         }
     }
 
diff --git a/services/core/java/com/android/server/utils/Slogf.java b/services/core/java/com/android/server/utils/Slogf.java
index e88ac63..6efbd89 100644
--- a/services/core/java/com/android/server/utils/Slogf.java
+++ b/services/core/java/com/android/server/utils/Slogf.java
@@ -162,7 +162,7 @@
     }
 
     /**
-     * Logs a {@link Log.VEBOSE} message with an exception
+     * Logs a {@link Log.VEBOSE} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#VERBOSE} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -170,10 +170,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void v(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void v(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.VERBOSE)) return;
 
-        v(tag, getMessage(format, args), exception);
+        v(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -192,7 +192,7 @@
     }
 
     /**
-     * Logs a {@link Log.DEBUG} message with an exception
+     * Logs a {@link Log.DEBUG} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -200,10 +200,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void d(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void d(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.DEBUG)) return;
 
-        d(tag, getMessage(format, args), exception);
+        d(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -222,7 +222,7 @@
     }
 
     /**
-     * Logs a {@link Log.INFO} message with an exception
+     * Logs a {@link Log.INFO} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging
      * is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -230,10 +230,10 @@
      * you're calling this method in a critical path, make sure to explicitly do the check before
      * calling it.
      */
-    public static void i(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void i(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.INFO)) return;
 
-        i(tag, getMessage(format, args), exception);
+        i(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -252,7 +252,7 @@
     }
 
     /**
-     * Logs a {@link Log.WARN} message with an exception
+     * Logs a {@link Log.WARN} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
      * enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -260,10 +260,10 @@
      * calling this method in a critical path, make sure to explicitly do the check before calling
      * it.
      */
-    public static void w(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void w(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.WARN)) return;
 
-        w(tag, getMessage(format, args), exception);
+        w(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -282,7 +282,7 @@
     }
 
     /**
-     * Logs a {@link Log.ERROR} message with an exception
+     * Logs a {@link Log.ERROR} message with a throwable
      *
      * <p><strong>Note: </strong>the message will only be formatted if {@link Log#ERROR} logging is
      * enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -290,10 +290,10 @@
      * calling this method in a critical path, make sure to explicitly do the check before calling
      * it.
      */
-    public static void e(String tag, Exception exception, String format, @Nullable Object... args) {
+    public static void e(String tag, Throwable throwable, String format, @Nullable Object... args) {
         if (!isLoggable(tag, Log.ERROR)) return;
 
-        e(tag, getMessage(format, args), exception);
+        e(tag, getMessage(format, args), throwable);
     }
 
     /**
@@ -304,11 +304,11 @@
     }
 
     /**
-     * Logs a {@code wtf} message with an exception.
+     * Logs a {@code wtf} message with a throwable.
      */
-    public static void wtf(String tag, Exception exception, String format,
+    public static void wtf(String tag, Throwable throwable, String format,
             @Nullable Object... args) {
-        wtf(tag, getMessage(format, args), exception);
+        wtf(tag, getMessage(format, args), throwable);
     }
 
     private static String getMessage(String format, @Nullable Object... args) {
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 7157293..af430f9 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -614,17 +614,18 @@
     }
 
     /**
-     * Returns the windowing mode of the task that hosts the activity, or {@code -1} if task is not
-     * found.
+     * Returns the {@link Configuration} of the task which hosts the Activity, or {@code null} if
+     * the task {@link Configuration} cannot be obtained.
      */
     @Override
-    public int getTaskWindowingMode(IBinder activityToken) {
+    @Nullable
+    public Configuration getTaskConfiguration(IBinder activityToken) {
         synchronized (mGlobalLock) {
             final ActivityRecord ar = ActivityRecord.isInAnyTask(activityToken);
             if (ar == null) {
-                return -1;
+                return null;
             }
-            return ar.getTask().getWindowingMode();
+            return ar.getTask().getConfiguration();
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 530fa4d..e099aac 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3317,9 +3317,17 @@
                 mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
                         resultTo.getUriPermissionsLocked());
             }
-            if (mForceSendResultForMediaProjection) {
-                resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode,
-                        resultData, resultGrants, true /* forceSendForMediaProjection */);
+            if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) {
+                // Sending the result to the resultTo activity asynchronously to prevent the
+                // resultTo activity getting results before this Activity paused.
+                final ActivityRecord resultToActivity = resultTo;
+                mAtmService.mH.post(() -> {
+                    synchronized (mAtmService.mGlobalLock) {
+                        resultToActivity.sendResult(this.getUid(), resultWho, requestCode,
+                                resultCode, resultData, resultGrants,
+                                mForceSendResultForMediaProjection);
+                    }
+                });
             } else {
                 resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
             }
@@ -4630,7 +4638,7 @@
                 false /* forceSendForMediaProjection */);
     }
 
-    private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
+    void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
             Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) {
         if (callingUid > 0) {
             mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
@@ -8910,9 +8918,7 @@
         }
 
         if (info.isChangeEnabled(OVERRIDE_MIN_ASPECT_RATIO_EXCLUDE_PORTRAIT_FULLSCREEN)
-                && getParent().getConfiguration().orientation == ORIENTATION_PORTRAIT
-                && getParent().getWindowConfiguration().getWindowingMode()
-                        == WINDOWING_MODE_FULLSCREEN) {
+                && isParentFullscreenPortrait()) {
             // We are using the parent configuration here as this is the most recent one that gets
             // passed to onConfigurationChanged when a relevant change takes place
             return info.getMinAspectRatio();
@@ -8935,6 +8941,13 @@
         return info.getMinAspectRatio();
     }
 
+    private boolean isParentFullscreenPortrait() {
+        final WindowContainer parent = getParent();
+        return parent != null
+                && parent.getConfiguration().orientation == ORIENTATION_PORTRAIT
+                && parent.getWindowConfiguration().getWindowingMode() == WINDOWING_MODE_FULLSCREEN;
+    }
+
     /**
      * Returns true if the activity has maximum or minimum aspect ratio.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index c49d672..56aae2d6 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -559,47 +559,52 @@
         final Task rootTask = mService.mRootWindowContainer.getDefaultTaskDisplayArea()
                 .getRootTask(WINDOWING_MODE_UNDEFINED, activityType);
         if (rootTask == null) return false;
+        final RemoteTransition remote = options.getRemoteTransition();
         final ActivityRecord r = rootTask.topRunningActivity();
-        if (r == null || r.mVisibleRequested || !r.attachedToProcess()
+        if (r == null || r.mVisibleRequested || !r.attachedToProcess() || remote == null
                 || !r.mActivityComponent.equals(intent.getComponent())
                 // Recents keeps invisible while device is locked.
                 || r.mDisplayContent.isKeyguardLocked()) {
             return false;
         }
         mService.mRootWindowContainer.startPowerModeLaunchIfNeeded(true /* forceSend */, r);
-        final RemoteTransition remote = options.getRemoteTransition();
-        if (remote != null && rootTask.mTransitionController.isCollecting()) {
-            final Transition transition = new Transition(WindowManager.TRANSIT_TO_FRONT,
-                    0 /* flags */, rootTask.mTransitionController,
-                    mService.mWindowManager.mSyncEngine);
+        final ActivityMetricsLogger.LaunchingState launchingState =
+                mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+        final Transition transition = new Transition(WindowManager.TRANSIT_TO_FRONT,
+                0 /* flags */, r.mTransitionController, mService.mWindowManager.mSyncEngine);
+        if (r.mTransitionController.isCollecting()) {
             // Special case: we are entering recents while an existing transition is running. In
             // this case, we know it's safe to "defer" the activity launch, so lets do so now so
             // that it can get its own transition and thus update launcher correctly.
             mService.mWindowManager.mSyncEngine.queueSyncSet(
-                    () -> rootTask.mTransitionController.moveToCollecting(transition),
                     () -> {
-                        final Task task = r.getTask();
-                        task.mTransitionController.requestStartTransition(transition,
-                                task, remote, null /* displayChange */);
-                        task.mTransitionController.collect(task);
-                        startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+                        if (r.isAttached()) {
+                            r.mTransitionController.moveToCollecting(transition);
+                        }
+                    },
+                    () -> {
+                        if (r.isAttached() && transition.isCollecting()) {
+                            startExistingRecentsIfPossibleInner(options, r, rootTask,
+                                    launchingState, remote, transition);
+                        }
                     });
         } else {
-            final Task task = r.getTask();
-            task.mTransitionController.requestTransitionIfNeeded(WindowManager.TRANSIT_TO_FRONT,
-                    0 /* flags */, task, task /* readyGroupRef */,
-                    options.getRemoteTransition(), null /* displayChange */);
-            startExistingRecentsIfPossibleInner(intent, options, r, task, rootTask);
+            r.mTransitionController.moveToCollecting(transition);
+            startExistingRecentsIfPossibleInner(options, r, rootTask, launchingState, remote,
+                    transition);
         }
         return true;
     }
 
-    void startExistingRecentsIfPossibleInner(Intent intent, ActivityOptions options,
-            ActivityRecord r, Task task, Task rootTask) {
-        final ActivityMetricsLogger.LaunchingState launchingState =
-                mSupervisor.getActivityMetricsLogger().notifyActivityLaunching(intent);
+    private void startExistingRecentsIfPossibleInner(ActivityOptions options, ActivityRecord r,
+            Task rootTask, ActivityMetricsLogger.LaunchingState launchingState,
+            RemoteTransition remoteTransition, Transition transition) {
+        final Task task = r.getTask();
         mService.deferWindowLayout();
         try {
+            r.mTransitionController.requestStartTransition(transition,
+                    task, remoteTransition, null /* displayChange */);
+            r.mTransitionController.collect(task);
             r.mTransitionController.setTransientLaunch(r,
                     TaskDisplayArea.getRootTaskAbove(rootTask));
             task.moveToFront("startExistingRecents");
diff --git a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
index d7c5e93..719f72c 100644
--- a/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/wm/ActivityStartInterceptor.java
@@ -399,8 +399,11 @@
      * @return The intercepting intent if needed.
      */
     private Intent interceptWithConfirmCredentialsIfNeeded(ActivityInfo aInfo, int userId) {
+        if (!mService.mAmInternal.shouldConfirmCredentials(userId)) {
+            return null;
+        }
         if ((aInfo.flags & ActivityInfo.FLAG_SHOW_WHEN_LOCKED) != 0
-                || !mService.mAmInternal.shouldConfirmCredentials(userId)) {
+                && (mUserManager.isUserUnlocked(userId) || aInfo.directBootAware)) {
             return null;
         }
         final IntentSender target = createIntentSenderForOriginalIntent(mCallingUid,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 97aee0b..5c83c4f 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -53,7 +53,9 @@
 import static android.content.pm.ActivityInfo.launchModeToString;
 import static android.os.Process.INVALID_UID;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
+import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 
 import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_CONFIGURATION;
@@ -78,7 +80,6 @@
 import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -1388,9 +1389,9 @@
                 && transitionController.getTransitionPlayer() != null)
                 ? transitionController.createTransition(TRANSIT_OPEN) : null;
         RemoteTransition remoteTransition = r.takeRemoteTransition();
-        transitionController.collect(r);
         try {
             mService.deferWindowLayout();
+            transitionController.collect(r);
             try {
                 Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "startActivityInner");
                 result = startActivityInner(r, sourceRecord, voiceSession, voiceInteractor,
@@ -2140,6 +2141,11 @@
                 if (actuallyMoved) {
                     // Only record if the activity actually moved.
                     mMovedToTopActivity = act;
+                    if (mNoAnimation) {
+                        act.mDisplayContent.prepareAppTransition(TRANSIT_NONE);
+                    } else {
+                        act.mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT);
+                    }
                 }
                 act.updateOptionsLocked(mOptions);
                 deliverNewIntent(act, intentGrants);
@@ -2777,11 +2783,6 @@
                 errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
                 break;
             }
-            case EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT: {
-                errMsg = "Cannot embed activity across TaskFragments for result, resultTo: "
-                        + mStartActivity.resultTo;
-                break;
-            }
             default:
                 errMsg = "Unhandled embed result:" + result;
         }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7dd8770..eb04687 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4386,6 +4386,13 @@
                 values.touchscreen,
                 values.uiMode);
 
+        // Note: certain tests currently run as platform_app which is not allowed
+        // to set debug system properties. To ensure that system properties are set
+        // only when allowed, we check the current UID.
+        if (Process.myUid() == Process.SYSTEM_UID) {
+            SystemProperties.set("debug.tracing.mcc", Integer.toString(values.mcc));
+            SystemProperties.set("debug.tracing.mnc", Integer.toString(values.mnc));
+        }
 
         if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
             final LocaleList locales = values.getLocales();
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index fca9743..74d52b2 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -272,6 +272,7 @@
             handleClosingApps();
             handleOpeningApps();
             handleChangingApps(transit);
+            handleClosingChangingContainers();
 
             appTransition.setLastAppTransition(transit, topOpeningApp,
                     topClosingApp, topChangingApp);
@@ -290,6 +291,7 @@
         mDisplayContent.mClosingApps.clear();
         mDisplayContent.mChangingContainers.clear();
         mDisplayContent.mUnknownAppVisibilityController.clear();
+        mDisplayContent.mClosingChangingContainers.clear();
 
         // This has changed the visibility of windows, so perform
         // a new layout to get them all up-to-date.
@@ -1178,6 +1180,24 @@
         }
     }
 
+    private void handleClosingChangingContainers() {
+        final ArrayMap<WindowContainer, Rect> containers =
+                mDisplayContent.mClosingChangingContainers;
+        while (!containers.isEmpty()) {
+            final WindowContainer container = containers.keyAt(0);
+            containers.remove(container);
+
+            // For closing changing windows that are part of the transition, they should have been
+            // removed from mClosingChangingContainers in WindowContainer#getAnimationAdapter()
+            // If the closing changing TaskFragment is not part of the transition, update its
+            // surface after removing it from mClosingChangingContainers.
+            final TaskFragment taskFragment = container.asTaskFragment();
+            if (taskFragment != null) {
+                taskFragment.updateOrganizedTaskFragmentSurface();
+            }
+        }
+    }
+
     private void handleChangingApps(@TransitionOldType int transit) {
         final ArraySet<WindowContainer> apps = mDisplayContent.mChangingContainers;
         final int appsCount = apps.size();
diff --git a/services/core/java/com/android/server/wm/BLASTSyncEngine.java b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
index d345227..cd26e2e 100644
--- a/services/core/java/com/android/server/wm/BLASTSyncEngine.java
+++ b/services/core/java/com/android/server/wm/BLASTSyncEngine.java
@@ -226,6 +226,9 @@
         }
 
         private void setReady(boolean ready) {
+            if (mReady == ready) {
+                return;
+            }
             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Set ready", mSyncId);
             mReady = ready;
             if (!ready) return;
@@ -239,7 +242,9 @@
             ProtoLog.v(WM_DEBUG_SYNC_ENGINE, "SyncGroup %d: Adding to group: %s", mSyncId, wc);
             wc.setSyncGroup(this);
             wc.prepareSync();
-            mWm.mWindowPlacerLocked.requestTraversal();
+            if (mReady) {
+                mWm.mWindowPlacerLocked.requestTraversal();
+            }
         }
 
         void onCancelSync(WindowContainer wc) {
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 3bb0238..8680f1b 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
@@ -167,6 +168,12 @@
                             + "recents. Overriding back callback to recents controller callback.");
                     return null;
                 }
+
+                if (!window.isDrawn()) {
+                    ProtoLog.d(WM_DEBUG_BACK_PREVIEW,
+                            "Focused window didn't have a valid surface drawn.");
+                    return null;
+                }
             }
 
             if (window == null) {
@@ -226,9 +233,8 @@
 
             mBackAnimationInProgress = true;
             // We don't have an application callback, let's find the destination of the back gesture
-            Task finalTask = currentTask;
-            prevActivity = currentTask.getActivity(
-                    (r) -> !r.finishing && r.getTask() == finalTask && !r.isTopRunningActivity());
+            // The search logic should align with ActivityClientController#finishActivity
+            prevActivity = currentTask.topRunningActivity(currentActivity.token, INVALID_TASK_ID);
             // TODO Dialog window does not need to attach on activity, check
             // window.mAttrs.type != TYPE_BASE_APPLICATION
             if ((window.getParent().getChildCount() > 1
@@ -241,15 +247,18 @@
                 // We have another Activity in the same currentTask to go to
                 backType = BackNavigationInfo.TYPE_CROSS_ACTIVITY;
                 removedWindowContainer = currentActivity;
+                prevTask = prevActivity.getTask();
             } else if (currentTask.returnsToHomeRootTask()) {
                 // Our Task should bring back to home
                 removedWindowContainer = currentTask;
+                prevTask = currentTask.getDisplayArea().getRootHomeTask();
                 backType = BackNavigationInfo.TYPE_RETURN_TO_HOME;
                 mShowWallpaper = true;
             } else if (currentActivity.isRootOfTask()) {
                 // TODO(208789724): Create single source of truth for this, maybe in
                 //  RootWindowContainer
-                prevTask = currentTask.mRootWindowContainer.getTaskBelow(currentTask);
+                prevTask = currentTask.mRootWindowContainer.getTask(Task::showToCurrentUser,
+                        currentTask, false /*includeBoundary*/, true /*traverseTopToBottom*/);
                 removedWindowContainer = currentTask;
                 // If it reaches the top activity, we will check the below task from parent.
                 // If it's null or multi-window, fallback the type to TYPE_CALLBACK.
@@ -423,6 +432,11 @@
 
         void reset(@NonNull WindowContainer close, @NonNull WindowContainer open) {
             clearBackAnimateTarget(null);
+            if (close == null || open == null) {
+                Slog.e(TAG, "reset animation with null target close: "
+                        + close + " open: " + open);
+                return;
+            }
             if (close.asActivityRecord() != null && open.asActivityRecord() != null
                     && (close.asActivityRecord().getTask() == open.asActivityRecord().getTask())) {
                 mSwitchType = ACTIVITY_SWITCH;
@@ -601,26 +615,23 @@
                 // reset leash after animation finished.
                 leashes.add(screenshotSurface);
             }
-        } else if (prevTask != null) {
-            prevActivity = prevTask.getTopNonFinishingActivity();
-            if (prevActivity != null) {
-                // Make previous task show from behind by marking its top activity as visible
-                // and launch-behind to bump its visibility for the duration of the back gesture.
-                setLaunchBehind(prevActivity);
+        } else if (prevTask != null && prevActivity != null) {
+            // Make previous task show from behind by marking its top activity as visible
+            // and launch-behind to bump its visibility for the duration of the back gesture.
+            setLaunchBehind(prevActivity);
 
-                final SurfaceControl leash = prevActivity.makeAnimationLeash()
-                        .setName("BackPreview Leash for " + prevActivity)
-                        .setHidden(false)
-                        .build();
-                prevActivity.reparentSurfaceControl(startedTransaction, leash);
-                behindAppTarget = createRemoteAnimationTargetLocked(
-                        prevTask, leash, MODE_OPENING);
+            final SurfaceControl leash = prevActivity.makeAnimationLeash()
+                    .setName("BackPreview Leash for " + prevActivity)
+                    .setHidden(false)
+                    .build();
+            prevActivity.reparentSurfaceControl(startedTransaction, leash);
+            behindAppTarget = createRemoteAnimationTargetLocked(
+                    prevTask, leash, MODE_OPENING);
 
-                // reset leash after animation finished.
-                leashes.add(leash);
-                prevActivity.reparentSurfaceControl(finishedTransaction,
-                        prevActivity.getParentSurfaceControl());
-            }
+            // reset leash after animation finished.
+            leashes.add(leash);
+            prevActivity.reparentSurfaceControl(finishedTransaction,
+                    prevActivity.getParentSurfaceControl());
         }
 
         if (mShowWallpaper) {
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index bedeabe..89f1bd0 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -343,7 +343,11 @@
             if (childArea == null) {
                 continue;
             }
-            pw.println(prefix + "* " + childArea.getName());
+            pw.print(prefix + "* " + childArea.getName());
+            if (childArea.isOrganized()) {
+                pw.print(" (organized)");
+            }
+            pw.println();
             if (childArea.isTaskDisplayArea()) {
                 // TaskDisplayArea can only contain task. And it is already printed by display.
                 continue;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 0119e4d..5ba70aa 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -192,6 +192,7 @@
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.DisplayUtils;
@@ -207,6 +208,7 @@
 import android.view.Display;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.IDisplayWindowInsetsController;
 import android.view.ISystemGestureExclusionListener;
@@ -355,6 +357,11 @@
     final ArraySet<ActivityRecord> mClosingApps = new ArraySet<>();
     final ArraySet<WindowContainer> mChangingContainers = new ArraySet<>();
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
+    /**
+     * If a container is closing when resizing, keeps track of its starting bounds when it is
+     * removed from {@link #mChangingContainers}.
+     */
+    final ArrayMap<WindowContainer, Rect> mClosingChangingContainers = new ArrayMap<>();
 
     private MetricsLogger mMetricsLogger;
 
@@ -391,6 +398,10 @@
             mPrivacyIndicatorBoundsCache = new
             RotationCache<>(this::calculatePrivacyIndicatorBoundsForRotationUncached);
 
+    DisplayShape mInitialDisplayShape;
+    private final RotationCache<DisplayShape, DisplayShape> mDisplayShapeCache =
+            new RotationCache<>(this::calculateDisplayShapeForRotationUncached);
+
     /**
      * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
      * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -1095,7 +1106,8 @@
         mDisplayFrames = new DisplayFrames(mInsetsStateController.getRawInsetsState(),
                 mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
                 calculateRoundedCornersForRotation(mDisplayInfo.rotation),
-                calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
+                calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation),
+                calculateDisplayShapeForRotation(mDisplayInfo.rotation));
         initializeDisplayBaseInfo();
 
         mHoldScreenWakeLock = mWmService.mPowerManager.newWakeLock(
@@ -1969,8 +1981,9 @@
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
         final PrivacyIndicatorBounds indicatorBounds =
                 calculatePrivacyIndicatorBoundsForRotation(rotation);
+        final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
         final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), info,
-                cutout, roundedCorners, indicatorBounds);
+                cutout, roundedCorners, indicatorBounds, displayShape);
         token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
     }
 
@@ -2178,6 +2191,7 @@
         // Update application display metrics.
         final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
         final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
+        final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
 
         final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
         mDisplayInfo.rotation = rotation;
@@ -2194,6 +2208,7 @@
         }
         mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
         mDisplayInfo.roundedCorners = roundedCorners;
+        mDisplayInfo.displayShape = displayShape;
         mDisplayInfo.getAppMetrics(mDisplayMetrics);
         if (mDisplayScalingDisabled) {
             mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -2280,6 +2295,23 @@
         return bounds.rotate(rotation);
     }
 
+    DisplayShape calculateDisplayShapeForRotation(int rotation) {
+        return mDisplayShapeCache.getOrCompute(mInitialDisplayShape, rotation);
+    }
+
+    private DisplayShape calculateDisplayShapeForRotationUncached(
+            DisplayShape displayShape, int rotation) {
+        if (displayShape == null) {
+            return DisplayShape.NONE;
+        }
+
+        if (rotation == ROTATION_0) {
+            return displayShape;
+        }
+
+        return displayShape.setRotation(rotation);
+    }
+
     /**
      * Compute display info and configuration according to the given rotation without changing
      * current display.
@@ -2781,7 +2813,8 @@
         return displayFrames.update(rotation, w, h,
                 calculateDisplayCutoutForRotation(rotation),
                 calculateRoundedCornersForRotation(rotation),
-                calculatePrivacyIndicatorBoundsForRotation(rotation));
+                calculatePrivacyIndicatorBoundsForRotation(rotation),
+                calculateDisplayShapeForRotation(rotation));
     }
 
     @Override
@@ -2821,6 +2854,7 @@
         mInitialRoundedCorners = mDisplayInfo.roundedCorners;
         mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
                 mDisplayInfo.rotation);
+        mInitialDisplayShape = mDisplayInfo.displayShape;
         final Display.Mode maxDisplayMode =
                 DisplayUtils.getMaximumResolutionDisplayMode(mDisplayInfo.supportedModes);
         mPhysicalDisplaySize = new Point(
@@ -2848,6 +2882,7 @@
                 ? DisplayCutout.NO_CUTOUT : mDisplayInfo.displayCutout;
         final String newUniqueId = mDisplayInfo.uniqueId;
         final RoundedCorners newRoundedCorners = mDisplayInfo.roundedCorners;
+        final DisplayShape newDisplayShape = mDisplayInfo.displayShape;
 
         final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
                 || mInitialDisplayHeight != newHeight
@@ -2855,7 +2890,8 @@
                 || mInitialPhysicalXDpi != newXDpi
                 || mInitialPhysicalYDpi != newYDpi
                 || !Objects.equals(mInitialDisplayCutout, newCutout)
-                || !Objects.equals(mInitialRoundedCorners, newRoundedCorners);
+                || !Objects.equals(mInitialRoundedCorners, newRoundedCorners)
+                || !Objects.equals(mInitialDisplayShape, newDisplayShape);
         final boolean physicalDisplayChanged = !newUniqueId.equals(mCurrentUniqueDisplayId);
 
         if (displayMetricsChanged || physicalDisplayChanged) {
@@ -2893,6 +2929,7 @@
             mInitialPhysicalYDpi = newYDpi;
             mInitialDisplayCutout = newCutout;
             mInitialRoundedCorners = newRoundedCorners;
+            mInitialDisplayShape = newDisplayShape;
             mCurrentUniqueDisplayId = newUniqueId;
             reconfigureDisplayLocked();
 
@@ -3380,7 +3417,7 @@
                     }
                 }
                 mWmService.mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN);
-                controller.mTransitionMetricsReporter.associate(t,
+                controller.mTransitionMetricsReporter.associate(t.getToken(),
                         startTime -> mWmService.mLatencyTracker.onActionEnd(ACTION_ROTATE_SCREEN));
                 startAsyncRotation(false /* shouldDebounce */);
             }
@@ -3485,9 +3522,8 @@
 
     @Override
     public void dump(PrintWriter pw, String prefix, boolean dumpAll) {
-        super.dump(pw, prefix, dumpAll);
         pw.print(prefix);
-        pw.println("Display: mDisplayId=" + mDisplayId + " rootTasks=" + getRootTaskCount());
+        pw.println("Display: mDisplayId=" + mDisplayId + (isOrganized() ? " (organized)" : ""));
         final String subPrefix = "  " + prefix;
         pw.print(subPrefix); pw.print("init="); pw.print(mInitialDisplayWidth); pw.print("x");
         pw.print(mInitialDisplayHeight); pw.print(" "); pw.print(mInitialDisplayDensity);
@@ -3518,6 +3554,7 @@
         pw.println(" mTouchExcludeRegion=" + mTouchExcludeRegion);
 
         pw.println();
+        super.dump(pw, prefix, dumpAll);
         pw.print(prefix); pw.print("mLayoutSeq="); pw.println(mLayoutSeq);
 
         pw.print("  mCurrentFocus="); pw.println(mCurrentFocus);
@@ -3609,6 +3646,7 @@
         pw.println();
         mInsetsStateController.dump(prefix, pw);
         mDwpcHelper.dump(prefix, pw);
+        pw.println();
     }
 
     @Override
@@ -3683,7 +3721,7 @@
      * @return The focused window or null if there isn't any or no need to seek.
      */
     WindowState findFocusedWindowIfNeeded(int topFocusedDisplayId) {
-        return (mWmService.mPerDisplayFocusEnabled || topFocusedDisplayId == INVALID_DISPLAY)
+        return (hasOwnFocus() || topFocusedDisplayId == INVALID_DISPLAY)
                     ? findFocusedWindow() : null;
     }
 
@@ -6315,6 +6353,14 @@
     }
 
     /**
+     * @return whether this display maintains its own focus and touch mode.
+     */
+    boolean hasOwnFocus() {
+        return mWmService.mPerDisplayFocusEnabled
+                || (mDisplayInfo.flags & Display.FLAG_OWN_FOCUS) != 0;
+    }
+
+    /**
      * @return whether the keyguard is occluded on this display
      */
     boolean isKeyguardOccluded() {
@@ -6768,10 +6814,9 @@
 
         @Override
         public boolean isRequestedVisible(@InsetsType int types) {
-            if (types == ime()) {
-                return getInsetsStateController().getImeSourceProvider().isImeShowing();
-            }
-            return (mRequestedVisibleTypes & types) != 0;
+            return ((types & ime()) != 0
+                            && getInsetsStateController().getImeSourceProvider().isImeShowing())
+                    || (mRequestedVisibleTypes & types) != 0;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 33641f7..e984456 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -26,6 +26,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
 import android.view.RoundedCorners;
@@ -56,10 +57,11 @@
     public int mRotation;
 
     public DisplayFrames(InsetsState insetsState, DisplayInfo info, DisplayCutout cutout,
-            RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds) {
+            RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds,
+            DisplayShape displayShape) {
         mInsetsState = insetsState;
         update(info.rotation, info.logicalWidth, info.logicalHeight, cutout, roundedCorners,
-                indicatorBounds);
+                indicatorBounds, displayShape);
     }
 
     DisplayFrames() {
@@ -73,7 +75,8 @@
      */
     public boolean update(int rotation, int w, int h, @NonNull DisplayCutout displayCutout,
             @NonNull RoundedCorners roundedCorners,
-            @NonNull PrivacyIndicatorBounds indicatorBounds) {
+            @NonNull PrivacyIndicatorBounds indicatorBounds,
+            @NonNull DisplayShape displayShape) {
         final InsetsState state = mInsetsState;
         final Rect safe = mDisplayCutoutSafe;
         if (mRotation == rotation && mWidth == w && mHeight == h
@@ -91,6 +94,7 @@
         state.setDisplayCutout(displayCutout);
         state.setRoundedCorners(roundedCorners);
         state.setPrivacyIndicatorBounds(indicatorBounds);
+        state.setDisplayShape(displayShape);
         state.getDisplayCutoutSafe(safe);
         if (safe.left > unrestricted.left) {
             state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1fef3c2..9ac1762 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -1202,7 +1202,6 @@
             return null;
         }
         return (displayFrames, windowContainer, inOutFrame) -> {
-            inOutFrame.inset(win.mGivenContentInsets);
             final LayoutParams lp = win.mAttrs.forRotation(displayFrames.mRotation);
             final InsetsFrameProvider ifp = lp.providedInsets[index];
             InsetsFrameProvider.calculateInsetsFrame(displayFrames.mUnrestricted,
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 7860b15..3e1105b 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -270,7 +270,7 @@
                 InputConfigAdapter.getMask());
 
         final boolean focusable = w.canReceiveKeys()
-                && (mService.mPerDisplayFocusEnabled || mDisplayContent.isOnTop());
+                && (mDisplayContent.hasOwnFocus() || mDisplayContent.isOnTop());
         inputWindowHandle.setFocusable(focusable);
 
         final boolean hasWallpaper = mDisplayContent.mWallpaperController.isWallpaperTarget(w)
diff --git a/services/core/java/com/android/server/wm/LetterboxUiController.java b/services/core/java/com/android/server/wm/LetterboxUiController.java
index 2dbccae..bb4c482 100644
--- a/services/core/java/com/android/server/wm/LetterboxUiController.java
+++ b/services/core/java/com/android/server/wm/LetterboxUiController.java
@@ -87,10 +87,6 @@
     private final LetterboxConfiguration mLetterboxConfiguration;
     private final ActivityRecord mActivityRecord;
 
-    // Taskbar expanded height. Used to determine whether to crop an app window to display rounded
-    // corners above the taskbar.
-    private final float mExpandedTaskBarHeight;
-
     private boolean mShowWallpaperForLetterboxBackground;
 
     @Nullable
@@ -102,8 +98,6 @@
         // is created in its constructor. It shouldn't be used in this constructor but it's safe
         // to use it after since controller is only used in ActivityRecord.
         mActivityRecord = activityRecord;
-        mExpandedTaskBarHeight =
-                getResources().getDimensionPixelSize(R.dimen.taskbar_frame_height);
     }
 
     /** Cleans up {@link Letterbox} if it exists.*/
@@ -285,14 +279,17 @@
     }
 
     float getSplitScreenAspectRatio() {
+        // Getting the same aspect ratio that apps get in split screen.
+        final DisplayContent displayContent = mActivityRecord.getDisplayContent();
+        if (displayContent == null) {
+            return getDefaultMinAspectRatioForUnresizableApps();
+        }
         int dividerWindowWidth =
                 getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_thickness);
         int dividerInsets =
                 getResources().getDimensionPixelSize(R.dimen.docked_stack_divider_insets);
         int dividerSize = dividerWindowWidth - dividerInsets * 2;
-
-        // Getting the same aspect ratio that apps get in split screen.
-        Rect bounds = new Rect(mActivityRecord.getDisplayContent().getBounds());
+        final Rect bounds = new Rect(displayContent.getBounds());
         if (bounds.width() >= bounds.height()) {
             bounds.inset(/* dx */ dividerSize / 2, /* dy */ 0);
             bounds.right = bounds.centerX();
@@ -555,7 +552,6 @@
         final InsetsSource taskbarInsetsSource = getTaskbarInsetsSource(mainWindow);
 
         return taskbarInsetsSource != null
-                && taskbarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight
                 && taskbarInsetsSource.isVisible();
     }
 
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index d34e610..3635ebb 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -104,10 +104,29 @@
     RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
             Point position, Rect localBounds, Rect endBounds, Rect startBounds,
             boolean showBackdrop) {
+        return createRemoteAnimationRecord(windowContainer, position, localBounds, endBounds,
+                startBounds, showBackdrop, startBounds != null /* shouldCreateSnapshot */);
+    }
+
+    /**
+     * Creates an animation record for each individual {@link WindowContainer}.
+     *
+     * @param windowContainer The windows to animate.
+     * @param position        The position app bounds relative to its parent.
+     * @param localBounds     The bounds of the app relative to its parent.
+     * @param endBounds       The end bounds after the transition, in screen coordinates.
+     * @param startBounds     The start bounds before the transition, in screen coordinates.
+     * @param showBackdrop    To show background behind a window during animation.
+     * @param shouldCreateSnapshot   Whether this target should create a snapshot animation.
+     * @return The record representing animation(s) to run on the app.
+     */
+    RemoteAnimationRecord createRemoteAnimationRecord(WindowContainer windowContainer,
+            Point position, Rect localBounds, Rect endBounds, Rect startBounds,
+            boolean showBackdrop, boolean shouldCreateSnapshot) {
         ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "createAnimationAdapter(): container=%s",
                 windowContainer);
         final RemoteAnimationRecord adapters = new RemoteAnimationRecord(windowContainer, position,
-                localBounds, endBounds, startBounds, showBackdrop);
+                localBounds, endBounds, startBounds, showBackdrop, shouldCreateSnapshot);
         mPendingAnimations.add(adapters);
         return adapters;
     }
@@ -441,14 +460,15 @@
         private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;
 
         RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
-                Rect endBounds, Rect startBounds, boolean showBackdrop) {
+                Rect endBounds, @Nullable Rect startBounds, boolean showBackdrop,
+                boolean shouldCreateSnapshot) {
             mWindowContainer = windowContainer;
             mShowBackdrop = showBackdrop;
             if (startBounds != null) {
                 mStartBounds = new Rect(startBounds);
                 mAdapter = new RemoteAnimationAdapterWrapper(this, endPos, localBounds, endBounds,
                         mStartBounds, mShowBackdrop);
-                if (mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
+                if (shouldCreateSnapshot && mRemoteAnimationAdapter.getChangeNeedsSnapshot()) {
                     final Rect thumbnailLocalBounds = new Rect(startBounds);
                     thumbnailLocalBounds.offsetTo(0, 0);
                     // Snapshot is located at (0,0) of the animation leash. It doesn't have size
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index d53ee1e..64cca87 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -3407,7 +3407,6 @@
             final DisplayContent display = getChildAt(i);
             display.dump(pw, prefix, dumpAll);
         }
-        pw.println();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 94d4dde..2e5ab1a 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -441,6 +441,7 @@
                         .setPixelFormat(PixelFormat.RGBA_8888)
                         .setChildrenOnly(true)
                         .setAllowProtected(true)
+                        .setCaptureSecureLayers(true)
                         .build();
         final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
                 ScreenCapture.captureLayers(captureArgs);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 356cbda..a93767e 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -498,6 +498,12 @@
      */
     boolean mInRemoveTask;
 
+    /**
+     * When set, disassociate the leaf task if relaunched and reparented it to TDA as root task if
+     * possible.
+     */
+    boolean mReparentLeafTaskIfRelaunch;
+
     private final AnimatingActivityRegistry mAnimatingActivityRegistry =
             new AnimatingActivityRegistry();
 
@@ -6064,6 +6070,12 @@
         }
     }
 
+    void setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) {
+        if (isOrganized()) {
+            mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch;
+        }
+    }
+
     @Override
     public void dumpDebug(ProtoOutputStream proto, long fieldId,
             @WindowTraceLogLevel int logLevel) {
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index f3ed937..25b58fa 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -899,15 +899,16 @@
             }
         } else if (candidateTask != null) {
             final int position = onTop ? POSITION_TOP : POSITION_BOTTOM;
-            final Task launchRootTask = getLaunchRootTask(resolvedWindowingMode, activityType,
+            final Task launchParentTask = getLaunchRootTask(resolvedWindowingMode, activityType,
                     options, sourceTask, launchFlags, candidateTask);
-            if (launchRootTask != null) {
+            if (launchParentTask != null) {
                 if (candidateTask.getParent() == null) {
-                    launchRootTask.addChild(candidateTask, position);
-                } else if (candidateTask.getParent() != launchRootTask) {
-                    candidateTask.reparent(launchRootTask, position);
+                    launchParentTask.addChild(candidateTask, position);
+                } else if (candidateTask.getParent() != launchParentTask) {
+                    candidateTask.reparent(launchParentTask, position);
                 }
-            } else if (candidateTask.getDisplayArea() != this) {
+            } else if (candidateTask.getDisplayArea() != this
+                    || candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) {
                 if (candidateTask.getParent() == null) {
                     addChild(candidateTask, position);
                 } else {
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 91cb037..d69d949 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -172,13 +172,6 @@
      * indicate that an Activity can't be embedded because the Activity is started on a new task.
      */
     static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
-    /**
-     * An embedding check result of
-     * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
-     * indicate that an Activity can't be embedded because the Activity is started on a new
-     * TaskFragment, e.g. start an Activity on a new TaskFragment for result.
-     */
-    static final int EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT = 4;
 
     /**
      * Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
@@ -189,7 +182,6 @@
             EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
             EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
             EMBEDDING_DISALLOWED_NEW_TASK,
-            EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
     })
     @interface EmbeddingCheckResult {}
 
@@ -616,14 +608,6 @@
             return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
         }
 
-        // Cannot embed activity across TaskFragments for activity result.
-        // If the activity that started for result is finishing, it's likely that this start mode
-        // is used to place an activity in the same task. Since the finishing activity won't be
-        // able to get the results, so it's OK to embed in a different TaskFragment.
-        if (a.resultTo != null && !a.resultTo.finishing && a.resultTo.getTaskFragment() != this) {
-            return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
-        }
-
         return EMBEDDING_ALLOWED;
     }
 
@@ -1167,8 +1151,16 @@
         }
 
         next.delayedResume = false;
-        final TaskDisplayArea taskDisplayArea = getDisplayArea();
 
+        // If we are currently pausing an activity, then don't do anything until that is done.
+        final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
+        if (!allPausedComplete) {
+            ProtoLog.v(WM_DEBUG_STATES,
+                    "resumeTopActivity: Skip resume: some activity pausing.");
+            return false;
+        }
+
+        final TaskDisplayArea taskDisplayArea = getDisplayArea();
         // If the top activity is the resumed one, nothing to do.
         if (mResumedActivity == next && next.isState(RESUMED)
                 && taskDisplayArea.allResumedActivitiesComplete()) {
@@ -1191,14 +1183,6 @@
             return false;
         }
 
-        // If we are currently pausing an activity, then don't do anything until that is done.
-        final boolean allPausedComplete = mRootWindowContainer.allPausedActivitiesComplete();
-        if (!allPausedComplete) {
-            ProtoLog.v(WM_DEBUG_STATES,
-                    "resumeTopActivity: Skip resume: some activity pausing.");
-            return false;
-        }
-
         // If we are sleeping, and there is no resumed activity, and the top activity is paused,
         // well that is the state we want.
         if (mLastPausedActivity == next && shouldSleepOrShutDownActivities()) {
@@ -2336,11 +2320,7 @@
     @Override
     public void onConfigurationChanged(Configuration newParentConfig) {
         super.onConfigurationChanged(newParentConfig);
-
-        if (mTaskFragmentOrganizer != null) {
-            updateOrganizedTaskFragmentSurface();
-        }
-
+        updateOrganizedTaskFragmentSurface();
         sendTaskFragmentInfoChanged();
     }
 
@@ -2353,8 +2333,13 @@
         updateOrganizedTaskFragmentSurface();
     }
 
-    private void updateOrganizedTaskFragmentSurface() {
-        if (mDelayOrganizedTaskFragmentSurfaceUpdate) {
+    /**
+     * TaskFragmentOrganizer doesn't have access to the surface for security reasons, so we need to
+     * update its surface on the server side if it is not collected for Shell or in pending
+     * animation.
+     */
+    void updateOrganizedTaskFragmentSurface() {
+        if (mDelayOrganizedTaskFragmentSurfaceUpdate || mTaskFragmentOrganizer == null) {
             return;
         }
         if (mTransitionController.isShellTransitionsEnabled()
@@ -2386,7 +2371,10 @@
             return;
         }
 
-        final Rect bounds = getBounds();
+        // If this TaskFragment is closing while resizing, crop to the starting bounds instead.
+        final Rect bounds = isClosingWhenResizing()
+                ? mDisplayContent.mClosingChangingContainers.get(this)
+                : getBounds();
         final int width = bounds.width();
         final int height = bounds.height();
         if (!forceUpdate && width == mLastSurfaceSize.x && height == mLastSurfaceSize.y) {
@@ -2434,6 +2422,15 @@
                 || endBounds.height() != startBounds.height();
     }
 
+    /** Records the starting bounds of the closing organized TaskFragment. */
+    void setClosingChangingStartBoundsIfNeeded() {
+        if (isOrganizedTaskFragment() && mDisplayContent != null
+                && mDisplayContent.mChangingContainers.remove(this)) {
+            mDisplayContent.mClosingChangingContainers.put(
+                    this, new Rect(mSurfaceFreezer.mFreezeBounds));
+        }
+    }
+
     @Override
     boolean isSyncFinished() {
         return super.isSyncFinished() && isReadyToTransit();
@@ -2596,6 +2593,14 @@
         return false;
     }
 
+    @Override
+    boolean canCustomizeAppTransition() {
+        // This is only called when the app transition is going to be played by system server. In
+        // this case, we should allow custom app transition for fullscreen embedded TaskFragment
+        // just like Activity.
+        return isEmbedded() && matchParentBounds();
+    }
+
     /** Clear {@link #mLastPausedActivity} for all {@link TaskFragment} children */
     void clearLastPausedActivity() {
         forAllTaskFragments(taskFragment -> taskFragment.mLastPausedActivity = null);
diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
index 6d149da..ad46770 100644
--- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
+++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java
@@ -165,9 +165,11 @@
         }
         // If the launch windowing mode is still undefined, inherit from the target task if the
         // task is already on the right display area (otherwise, the task may be on a different
-        // display area that has incompatible windowing mode).
+        // display area that has incompatible windowing mode or the task organizer request to
+        // disassociate the leaf task if relaunched and reparented it to TDA as root task).
         if (launchMode == WINDOWING_MODE_UNDEFINED
-                && task != null && task.getTaskDisplayArea() == suggestedDisplayArea) {
+                && task != null && task.getTaskDisplayArea() == suggestedDisplayArea
+                && !task.getRootTask().mReparentLeafTaskIfRelaunch) {
             launchMode = task.getWindowingMode();
             if (DEBUG) {
                 appendLog("inherit-from-task="
@@ -278,31 +280,29 @@
         // is set with the suggestedDisplayArea. If it is set, but the eventual TaskDisplayArea is
         // different, we should recalcuating the bounds.
         boolean hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = false;
-        // shouldSetAsOverrideWindowingMode is set if the task needs to retain the launchMode
-        // regardless of the windowing mode of the parent.
-        boolean shouldSetAsOverrideWindowingMode = false;
-        if (launchMode == WINDOWING_MODE_PINNED) {
-            if (DEBUG) appendLog("picture-in-picture");
-        } else if (!root.isResizeable()) {
-            if (shouldLaunchUnresizableAppInFreeformInFreeformMode(root, suggestedDisplayArea,
-                    options)) {
-                launchMode = WINDOWING_MODE_UNDEFINED;
-                if (outParams.mBounds.isEmpty()) {
-                    getTaskBounds(root, suggestedDisplayArea, layout, launchMode, hasInitialBounds,
-                            outParams.mBounds);
-                    hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = true;
+        if (suggestedDisplayArea.inFreeformWindowingMode()) {
+            if (launchMode == WINDOWING_MODE_PINNED) {
+                if (DEBUG) appendLog("picture-in-picture");
+            } else if (!root.isResizeable()) {
+                if (shouldLaunchUnresizableAppInFreeform(root, suggestedDisplayArea, options)) {
+                    launchMode = WINDOWING_MODE_FREEFORM;
+                    if (outParams.mBounds.isEmpty()) {
+                        getTaskBounds(root, suggestedDisplayArea, layout, launchMode,
+                                hasInitialBounds, outParams.mBounds);
+                        hasInitialBoundsForSuggestedDisplayAreaInFreeformMode = true;
+                    }
+                    if (DEBUG) appendLog("unresizable-freeform");
+                } else {
+                    launchMode = WINDOWING_MODE_FULLSCREEN;
+                    outParams.mBounds.setEmpty();
+                    if (DEBUG) appendLog("unresizable-forced-maximize");
                 }
-                if (DEBUG) appendLog("unresizable-freeform");
-            } else {
-                launchMode = WINDOWING_MODE_FULLSCREEN;
-                outParams.mBounds.setEmpty();
-                shouldSetAsOverrideWindowingMode = true;
-                if (DEBUG) appendLog("unresizable-forced-maximize");
             }
+        } else {
+            if (DEBUG) appendLog("non-freeform-task-display-area");
         }
         // If launch mode matches display windowing mode, let it inherit from display.
         outParams.mWindowingMode = launchMode == suggestedDisplayArea.getWindowingMode()
-                && !shouldSetAsOverrideWindowingMode
                 ? WINDOWING_MODE_UNDEFINED : launchMode;
 
         if (phase == PHASE_WINDOWING_MODE) {
@@ -669,7 +669,7 @@
         inOutBounds.offset(xOffset, yOffset);
     }
 
-    private boolean shouldLaunchUnresizableAppInFreeformInFreeformMode(ActivityRecord activity,
+    private boolean shouldLaunchUnresizableAppInFreeform(ActivityRecord activity,
             TaskDisplayArea displayArea, @Nullable ActivityOptions options) {
         if (options != null && options.getLaunchWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
             // Do not launch the activity in freeform if it explicitly requested fullscreen mode.
@@ -682,7 +682,8 @@
         final int displayOrientation = orientationFromBounds(displayArea.getBounds());
         final int activityOrientation = resolveOrientation(activity, displayArea,
                 displayArea.getBounds());
-        if (displayOrientation != activityOrientation) {
+        if (displayArea.getWindowingMode() == WINDOWING_MODE_FREEFORM
+                && displayOrientation != activityOrientation) {
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 0a2e877..274d7ff 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -691,6 +691,8 @@
             if (mainWindow == null || mainWindow.mRemoved) {
                 removalInfo.playRevealAnimation = false;
             } else if (removalInfo.playRevealAnimation && playShiftUpAnimation) {
+                removalInfo.roundedCornerRadius =
+                        topActivity.mLetterboxUiController.getRoundedCornersRadius(mainWindow);
                 removalInfo.windowAnimationLeash = applyStartingWindowAnimation(mainWindow);
                 removalInfo.mainFrame = mainWindow.getRelativeFrame();
             }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 29c98b9..c1b9e662 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -16,29 +16,14 @@
 
 package com.android.server.wm;
 
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
-import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
-import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
-
-import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
-import static com.android.internal.policy.DecorView.getNavigationBarRect;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.app.ActivityThread;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.RecordingCanvas;
@@ -59,12 +44,11 @@
 import android.view.WindowInsetsController.Appearance;
 import android.view.WindowManager.LayoutParams;
 import android.window.ScreenCapture;
+import android.window.SnapshotDrawerUtils;
 import android.window.TaskSnapshot;
 
-import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.graphics.ColorUtils;
-import com.android.internal.policy.DecorView;
 import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
 import com.android.server.wm.utils.InsetUtils;
 
@@ -585,7 +569,8 @@
         final Rect taskBounds = task.getBounds();
         final InsetsState insetsState = mainWindow.getInsetsStateWithVisibilityOverride();
         final Rect systemBarInsets = getSystemBarInsets(mainWindow.getFrame(), insetsState);
-        final SystemBarBackgroundPainter decorPainter = new SystemBarBackgroundPainter(attrs.flags,
+        final SnapshotDrawerUtils.SystemBarBackgroundPainter decorPainter =
+                new SnapshotDrawerUtils.SystemBarBackgroundPainter(attrs.flags,
                 attrs.privateFlags, attrs.insetsFlags.appearance, task.getTaskDescription(),
                 mHighResTaskSnapshotScale, mainWindow.getRequestedVisibleTypes());
         final int taskWidth = taskBounds.width();
@@ -599,7 +584,7 @@
         final RecordingCanvas c = node.start(width, height);
         c.drawColor(color);
         decorPainter.setInsets(systemBarInsets);
-        decorPainter.drawDecors(c /* statusBarExcludeFrame */);
+        decorPainter.drawDecors(c /* statusBarExcludeFrame */, null /* alreadyDrawnFrame */);
         node.end(c);
         final Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, width, height);
         if (hwBitmap == null) {
@@ -736,92 +721,4 @@
         pw.println(prefix + "mTaskSnapshotEnabled=" + mTaskSnapshotEnabled);
         mCache.dump(pw, prefix);
     }
-
-    /**
-     * Helper class to draw the background of the system bars in regions the task snapshot isn't
-     * filling the window.
-     */
-    static class SystemBarBackgroundPainter {
-
-        private final Paint mStatusBarPaint = new Paint();
-        private final Paint mNavigationBarPaint = new Paint();
-        private final int mStatusBarColor;
-        private final int mNavigationBarColor;
-        private final int mWindowFlags;
-        private final int mWindowPrivateFlags;
-        private final float mScale;
-        private final @Type.InsetsType int mRequestedVisibleTypes;
-        private final Rect mSystemBarInsets = new Rect();
-
-        SystemBarBackgroundPainter(int windowFlags, int windowPrivateFlags, int appearance,
-                ActivityManager.TaskDescription taskDescription, float scale,
-                @Type.InsetsType int requestedVisibleTypes) {
-            mWindowFlags = windowFlags;
-            mWindowPrivateFlags = windowPrivateFlags;
-            mScale = scale;
-            final Context context = ActivityThread.currentActivityThread().getSystemUiContext();
-            final int semiTransparent = context.getColor(
-                    R.color.system_bar_background_semi_transparent);
-            mStatusBarColor = DecorView.calculateBarColor(windowFlags, FLAG_TRANSLUCENT_STATUS,
-                    semiTransparent, taskDescription.getStatusBarColor(), appearance,
-                    APPEARANCE_LIGHT_STATUS_BARS,
-                    taskDescription.getEnsureStatusBarContrastWhenTransparent());
-            mNavigationBarColor = DecorView.calculateBarColor(windowFlags,
-                    FLAG_TRANSLUCENT_NAVIGATION, semiTransparent,
-                    taskDescription.getNavigationBarColor(), appearance,
-                    APPEARANCE_LIGHT_NAVIGATION_BARS,
-                    taskDescription.getEnsureNavigationBarContrastWhenTransparent()
-                            && context.getResources().getBoolean(R.bool.config_navBarNeedsScrim));
-            mStatusBarPaint.setColor(mStatusBarColor);
-            mNavigationBarPaint.setColor(mNavigationBarColor);
-            mRequestedVisibleTypes = requestedVisibleTypes;
-        }
-
-        void setInsets(Rect systemBarInsets) {
-            mSystemBarInsets.set(systemBarInsets);
-        }
-
-        int getStatusBarColorViewHeight() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            if (STATUS_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mStatusBarColor, mWindowFlags, forceBarBackground)) {
-                return (int) (mSystemBarInsets.top * mScale);
-            } else {
-                return 0;
-            }
-        }
-
-        private boolean isNavigationBarColorViewVisible() {
-            final boolean forceBarBackground =
-                    (mWindowPrivateFlags & PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS) != 0;
-            return NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES.isVisible(
-                    mRequestedVisibleTypes, mNavigationBarColor, mWindowFlags, forceBarBackground);
-        }
-
-        void drawDecors(Canvas c) {
-            drawStatusBarBackground(c, getStatusBarColorViewHeight());
-            drawNavigationBarBackground(c);
-        }
-
-        @VisibleForTesting
-        void drawStatusBarBackground(Canvas c,
-                int statusBarHeight) {
-            if (statusBarHeight > 0 && Color.alpha(mStatusBarColor) != 0) {
-                final int rightInset = (int) (mSystemBarInsets.right * mScale);
-                c.drawRect(0, 0, c.getWidth() - rightInset, statusBarHeight, mStatusBarPaint);
-            }
-        }
-
-        @VisibleForTesting
-        void drawNavigationBarBackground(Canvas c) {
-            final Rect navigationBarRect = new Rect();
-            getNavigationBarRect(c.getWidth(), c.getHeight(), mSystemBarInsets, navigationBarRect,
-                    mScale);
-            final boolean visible = isNavigationBarColorViewVisible();
-            if (visible && Color.alpha(mNavigationBarColor) != 0 && !navigationBarRect.isEmpty()) {
-                c.drawRect(navigationBarRect, mNavigationBarPaint);
-            }
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 4f91c54..2b11d54 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -91,6 +91,7 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
@@ -100,7 +101,7 @@
  * Represents a logical transition.
  * @see TransitionController
  */
-class Transition extends Binder implements BLASTSyncEngine.TransactionReadyListener {
+class Transition implements BLASTSyncEngine.TransactionReadyListener {
     private static final String TAG = "Transition";
     private static final String TRACE_NAME_PLAY_TRANSITION = "PlayTransition";
 
@@ -151,6 +152,7 @@
     private @TransitionFlags int mFlags;
     private final TransitionController mController;
     private final BLASTSyncEngine mSyncEngine;
+    private final Token mToken;
     private RemoteTransition mRemoteTransition = null;
 
     /** Only use for clean-up after binder death! */
@@ -158,9 +160,9 @@
     private SurfaceControl.Transaction mFinishTransaction = null;
 
     /**
-     * Contains change infos for both participants and all ancestors. We have to track ancestors
-     * because they are all promotion candidates and thus we need their start-states
-     * to be captured.
+     * Contains change infos for both participants and all remote-animatable ancestors. The
+     * ancestors can be the promotion candidates so their start-states need to be captured.
+     * @see #getAnimatableParent
      */
     final ArrayMap<WindowContainer, ChangeInfo> mChanges = new ArrayMap<>();
 
@@ -213,10 +215,27 @@
         mFlags = flags;
         mController = controller;
         mSyncEngine = syncEngine;
+        mToken = new Token(this);
 
         controller.mTransitionTracer.logState(this);
     }
 
+    @Nullable
+    static Transition fromBinder(@Nullable IBinder token) {
+        if (token == null) return null;
+        try {
+            return ((Token) token).mTransition.get();
+        } catch (ClassCastException e) {
+            Slog.w(TAG, "Invalid transition token: " + token, e);
+            return null;
+        }
+    }
+
+    @NonNull
+    IBinder getToken() {
+        return mToken;
+    }
+
     void addFlag(int flag) {
         mFlags |= flag;
     }
@@ -338,7 +357,7 @@
         return mFinishTransaction;
     }
 
-    private boolean isCollecting() {
+    boolean isCollecting() {
         return mState == STATE_COLLECTING || mState == STATE_STARTED;
     }
 
@@ -392,8 +411,9 @@
                 mSyncId, wc);
         // "snapshot" all parents (as potential promotion targets). Do this before checking
         // if this is already a participant in case it has since been re-parented.
-        for (WindowContainer curr = wc.getParent(); curr != null && !mChanges.containsKey(curr);
-                curr = curr.getParent()) {
+        for (WindowContainer<?> curr = getAnimatableParent(wc);
+                curr != null && !mChanges.containsKey(curr);
+                curr = getAnimatableParent(curr)) {
             mChanges.put(curr, new ChangeInfo(curr));
             if (isReadyGroup(curr)) {
                 mReadyTracker.addGroup(curr);
@@ -726,6 +746,11 @@
             Trace.asyncTraceEnd(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
                     System.identityHashCode(this));
         }
+        // Close the transactions now. They were originally copied to Shell in case we needed to
+        // apply them due to a remote failure. Since we don't need to apply them anymore, free them
+        // immediately.
+        if (mStartTransaction != null) mStartTransaction.close();
+        if (mFinishTransaction != null) mFinishTransaction.close();
         mStartTransaction = mFinishTransaction = null;
         if (mState < STATE_PLAYING) {
             throw new IllegalStateException("Can't finish a non-playing transition " + mSyncId);
@@ -867,6 +892,7 @@
             mController.mAtm.mWindowManager.updateRotation(false /* alwaysSendConfiguration */,
                     false /* forceRelayout */);
         }
+        cleanUpInternal();
     }
 
     void abort() {
@@ -909,6 +935,7 @@
             dc.getPendingTransaction().merge(transaction);
             mSyncId = -1;
             mOverrideOptions = null;
+            cleanUpInternal();
             return;
         }
 
@@ -1026,7 +1053,9 @@
                 ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
                         "Calling onTransitionReady: %s", info);
                 mController.getTransitionPlayer().onTransitionReady(
-                        this, info, transaction, mFinishTransaction);
+                        mToken, info, transaction, mFinishTransaction);
+                // Since we created root-leash but no longer reference it from core, release it now
+                info.releaseAnimSurfaces();
                 if (Trace.isTagEnabled(TRACE_TAG_WINDOW_MANAGER)) {
                     Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, TRACE_NAME_PLAY_TRANSITION,
                             System.identityHashCode(this));
@@ -1059,7 +1088,17 @@
         if (mFinishTransaction != null) {
             mFinishTransaction.apply();
         }
-        mController.finishTransition(this);
+        mController.finishTransition(mToken);
+    }
+
+    private void cleanUpInternal() {
+        // Clean-up any native references.
+        for (int i = 0; i < mChanges.size(); ++i) {
+            final ChangeInfo ci = mChanges.valueAt(i);
+            if (ci.mSnapshot != null) {
+                ci.mSnapshot.release();
+            }
+        }
     }
 
     /** @see RecentsAnimationController#attachNavigationBarToApp */
@@ -1234,6 +1273,16 @@
         return sb.toString();
     }
 
+    /** Returns the parent that the remote animator can animate or control. */
+    private static WindowContainer<?> getAnimatableParent(WindowContainer<?> wc) {
+        WindowContainer<?> parent = wc.getParent();
+        while (parent != null
+                && (!parent.canCreateRemoteAnimationTarget() && !parent.isOrganized())) {
+            parent = parent.getParent();
+        }
+        return parent;
+    }
+
     private static boolean reportIfNotTop(WindowContainer wc) {
         // Organized tasks need to be reported anyways because Core won't show() their surfaces
         // and we can't rely on onTaskAppeared because it isn't in sync.
@@ -1457,7 +1506,8 @@
             intermediates.clear();
             boolean foundParentInTargets = false;
             // Collect the intermediate parents between target and top changed parent.
-            for (WindowContainer<?> p = wc.getParent(); p != null; p = p.getParent()) {
+            for (WindowContainer<?> p = getAnimatableParent(wc); p != null;
+                    p = getAnimatableParent(p)) {
                 final ChangeInfo parentChange = changes.get(p);
                 if (parentChange == null || !parentChange.hasChanged(p)) break;
                 if (p.mRemoteToken == null) {
@@ -1815,10 +1865,6 @@
         return isCollecting() && mSyncId >= 0;
     }
 
-    static Transition fromBinder(IBinder binder) {
-        return (Transition) binder;
-    }
-
     @VisibleForTesting
     static class ChangeInfo {
         private static final int FLAG_NONE = 0;
@@ -2325,4 +2371,18 @@
             }
         }
     }
+
+    private static class Token extends Binder {
+        final WeakReference<Transition> mTransition;
+
+        Token(Transition transition) {
+            mTransition = new WeakReference<>(transition);
+        }
+
+        @Override
+        public String toString() {
+            return "Token{" + Integer.toHexString(System.identityHashCode(this)) + " "
+                    + mTransition.get() + "}";
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 25df511..99527b1 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -458,8 +458,9 @@
                 info = new ActivityManager.RunningTaskInfo();
                 startTask.fillTaskInfo(info);
             }
-            mTransitionPlayer.requestStartTransition(transition, new TransitionRequestInfo(
-                    transition.mType, info, remoteTransition, displayChange));
+            mTransitionPlayer.requestStartTransition(transition.getToken(),
+                    new TransitionRequestInfo(transition.mType, info, remoteTransition,
+                            displayChange));
             transition.setRemoteTransition(remoteTransition);
         } catch (RemoteException e) {
             Slog.e(TAG, "Error requesting transition", e);
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 6522d93..3b30dd1 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -114,12 +114,6 @@
 
     private boolean mShouldUpdateZoom;
 
-    /**
-     * Temporary storage for taking a screenshot of the wallpaper.
-     * @see #screenshotWallpaperLocked()
-     */
-    private WindowState mTmpTopWallpaper;
-
     @Nullable private Point mLargestDisplaySize = null;
 
     private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
@@ -965,21 +959,16 @@
     }
 
     WindowState getTopVisibleWallpaper() {
-        mTmpTopWallpaper = null;
-
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
             final WallpaperWindowToken token = mWallpaperTokens.get(curTokenNdx);
-            token.forAllWindows(w -> {
-                final WindowStateAnimator winAnim = w.mWinAnimator;
-                if (winAnim != null && winAnim.getShown() && winAnim.mLastAlpha > 0f) {
-                    mTmpTopWallpaper = w;
-                    return true;
+            for (int i = token.getChildCount() - 1; i >= 0; i--) {
+                final WindowState w = token.getChildAt(i);
+                if (w.mWinAnimator.getShown() && w.mWinAnimator.mLastAlpha > 0f) {
+                    return w;
                 }
-                return false;
-            }, true /* traverseTopToBottom */);
+            }
         }
-
-        return mTmpTopWallpaper;
+        return null;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 05dea0e..6e61071 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -813,6 +813,7 @@
     void removeImmediately() {
         final DisplayContent dc = getDisplayContent();
         if (dc != null) {
+            dc.mClosingChangingContainers.remove(this);
             mSurfaceFreezer.unfreeze(getSyncTransaction());
         }
         while (!mChildren.isEmpty()) {
@@ -1022,9 +1023,12 @@
      * @param dc The display this container is on after changes.
      */
     void onDisplayChanged(DisplayContent dc) {
-        if (mDisplayContent != null && mDisplayContent.mChangingContainers.remove(this)) {
-            // Cancel any change transition queued-up for this container on the old display.
-            mSurfaceFreezer.unfreeze(getSyncTransaction());
+        if (mDisplayContent != null) {
+            mDisplayContent.mClosingChangingContainers.remove(this);
+            if (mDisplayContent.mChangingContainers.remove(this)) {
+                // Cancel any change transition queued-up for this container on the old display.
+                mSurfaceFreezer.unfreeze(getSyncTransaction());
+            }
         }
         mDisplayContent = dc;
         if (dc != null && dc != this) {
@@ -1301,6 +1305,13 @@
         // If we are losing visibility, then a snapshot isn't necessary and we are no-longer
         // part of a change transition.
         if (!visible) {
+            if (asTaskFragment() != null) {
+                // If the organized TaskFragment is closing while resizing, we want to keep track of
+                // its starting bounds to make sure the animation starts at the correct position.
+                // This should be called before unfreeze() because we record the starting bounds
+                // in SurfaceFreezer.
+                asTaskFragment().setClosingChangingStartBoundsIfNeeded();
+            }
             mSurfaceFreezer.unfreeze(getSyncTransaction());
         }
         WindowContainer parent = getParent();
@@ -1309,6 +1320,12 @@
         }
     }
 
+    /** Whether this window is closing while resizing. */
+    boolean isClosingWhenResizing() {
+        return mDisplayContent != null
+                && mDisplayContent.mClosingChangingContainers.containsKey(this);
+    }
+
     void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) {
         final long token = proto.start(fieldId);
         proto.write(HASH_CODE, System.identityHashCode(this));
@@ -3018,10 +3035,22 @@
             }
             final Rect localBounds = new Rect(mTmpRect);
             localBounds.offsetTo(mTmpPoint.x, mTmpPoint.y);
-            final RemoteAnimationController.RemoteAnimationRecord adapters =
-                    controller.createRemoteAnimationRecord(
-                            this, mTmpPoint, localBounds, screenBounds,
-                            (isChanging ? mSurfaceFreezer.mFreezeBounds : null), showBackdrop);
+            final RemoteAnimationController.RemoteAnimationRecord adapters;
+            if (!isChanging && !enter && isClosingWhenResizing()) {
+                // Container that is closing while resizing. Pass in the closing start bounds, so
+                // the animation can start with the correct bounds, there won't be a snapshot.
+                // Cleanup the mClosingChangingContainers so that when the animation is finished, it
+                // will reset the surface.
+                final Rect closingStartBounds = getDisplayContent().mClosingChangingContainers
+                        .remove(this);
+                adapters = controller.createRemoteAnimationRecord(
+                        this, mTmpPoint, localBounds, screenBounds, closingStartBounds,
+                        showBackdrop, false /* shouldCreateSnapshot */);
+            } else {
+                final Rect startBounds = isChanging ? mSurfaceFreezer.mFreezeBounds : null;
+                adapters = controller.createRemoteAnimationRecord(
+                        this, mTmpPoint, localBounds, screenBounds, startBounds, showBackdrop);
+            }
             if (backdropColor != 0) {
                 adapters.setBackDropColor(backdropColor);
             }
@@ -3470,7 +3499,13 @@
             return;
         }
 
-        getRelativePosition(mTmpPos);
+        if (isClosingWhenResizing()) {
+            // This container is closing while resizing, keep its surface at the starting position
+            // to prevent animation flicker.
+            getRelativePosition(mDisplayContent.mClosingChangingContainers.get(this), mTmpPos);
+        } else {
+            getRelativePosition(mTmpPos);
+        }
         final int deltaRotation = getRelativeDisplayRotation();
         if (mTmpPos.equals(mLastSurfacePosition) && deltaRotation == mLastDeltaRotation) {
             return;
@@ -3535,9 +3570,14 @@
         outSurfaceInsets.setEmpty();
     }
 
+    /** Gets the position of this container in its parent's coordinate. */
     void getRelativePosition(Point outPos) {
-        final Rect dispBounds = getBounds();
-        outPos.set(dispBounds.left, dispBounds.top);
+        getRelativePosition(getBounds(), outPos);
+    }
+
+    /** Gets the position of {@code curBounds} in this container's parent's coordinate. */
+    void getRelativePosition(Rect curBounds, Point outPos) {
+        outPos.set(curBounds.left, curBounds.top);
         final WindowContainer parent = getParent();
         if (parent != null) {
             final Rect parentBounds = parent.getBounds();
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 42cd8c1..f6f825f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2553,6 +2553,12 @@
                         && win.mSyncSeqId > lastSyncSeqId) {
                     maybeSyncSeqId = win.shouldSyncWithBuffers() ? win.mSyncSeqId : -1;
                     win.markRedrawForSyncReported();
+                    if (win.mSyncState == WindowContainer.SYNC_STATE_WAITING_FOR_DRAW
+                            && winAnimator.mDrawState == WindowStateAnimator.HAS_DRAWN
+                            && maybeSyncSeqId < 0) {
+                        // Do not wait for a drawn window which won't report draw.
+                        win.onSyncFinishedDrawing();
+                    }
                 } else {
                     maybeSyncSeqId = -1;
                 }
@@ -3841,6 +3847,11 @@
                     || displayContent.isInTouchMode() == inTouch)) {
                 return;
             }
+            final boolean displayHasOwnTouchMode =
+                    displayContent != null && displayContent.hasOwnFocus();
+            if (displayHasOwnTouchMode && displayContent.isInTouchMode() == inTouch) {
+                return;
+            }
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final boolean hasPermission =
@@ -3849,17 +3860,17 @@
                             /* printlog= */ false);
             final long token = Binder.clearCallingIdentity();
             try {
-                // If perDisplayFocusEnabled is set, then just update the display pointed by
-                // displayId
-                if (perDisplayFocusEnabled) {
+                // If perDisplayFocusEnabled is set or the display maintains its own touch mode,
+                // then just update the display pointed by displayId
+                if (perDisplayFocusEnabled || displayHasOwnTouchMode) {
                     if (mInputManager.setInTouchMode(inTouch, pid, uid, hasPermission, displayId)) {
                         displayContent.setInTouchMode(inTouch);
                     }
-                } else {  // Otherwise update all displays
+                } else {  // Otherwise update all displays that do not maintain their own touch mode
                     final int displayCount = mRoot.mChildren.size();
                     for (int i = 0; i < displayCount; ++i) {
                         DisplayContent dc = mRoot.mChildren.get(i);
-                        if (dc.isInTouchMode() == inTouch) {
+                        if (dc.isInTouchMode() == inTouch || dc.hasOwnFocus()) {
                             continue;
                         }
                         if (mInputManager.setInTouchMode(inTouch, pid, uid, hasPermission,
@@ -8929,14 +8940,14 @@
     }
 
     @Override
-    public List<DisplayInfo> getPossibleDisplayInfo(int displayId, String packageName) {
+    public List<DisplayInfo> getPossibleDisplayInfo(int displayId) {
         final int callingUid = Binder.getCallingUid();
         final long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mGlobalLock) {
-                if (packageName == null || !isRecentsComponent(packageName, callingUid)) {
-                    Slog.e(TAG, "Unable to verify uid for package " + packageName
-                            + " for getPossibleMaximumWindowMetrics");
+                if (!mAtmService.isCallerRecents(callingUid)) {
+                    Slog.e(TAG, "Unable to verify uid for getPossibleDisplayInfo"
+                            + " on uid " + callingUid);
                     return new ArrayList<>();
                 }
 
@@ -8954,31 +8965,6 @@
         return mPossibleDisplayInfoMapper.getPossibleDisplayInfos(displayId);
     }
 
-    /**
-     * Returns {@code true} when the calling package is the recents component.
-     */
-    boolean isRecentsComponent(@NonNull String callingPackageName, int callingUid) {
-        String recentsPackage;
-        try {
-            String recentsComponent = mContext.getResources().getString(
-                    R.string.config_recentsComponentName);
-            if (recentsComponent == null) {
-                return false;
-            }
-            recentsPackage = ComponentName.unflattenFromString(recentsComponent).getPackageName();
-        } catch (Resources.NotFoundException e) {
-            Slog.e(TAG, "Unable to verify if recents component", e);
-            return false;
-        }
-        try {
-            return callingUid == mContext.getPackageManager().getPackageUid(callingPackageName, 0)
-                    && callingPackageName.equals(recentsPackage);
-        } catch (PackageManager.NameNotFoundException e) {
-            Slog.e(TAG, "Unable to verify if recents component", e);
-            return false;
-        }
-    }
-
     void grantEmbeddedWindowFocus(Session session, IBinder focusToken, boolean grantFocus) {
         synchronized (mGlobalLock) {
             final EmbeddedWindowController.EmbeddedWindow embeddedWindow =
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4c35178..738adc3 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -43,6 +43,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT;
+import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT;
 
@@ -306,7 +307,7 @@
                                         nextTransition.setAllReady();
                                     }
                                 });
-                        return nextTransition;
+                        return nextTransition.getToken();
                     }
                     transition = mTransitionController.createTransition(type);
                 }
@@ -315,7 +316,7 @@
                 if (needsSetReady) {
                     transition.setAllReady();
                 }
-                return transition;
+                return transition.getToken();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -1233,7 +1234,7 @@
                 WindowContainer.fromBinder(hop.getContainer())
                         .removeLocalInsetsSourceProvider(hop.getInsetsTypes());
                 break;
-            case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP:
+            case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: {
                 final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
                 if (container == null || container.asDisplayArea() == null
                         || !container.isAttached()) {
@@ -1244,7 +1245,26 @@
                 container.setAlwaysOnTop(hop.isAlwaysOnTop());
                 effects |= TRANSACT_EFFECTS_LIFECYCLE;
                 break;
-
+            }
+            case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: {
+                final WindowContainer container = WindowContainer.fromBinder(hop.getContainer());
+                final Task task = container != null ? container.asTask() : null;
+                if (task == null || !task.isAttached()) {
+                    Slog.e(TAG, "Attempt to operate on unknown or detached container: "
+                            + container);
+                    break;
+                }
+                if (!task.mCreatedByOrganizer) {
+                    throw new UnsupportedOperationException(
+                            "Cannot set reparent leaf task flag on non-organized task : " + task);
+                }
+                if (!task.isRootTask()) {
+                    throw new UnsupportedOperationException(
+                            "Cannot set reparent leaf task flag on non-root task : " + task);
+                }
+                task.setReparentLeafTaskIfRelaunch(hop.isReparentLeafTaskIfRelaunch());
+                break;
+            }
         }
         return effects;
     }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 19409b1..73759d3 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4927,7 +4927,8 @@
         // animation on the keyguard but seeing the IME window that originally on the app
         // which behinds the keyguard.
         final WindowState imeInputTarget = getImeInputTarget();
-        if (imeInputTarget != null && !(imeInputTarget.isDrawn() || imeInputTarget.isVisible())) {
+        if (imeInputTarget != null
+                && !(imeInputTarget.isDrawn() || imeInputTarget.isVisibleRequested())) {
             return false;
         }
         return mDisplayContent.forAllImeWindows(callback, traverseTopToBottom);
diff --git a/services/core/java/com/android/server/wm/utils/StateMachine.java b/services/core/java/com/android/server/wm/utils/StateMachine.java
new file mode 100644
index 0000000..91a5dc4
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/StateMachine.java
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import android.annotation.IntRange;
+import android.annotation.Nullable;
+import android.util.IntArray;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.util.AnnotationValidations;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Simple hierarchical state machine.
+ *
+ * The state is represented by an integer value. The root state has a value {@code 0x0}, and top
+ * level state has a value in range {@code 0x1} to {@code 0xF}. To indicate a state B is a sub state
+ * of a state A, assign an integer state_value(B) = state_value(A) << 4 + (0x0 .. 0xF).
+ */
+public class StateMachine {
+    private static final String TAG = "StateMachine";
+
+    /**
+     * Interface for implementing state specific actions.
+     */
+    public interface Handler {
+        /**
+         * Called when state machine changes its state to this state.
+         */
+        default void enter() {}
+
+        /**
+         * Called when state machine changes its state from this state to other state.
+         */
+        default void exit() {}
+
+        /**
+         * @param event type of this event.
+         * @param param parameter passed to {@link StateMachine#handle(int, Object)}
+         * @return {@code true} if the event was handled in this handler, so we don't need to
+         *          check the parent state. Otherwise, handle() of the parent state is triggered.
+         */
+        default boolean handle(int event, @Nullable Object param) {
+            return false;
+        }
+    }
+
+    /**
+     * The most recent state requested by transit() call.
+     *
+     * @note When transit() is called recursively, this might not be same value as mState until
+     *       transit() finishes.
+     */
+    private int mLastRequestedState;
+
+    /**
+     * The current state of this state machine.
+     */
+    private int mState;
+
+    private final IntArray mTmp = new IntArray();
+    private final SparseArray<Handler> mStateHandlers = new SparseArray<>();
+
+    /**
+     * Actions which need to execute to finish requested transition.
+     */
+    private final Queue<Command> mCommands = new ArrayDeque<>();
+
+    protected static class Command {
+        static final int COMMIT = 1;
+        static final int ENTER = 2;
+        static final int EXIT = 3;
+
+        final int mType;
+        final int mState;
+
+        private Command(int type, @IntRange(from = 0) int state) {
+            mType = type;
+            AnnotationValidations.validate(IntRange.class, null, state, "from", 0);
+            mState = state;
+        }
+
+        static Command newCommit(int state) {
+            return new Command(COMMIT, state);
+        }
+
+        static Command newEnter(int state) {
+            return new Command(ENTER, state);
+        }
+
+        static Command newExit(int state) {
+            return new Command(EXIT, state);
+        }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("Command{ type: ");
+            switch (mType) {
+                case COMMIT:
+                    sb.append("commit");
+                    break;
+                case ENTER:
+                    sb.append("enter");
+                    break;
+                case EXIT:
+                    sb.append("exit");
+                    break;
+                default:
+                    sb.append("UNKNOWN(");
+                    sb.append(mType);
+                    sb.append(")");
+                    break;
+            }
+            sb.append(" state: ");
+            sb.append(Integer.toHexString(mState));
+            sb.append(" }");
+            return sb.toString();
+        }
+    }
+
+    public StateMachine() {
+        this(0);
+    }
+
+    public StateMachine(@IntRange(from = 0) int initialState) {
+        mState = initialState;
+        AnnotationValidations.validate(IntRange.class, null, initialState, "from", 0);
+        mLastRequestedState = initialState;
+    }
+
+    /**
+     * @see #mLastRequestedState
+     */
+    public int getState() {
+        return mLastRequestedState;
+    }
+
+    protected int getCurrentState() {
+        return mState;
+    }
+
+    protected Command[] getCommands() {
+        final Command[] commands = new Command[mCommands.size()];
+        mCommands.toArray(commands);
+        return commands;
+    }
+
+    /**
+     * Add a handler for a specific state.
+     *
+     * @param state State which the given handler processes.
+     * @param handler A handler which runs entry, exit actions and processes events.
+     * @return Previous state handler if it's already registered, or {@code null}.
+     */
+    @Nullable public Handler addStateHandler(int state, @Nullable Handler handler) {
+        final Handler handlerOld = mStateHandlers.get(state);
+        mStateHandlers.put(state, handler);
+        return handlerOld;
+    }
+
+    /**
+     * Process an event. Search handler for a given event and {@link Handler#handle(int)}. If the
+     * handler cannot handle the event, delegate it to a handler for a parent of the given state.
+     *
+     * @param event Type of an event.
+     */
+    public void handle(int event, @Nullable Object param) {
+        int state = mState;
+        while (state != 0) {
+            final Handler h = mStateHandlers.get(state);
+            if (h != null && h.handle(event, param)) {
+                return;
+            }
+            state >>= 4;
+        }
+    }
+
+    protected void enter(@IntRange(from = 0) int state) {
+        AnnotationValidations.validate(IntRange.class, null, state, "from", 0);
+        final Handler h = mStateHandlers.get(state);
+        if (h != null) {
+            h.enter();
+        }
+    }
+
+    protected void exit(@IntRange(from = 0) int state) {
+        AnnotationValidations.validate(IntRange.class, null, state, "from", 0);
+        final Handler h = mStateHandlers.get(state);
+        if (h != null) {
+            h.exit();
+        }
+    }
+
+    /**
+     * @return {@code true} if a given sub state is a descendant of a given super state.
+     */
+    public static boolean isIn(int subState, int superState) {
+        while (subState > superState) {
+            subState >>= 4;
+        }
+        return subState == superState;
+    }
+
+    /**
+     * Check if the last requested state is a sub state of a given state.
+     *
+     * @return {@code true} if the last requested state (via {@link #transit(int)}) is a sub state
+     *         of a given state.
+     */
+    public boolean isIn(int state) {
+        return isIn(mLastRequestedState, state);
+    }
+
+    /**
+     * Change state to the requested state.
+     *
+     * @param newState The new state that the state machine should be changed.
+     */
+    public void transit(@IntRange(from = 0) int newState) {
+        AnnotationValidations.validate(IntRange.class, null, newState, "from", 0);
+
+        // entry and exit action might start another transition, so this transit() function can be
+        // called recursively. In order to guarantee entry and exit actions in expected order,
+        // we first compute the sequence and push them into a queue, then process them later.
+        mCommands.add(Command.newCommit(newState));
+        if (mLastRequestedState == newState) {
+            mCommands.add(Command.newExit(newState));
+            mCommands.add(Command.newEnter(newState));
+        } else {
+            // mLastRequestedState to least common ancestor
+            for (int s = mLastRequestedState; !isIn(newState, s); s >>= 4) {
+                mCommands.add(Command.newExit(s));
+            }
+            // least common ancestor to newState
+            mTmp.clear();
+            for (int s = newState; !isIn(mLastRequestedState, s); s >>= 4) {
+                mTmp.add(s);
+            }
+            for (int i = mTmp.size() - 1; i >= 0; --i) {
+                mCommands.add(Command.newEnter(mTmp.get(i)));
+            }
+        }
+        mLastRequestedState = newState;
+        while (!mCommands.isEmpty()) {
+            final Command cmd = mCommands.remove();
+            switch (cmd.mType) {
+                case Command.EXIT:
+                    exit(cmd.mState);
+                    break;
+                case Command.ENTER:
+                    enter(cmd.mState);
+                    break;
+                case Command.COMMIT:
+                    mState = cmd.mState;
+                    break;
+                default:
+                    Slog.e(TAG, "Unknown command type: " + cmd.mType);
+                    break;
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/utils/TEST_MAPPING b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
new file mode 100644
index 0000000..aa69d2a
--- /dev/null
+++ b/services/core/java/com/android/server/wm/utils/TEST_MAPPING
@@ -0,0 +1,18 @@
+{
+  "presubmit": [
+    {
+      "name": "WmTests",
+      "options": [
+        {
+          "include-filter": "com.android.server.wm.utils"
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
+    }
+  ]
+}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index f431250..e661688 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -31,6 +31,9 @@
         "BroadcastRadio/convert.cpp",
         "BroadcastRadio/regions.cpp",
         "stats/SurfaceFlingerPuller.cpp",
+        "tvinput/BufferProducerThread.cpp",
+        "tvinput/JTvInputHal.cpp",
+        "tvinput/TvInputHal_hidl.cpp",
         "com_android_server_adb_AdbDebuggingManager.cpp",
         "com_android_server_am_BatteryStatsService.cpp",
         "com_android_server_biometrics_SurfaceToNativeHandleConverter.cpp",
@@ -150,6 +153,7 @@
         "libdataloader",
         "libincfs",
         "android.hardware.audio.common@2.0",
+        "android.media.audio.common.types-V1-ndk",
         "android.hardware.broadcastradio@1.0",
         "android.hardware.broadcastradio@1.1",
         "android.hardware.contexthub@1.0",
@@ -176,6 +180,7 @@
         "android.hardware.power.stats-V1-ndk",
         "android.hardware.thermal@1.0",
         "android.hardware.tv.input@1.0",
+        "android.hardware.tv.input-V1-ndk",
         "android.hardware.vibrator-V2-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
@@ -197,6 +202,7 @@
 
     static_libs: [
         "android.hardware.broadcastradio@common-utils-1x-lib",
+        "libaidlcommonsupport",
     ],
 
     product_variables: {
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 5d0551b..969056e 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -310,7 +310,7 @@
             const InputDeviceIdentifier& identifier) override;
     std::string getDeviceAlias(const InputDeviceIdentifier& identifier) override;
     TouchAffineTransformation getTouchAffineTransformation(const std::string& inputDeviceDescriptor,
-                                                           int32_t surfaceRotation) override;
+                                                           ui::Rotation surfaceRotation) override;
 
     TouchAffineTransformation getTouchAffineTransformation(JNIEnv* env, jfloatArray matrixArr);
     void notifyStylusGestureStarted(int32_t deviceId, nsecs_t eventTime) override;
@@ -1153,7 +1153,7 @@
 }
 
 TouchAffineTransformation NativeInputManager::getTouchAffineTransformation(
-        const std::string& inputDeviceDescriptor, int32_t surfaceRotation) {
+        const std::string& inputDeviceDescriptor, ui::Rotation surfaceRotation) {
     JNIEnv* env = jniEnv();
 
     ScopedLocalRef<jstring> descriptorObj(env, env->NewStringUTF(inputDeviceDescriptor.c_str()));
diff --git a/services/core/jni/com_android_server_sensor_SensorService.cpp b/services/core/jni/com_android_server_sensor_SensorService.cpp
index 63b7dfb..10d8b42 100644
--- a/services/core/jni/com_android_server_sensor_SensorService.cpp
+++ b/services/core/jni/com_android_server_sensor_SensorService.cpp
@@ -22,6 +22,7 @@
 #include <cutils/properties.h>
 #include <jni.h>
 #include <sensorservice/SensorService.h>
+#include <string.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
 
@@ -30,10 +31,14 @@
 #define PROXIMITY_ACTIVE_CLASS \
     "com/android/server/sensors/SensorManagerInternal$ProximityActiveListener"
 
+#define RUNTIME_SENSOR_CALLBACK_CLASS \
+    "com/android/server/sensors/SensorManagerInternal$RuntimeSensorStateChangeCallback"
+
 namespace android {
 
 static JavaVM* sJvm = nullptr;
 static jmethodID sMethodIdOnProximityActive;
+static jmethodID sMethodIdOnStateChanged;
 
 class NativeSensorService {
 public:
@@ -41,6 +46,11 @@
 
     void registerProximityActiveListener();
     void unregisterProximityActiveListener();
+    jint registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name, jstring vendor,
+                               jobject callback);
+    void unregisterRuntimeSensor(jint handle);
+    jboolean sendRuntimeSensorEvent(JNIEnv* env, jint handle, jint type, jlong timestamp,
+                                    jfloatArray values);
 
 private:
     sp<SensorService> mService;
@@ -56,6 +66,18 @@
         jobject mListener;
     };
     sp<ProximityActiveListenerDelegate> mProximityActiveListenerDelegate;
+
+    class RuntimeSensorCallbackDelegate : public SensorService::RuntimeSensorStateChangeCallback {
+    public:
+        RuntimeSensorCallbackDelegate(JNIEnv* env, jobject callback);
+        ~RuntimeSensorCallbackDelegate();
+
+        void onStateChanged(bool enabled, int64_t samplingPeriodNs,
+                            int64_t batchReportLatencyNs) override;
+
+    private:
+        jobject mCallback;
+    };
 };
 
 NativeSensorService::NativeSensorService(JNIEnv* env, jobject listener)
@@ -85,6 +107,109 @@
     mService->removeProximityActiveListener(mProximityActiveListenerDelegate);
 }
 
+jint NativeSensorService::registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name,
+                                                jstring vendor, jobject callback) {
+    if (mService == nullptr) {
+        ALOGD("Dropping registerRuntimeSensor, sensor service not available.");
+        return -1;
+    }
+
+    sensor_t sensor{
+            .name = env->GetStringUTFChars(name, 0),
+            .vendor = env->GetStringUTFChars(vendor, 0),
+            .version = sizeof(sensor_t),
+            .type = type,
+    };
+
+    sp<RuntimeSensorCallbackDelegate> callbackDelegate(
+            new RuntimeSensorCallbackDelegate(env, callback));
+    return mService->registerRuntimeSensor(sensor, deviceId, callbackDelegate);
+}
+
+void NativeSensorService::unregisterRuntimeSensor(jint handle) {
+    if (mService == nullptr) {
+        ALOGD("Dropping unregisterProximityActiveListener, sensor service not available.");
+        return;
+    }
+
+    mService->unregisterRuntimeSensor(handle);
+}
+
+jboolean NativeSensorService::sendRuntimeSensorEvent(JNIEnv* env, jint handle, jint type,
+                                                     jlong timestamp, jfloatArray values) {
+    if (mService == nullptr) {
+        ALOGD("Dropping sendRuntimeSensorEvent, sensor service not available.");
+        return false;
+    }
+    if (values == nullptr) {
+        ALOGD("Dropping sendRuntimeSensorEvent, no values.");
+        return false;
+    }
+
+    sensors_event_t event{
+            .version = sizeof(sensors_event_t),
+            .timestamp = timestamp,
+            .sensor = handle,
+            .type = type,
+    };
+
+    int valuesLength = env->GetArrayLength(values);
+    jfloat* sensorValues = env->GetFloatArrayElements(values, nullptr);
+
+    switch (type) {
+        case SENSOR_TYPE_ACCELEROMETER:
+        case SENSOR_TYPE_MAGNETIC_FIELD:
+        case SENSOR_TYPE_ORIENTATION:
+        case SENSOR_TYPE_GYROSCOPE:
+        case SENSOR_TYPE_GRAVITY:
+        case SENSOR_TYPE_LINEAR_ACCELERATION: {
+            if (valuesLength != 3) {
+                ALOGD("Dropping sendRuntimeSensorEvent, wrong number of values.");
+                return false;
+            }
+            event.acceleration.x = sensorValues[0];
+            event.acceleration.y = sensorValues[1];
+            event.acceleration.z = sensorValues[2];
+            break;
+        }
+        case SENSOR_TYPE_DEVICE_ORIENTATION:
+        case SENSOR_TYPE_LIGHT:
+        case SENSOR_TYPE_PRESSURE:
+        case SENSOR_TYPE_TEMPERATURE:
+        case SENSOR_TYPE_PROXIMITY:
+        case SENSOR_TYPE_RELATIVE_HUMIDITY:
+        case SENSOR_TYPE_AMBIENT_TEMPERATURE:
+        case SENSOR_TYPE_SIGNIFICANT_MOTION:
+        case SENSOR_TYPE_STEP_DETECTOR:
+        case SENSOR_TYPE_TILT_DETECTOR:
+        case SENSOR_TYPE_WAKE_GESTURE:
+        case SENSOR_TYPE_GLANCE_GESTURE:
+        case SENSOR_TYPE_PICK_UP_GESTURE:
+        case SENSOR_TYPE_WRIST_TILT_GESTURE:
+        case SENSOR_TYPE_STATIONARY_DETECT:
+        case SENSOR_TYPE_MOTION_DETECT:
+        case SENSOR_TYPE_HEART_BEAT:
+        case SENSOR_TYPE_LOW_LATENCY_OFFBODY_DETECT: {
+            if (valuesLength != 1) {
+                ALOGD("Dropping sendRuntimeSensorEvent, wrong number of values.");
+                return false;
+            }
+            event.data[0] = sensorValues[0];
+            break;
+        }
+        default: {
+            if (valuesLength > 16) {
+                ALOGD("Dropping sendRuntimeSensorEvent, number of values exceeds the maximum.");
+                return false;
+            }
+            memcpy(event.data, sensorValues, valuesLength * sizeof(float));
+        }
+    }
+
+    status_t err = mService->sendRuntimeSensorEvent(event);
+    return err == OK;
+}
+
 NativeSensorService::ProximityActiveListenerDelegate::ProximityActiveListenerDelegate(
         JNIEnv* env, jobject listener)
       : mListener(env->NewGlobalRef(listener)) {}
@@ -98,6 +223,22 @@
     jniEnv->CallVoidMethod(mListener, sMethodIdOnProximityActive, static_cast<jboolean>(isActive));
 }
 
+NativeSensorService::RuntimeSensorCallbackDelegate::RuntimeSensorCallbackDelegate(JNIEnv* env,
+                                                                                  jobject callback)
+      : mCallback(env->NewGlobalRef(callback)) {}
+
+NativeSensorService::RuntimeSensorCallbackDelegate::~RuntimeSensorCallbackDelegate() {
+    AndroidRuntime::getJNIEnv()->DeleteGlobalRef(mCallback);
+}
+
+void NativeSensorService::RuntimeSensorCallbackDelegate::onStateChanged(
+        bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
+    auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
+    jniEnv->CallVoidMethod(mCallback, sMethodIdOnStateChanged, static_cast<jboolean>(enabled),
+                           static_cast<jint>(ns2us(samplingPeriodNs)),
+                           static_cast<jint>(ns2us(batchReportLatencyNs)));
+}
+
 static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
     NativeSensorService* service = new NativeSensorService(env, listener);
     return reinterpret_cast<jlong>(service);
@@ -113,26 +254,46 @@
     service->unregisterProximityActiveListener();
 }
 
-static const JNINativeMethod methods[] = {
-        {
-                "startSensorServiceNative", "(L" PROXIMITY_ACTIVE_CLASS ";)J",
-                reinterpret_cast<void*>(startSensorServiceNative)
-        },
-        {
-                "registerProximityActiveListenerNative", "(J)V",
-                reinterpret_cast<void*>(registerProximityActiveListenerNative)
-        },
-        {
-                "unregisterProximityActiveListenerNative", "(J)V",
-                reinterpret_cast<void*>(unregisterProximityActiveListenerNative)
-         },
+static jint registerRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint deviceId, jint type,
+                                        jstring name, jstring vendor, jobject callback) {
+    auto* service = reinterpret_cast<NativeSensorService*>(ptr);
+    return service->registerRuntimeSensor(env, deviceId, type, name, vendor, callback);
+}
 
+static void unregisterRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint handle) {
+    auto* service = reinterpret_cast<NativeSensorService*>(ptr);
+    service->unregisterRuntimeSensor(handle);
+}
+
+static jboolean sendRuntimeSensorEventNative(JNIEnv* env, jclass, jlong ptr, jint handle, jint type,
+                                             jlong timestamp, jfloatArray values) {
+    auto* service = reinterpret_cast<NativeSensorService*>(ptr);
+    return service->sendRuntimeSensorEvent(env, handle, type, timestamp, values);
+}
+
+static const JNINativeMethod methods[] = {
+        {"startSensorServiceNative", "(L" PROXIMITY_ACTIVE_CLASS ";)J",
+         reinterpret_cast<void*>(startSensorServiceNative)},
+        {"registerProximityActiveListenerNative", "(J)V",
+         reinterpret_cast<void*>(registerProximityActiveListenerNative)},
+        {"unregisterProximityActiveListenerNative", "(J)V",
+         reinterpret_cast<void*>(unregisterProximityActiveListenerNative)},
+        {"registerRuntimeSensorNative",
+         "(JIILjava/lang/String;Ljava/lang/String;L" RUNTIME_SENSOR_CALLBACK_CLASS ";)I",
+         reinterpret_cast<void*>(registerRuntimeSensorNative)},
+        {"unregisterRuntimeSensorNative", "(JI)V",
+         reinterpret_cast<void*>(unregisterRuntimeSensorNative)},
+        {"sendRuntimeSensorEventNative", "(JIIJ[F)Z",
+         reinterpret_cast<void*>(sendRuntimeSensorEventNative)},
 };
 
 int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
     sJvm = vm;
     jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
     sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
+    jclass runtimeSensorCallbackClass = FindClassOrDie(env, RUNTIME_SENSOR_CALLBACK_CLASS);
+    sMethodIdOnStateChanged =
+            GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onStateChanged", "(ZII)V");
     return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
                                     NELEM(methods));
 }
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index a5311f3..a8d2f4e 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -18,577 +18,15 @@
 
 //#define LOG_NDEBUG 0
 
-#include "android_os_MessageQueue.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "android_runtime/android_view_Surface.h"
-#include <nativehelper/JNIHelp.h>
-#include "jni.h"
+#include "tvinput/JTvInputHal.h"
 
-#include <android/hardware/tv/input/1.0/ITvInputCallback.h>
-#include <android/hardware/tv/input/1.0/ITvInput.h>
-#include <android/hardware/tv/input/1.0/types.h>
-#include <gui/Surface.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/Log.h>
-#include <utils/Looper.h>
-#include <utils/NativeHandle.h>
-#include <hardware/tv_input.h>
-
-using ::android::hardware::audio::common::V2_0::AudioDevice;
-using ::android::hardware::tv::input::V1_0::ITvInput;
-using ::android::hardware::tv::input::V1_0::ITvInputCallback;
-using ::android::hardware::tv::input::V1_0::Result;
-using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
-using ::android::hardware::tv::input::V1_0::TvInputEvent;
-using ::android::hardware::tv::input::V1_0::TvInputEventType;
-using ::android::hardware::tv::input::V1_0::TvInputType;
-using ::android::hardware::tv::input::V1_0::TvStreamConfig;
-using ::android::hardware::Return;
-using ::android::hardware::Void;
-using ::android::hardware::hidl_vec;
-using ::android::hardware::hidl_string;
+gTvInputHalClassInfoType gTvInputHalClassInfo;
+gTvStreamConfigClassInfoType gTvStreamConfigClassInfo;
+gTvStreamConfigBuilderClassInfoType gTvStreamConfigBuilderClassInfo;
+gTvInputHardwareInfoBuilderClassInfoType gTvInputHardwareInfoBuilderClassInfo;
 
 namespace android {
 
-static struct {
-    jmethodID deviceAvailable;
-    jmethodID deviceUnavailable;
-    jmethodID streamConfigsChanged;
-    jmethodID firstFrameCaptured;
-} gTvInputHalClassInfo;
-
-static struct {
-    jclass clazz;
-} gTvStreamConfigClassInfo;
-
-static struct {
-    jclass clazz;
-
-    jmethodID constructor;
-    jmethodID streamId;
-    jmethodID type;
-    jmethodID maxWidth;
-    jmethodID maxHeight;
-    jmethodID generation;
-    jmethodID build;
-} gTvStreamConfigBuilderClassInfo;
-
-static struct {
-    jclass clazz;
-
-    jmethodID constructor;
-    jmethodID deviceId;
-    jmethodID type;
-    jmethodID hdmiPortId;
-    jmethodID cableConnectionStatus;
-    jmethodID audioType;
-    jmethodID audioAddress;
-    jmethodID build;
-} gTvInputHardwareInfoBuilderClassInfo;
-
-////////////////////////////////////////////////////////////////////////////////
-
-class BufferProducerThread : public Thread {
-public:
-    BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
-
-    virtual status_t readyToRun();
-
-    void setSurface(const sp<Surface>& surface);
-    void onCaptured(uint32_t seq, bool succeeded);
-    void shutdown();
-
-private:
-    Mutex mLock;
-    Condition mCondition;
-    sp<Surface> mSurface;
-    tv_input_device_t* mDevice;
-    int mDeviceId;
-    tv_stream_t mStream;
-    sp<ANativeWindowBuffer_t> mBuffer;
-    enum {
-        CAPTURING,
-        CAPTURED,
-        RELEASED,
-    } mBufferState;
-    uint32_t mSeq;
-    bool mShutdown;
-
-    virtual bool threadLoop();
-
-    void setSurfaceLocked(const sp<Surface>& surface);
-};
-
-BufferProducerThread::BufferProducerThread(
-        tv_input_device_t* device, int deviceId, const tv_stream_t* stream)
-    : Thread(false),
-      mDevice(device),
-      mDeviceId(deviceId),
-      mBuffer(NULL),
-      mBufferState(RELEASED),
-      mSeq(0u),
-      mShutdown(false) {
-    memcpy(&mStream, stream, sizeof(mStream));
-}
-
-status_t BufferProducerThread::readyToRun() {
-    sp<ANativeWindow> anw(mSurface);
-    status_t err = native_window_set_usage(anw.get(), mStream.buffer_producer.usage);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = native_window_set_buffers_dimensions(
-            anw.get(), mStream.buffer_producer.width, mStream.buffer_producer.height);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = native_window_set_buffers_format(anw.get(), mStream.buffer_producer.format);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    return NO_ERROR;
-}
-
-void BufferProducerThread::setSurface(const sp<Surface>& surface) {
-    Mutex::Autolock autoLock(&mLock);
-    setSurfaceLocked(surface);
-}
-
-void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
-    if (surface == mSurface) {
-        return;
-    }
-
-    if (mBufferState == CAPTURING) {
-        mDevice->cancel_capture(mDevice, mDeviceId, mStream.stream_id, mSeq);
-    }
-    while (mBufferState == CAPTURING) {
-        status_t err = mCondition.waitRelative(mLock, s2ns(1));
-        if (err != NO_ERROR) {
-            ALOGE("error %d while wating for buffer state to change.", err);
-            break;
-        }
-    }
-    mBuffer.clear();
-    mBufferState = RELEASED;
-
-    mSurface = surface;
-    mCondition.broadcast();
-}
-
-void BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) {
-    Mutex::Autolock autoLock(&mLock);
-    if (seq != mSeq) {
-        ALOGW("Incorrect sequence value: expected %u actual %u", mSeq, seq);
-    }
-    if (mBufferState != CAPTURING) {
-        ALOGW("mBufferState != CAPTURING : instead %d", mBufferState);
-    }
-    if (succeeded) {
-        mBufferState = CAPTURED;
-    } else {
-        mBuffer.clear();
-        mBufferState = RELEASED;
-    }
-    mCondition.broadcast();
-}
-
-void BufferProducerThread::shutdown() {
-    Mutex::Autolock autoLock(&mLock);
-    mShutdown = true;
-    setSurfaceLocked(NULL);
-    requestExitAndWait();
-}
-
-bool BufferProducerThread::threadLoop() {
-    Mutex::Autolock autoLock(&mLock);
-
-    status_t err = NO_ERROR;
-    if (mSurface == NULL) {
-        err = mCondition.waitRelative(mLock, s2ns(1));
-        // It's OK to time out here.
-        if (err != NO_ERROR && err != TIMED_OUT) {
-            ALOGE("error %d while wating for non-null surface to be set", err);
-            return false;
-        }
-        return true;
-    }
-    sp<ANativeWindow> anw(mSurface);
-    while (mBufferState == CAPTURING) {
-        err = mCondition.waitRelative(mLock, s2ns(1));
-        if (err != NO_ERROR) {
-            ALOGE("error %d while wating for buffer state to change.", err);
-            return false;
-        }
-    }
-    if (mBufferState == CAPTURED && anw != NULL) {
-        err = anw->queueBuffer(anw.get(), mBuffer.get(), -1);
-        if (err != NO_ERROR) {
-            ALOGE("error %d while queueing buffer to surface", err);
-            return false;
-        }
-        mBuffer.clear();
-        mBufferState = RELEASED;
-    }
-    if (mBuffer == NULL && !mShutdown && anw != NULL) {
-        ANativeWindowBuffer_t* buffer = NULL;
-        err = native_window_dequeue_buffer_and_wait(anw.get(), &buffer);
-        if (err != NO_ERROR) {
-            ALOGE("error %d while dequeueing buffer to surface", err);
-            return false;
-        }
-        mBuffer = buffer;
-        mBufferState = CAPTURING;
-        mDevice->request_capture(mDevice, mDeviceId, mStream.stream_id,
-                                 buffer->handle, ++mSeq);
-    }
-
-    return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-class JTvInputHal {
-public:
-    ~JTvInputHal();
-
-    static JTvInputHal* createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper);
-
-    int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
-    int removeStream(int deviceId, int streamId);
-    const hidl_vec<TvStreamConfig> getStreamConfigs(int deviceId);
-
-    void onDeviceAvailable(const TvInputDeviceInfo& info);
-    void onDeviceUnavailable(int deviceId);
-    void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus);
-    void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
-
-private:
-    // Connection between a surface and a stream.
-    class Connection {
-    public:
-        Connection() {}
-
-        sp<Surface> mSurface;
-        tv_stream_type_t mStreamType;
-
-        // Only valid when mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE
-        sp<NativeHandle> mSourceHandle;
-        // Only valid when mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER
-        sp<BufferProducerThread> mThread;
-    };
-
-    class NotifyHandler : public MessageHandler {
-    public:
-        NotifyHandler(JTvInputHal* hal, const TvInputEvent& event);
-
-        virtual void handleMessage(const Message& message);
-
-    private:
-        TvInputEvent mEvent;
-        JTvInputHal* mHal;
-    };
-
-    class TvInputCallback : public ITvInputCallback {
-    public:
-        explicit TvInputCallback(JTvInputHal* hal);
-        Return<void> notify(const TvInputEvent& event) override;
-    private:
-        JTvInputHal* mHal;
-    };
-
-    JTvInputHal(JNIEnv* env, jobject thiz, sp<ITvInput> tvInput, const sp<Looper>& looper);
-
-    Mutex mLock;
-    Mutex mStreamLock;
-    jweak mThiz;
-    sp<Looper> mLooper;
-
-    KeyedVector<int, KeyedVector<int, Connection> > mConnections;
-
-    sp<ITvInput> mTvInput;
-    sp<ITvInputCallback> mTvInputCallback;
-};
-
-JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, sp<ITvInput> tvInput,
-        const sp<Looper>& looper) {
-    mThiz = env->NewWeakGlobalRef(thiz);
-    mTvInput = tvInput;
-    mLooper = looper;
-    mTvInputCallback = new TvInputCallback(this);
-    mTvInput->setCallback(mTvInputCallback);
-}
-
-JTvInputHal::~JTvInputHal() {
-    mTvInput->setCallback(nullptr);
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->DeleteWeakGlobalRef(mThiz);
-    mThiz = NULL;
-}
-
-JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
-    // TODO(b/31632518)
-    sp<ITvInput> tvInput = ITvInput::getService();
-    if (tvInput == nullptr) {
-        ALOGE("Couldn't get tv.input service.");
-        return nullptr;
-    }
-
-    return new JTvInputHal(env, thiz, tvInput, looper);
-}
-
-int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
-    Mutex::Autolock autoLock(&mStreamLock);
-    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
-    if (connections.indexOfKey(streamId) < 0) {
-        connections.add(streamId, Connection());
-    }
-    Connection& connection = connections.editValueFor(streamId);
-    if (connection.mSurface == surface) {
-        // Nothing to do
-        return NO_ERROR;
-    }
-    // Clear the surface in the connection.
-    if (connection.mSurface != NULL) {
-        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
-            if (Surface::isValid(connection.mSurface)) {
-                connection.mSurface->setSidebandStream(NULL);
-            }
-        }
-        connection.mSurface.clear();
-    }
-    if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
-        // Need to configure stream
-        Result result = Result::UNKNOWN;
-        hidl_vec<TvStreamConfig> list;
-        mTvInput->getStreamConfigurations(deviceId,
-                [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
-                    result = res;
-                    if (res == Result::OK) {
-                        list = configs;
-                    }
-                });
-        if (result != Result::OK) {
-            ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId, result);
-            return UNKNOWN_ERROR;
-        }
-        int configIndex = -1;
-        for (size_t i = 0; i < list.size(); ++i) {
-            if (list[i].streamId == streamId) {
-                configIndex = i;
-                break;
-            }
-        }
-        if (configIndex == -1) {
-            ALOGE("Cannot find a config with given stream ID: %d", streamId);
-            return BAD_VALUE;
-        }
-        connection.mStreamType = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE;
-
-        result = Result::UNKNOWN;
-        const native_handle_t* sidebandStream;
-        mTvInput->openStream(deviceId, streamId,
-                [&result, &sidebandStream](Result res, const native_handle_t* handle) {
-                    result = res;
-                    if (res == Result::OK) {
-                        if (handle) {
-                            sidebandStream = native_handle_clone(handle);
-                        } else {
-                            result = Result::UNKNOWN;
-                        }
-                    }
-                });
-        if (result != Result::OK) {
-            ALOGE("Couldn't open stream. device id:%d stream id:%d result:%d", deviceId, streamId,
-                    result);
-            return UNKNOWN_ERROR;
-        }
-        connection.mSourceHandle = NativeHandle::create((native_handle_t*)sidebandStream, true);
-    }
-    connection.mSurface = surface;
-    if (connection.mSurface != nullptr) {
-        connection.mSurface->setSidebandStream(connection.mSourceHandle);
-    }
-    return NO_ERROR;
-}
-
-int JTvInputHal::removeStream(int deviceId, int streamId) {
-    Mutex::Autolock autoLock(&mStreamLock);
-    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
-    if (connections.indexOfKey(streamId) < 0) {
-        return BAD_VALUE;
-    }
-    Connection& connection = connections.editValueFor(streamId);
-    if (connection.mSurface == NULL) {
-        // Nothing to do
-        return NO_ERROR;
-    }
-    if (Surface::isValid(connection.mSurface)) {
-        connection.mSurface->setSidebandStream(NULL);
-    }
-    connection.mSurface.clear();
-    if (connection.mThread != NULL) {
-        connection.mThread->shutdown();
-        connection.mThread.clear();
-    }
-    if (mTvInput->closeStream(deviceId, streamId) != Result::OK) {
-        ALOGE("Couldn't close stream. device id:%d stream id:%d", deviceId, streamId);
-        return BAD_VALUE;
-    }
-    if (connection.mSourceHandle != NULL) {
-        connection.mSourceHandle.clear();
-    }
-    return NO_ERROR;
-}
-
-const hidl_vec<TvStreamConfig> JTvInputHal::getStreamConfigs(int deviceId) {
-    Result result = Result::UNKNOWN;
-    hidl_vec<TvStreamConfig> list;
-    mTvInput->getStreamConfigurations(deviceId,
-            [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
-                result = res;
-                if (res == Result::OK) {
-                    list = configs;
-                }
-            });
-    if (result != Result::OK) {
-        ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId, result);
-    }
-    return list;
-}
-
-void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfo& info) {
-    {
-        Mutex::Autolock autoLock(&mLock);
-        mConnections.add(info.deviceId, KeyedVector<int, Connection>());
-    }
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-
-    jobject builder = env->NewObject(
-            gTvInputHardwareInfoBuilderClassInfo.clazz,
-            gTvInputHardwareInfoBuilderClassInfo.constructor);
-    env->CallObjectMethod(
-            builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.deviceId);
-    env->CallObjectMethod(
-            builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
-    if (info.type == TvInputType::HDMI) {
-        env->CallObjectMethod(
-                builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.portId);
-    }
-    env->CallObjectMethod(
-            builder, gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus,
-            info.cableConnectionStatus);
-    env->CallObjectMethod(
-            builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audioType);
-    if (info.audioType != AudioDevice::NONE) {
-        uint8_t buffer[info.audioAddress.size() + 1];
-        memcpy(buffer, info.audioAddress.data(), info.audioAddress.size());
-        buffer[info.audioAddress.size()] = '\0';
-        jstring audioAddress = env->NewStringUTF(reinterpret_cast<const char *>(buffer));
-        env->CallObjectMethod(
-                builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress);
-        env->DeleteLocalRef(audioAddress);
-    }
-
-    jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
-
-    env->CallVoidMethod(
-            mThiz,
-            gTvInputHalClassInfo.deviceAvailable,
-            infoObject);
-
-    env->DeleteLocalRef(builder);
-    env->DeleteLocalRef(infoObject);
-}
-
-void JTvInputHal::onDeviceUnavailable(int deviceId) {
-    {
-        Mutex::Autolock autoLock(&mLock);
-        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
-        for (size_t i = 0; i < connections.size(); ++i) {
-            removeStream(deviceId, connections.keyAt(i));
-        }
-        connections.clear();
-        mConnections.removeItem(deviceId);
-    }
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(
-            mThiz,
-            gTvInputHalClassInfo.deviceUnavailable,
-            deviceId);
-}
-
-void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
-    {
-        Mutex::Autolock autoLock(&mLock);
-        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
-        for (size_t i = 0; i < connections.size(); ++i) {
-            removeStream(deviceId, connections.keyAt(i));
-        }
-        connections.clear();
-    }
-    JNIEnv* env = AndroidRuntime::getJNIEnv();
-    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
-                        cableConnectionStatus);
-}
-
-void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
-    sp<BufferProducerThread> thread;
-    {
-        Mutex::Autolock autoLock(&mLock);
-        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
-        Connection& connection = connections.editValueFor(streamId);
-        if (connection.mThread == NULL) {
-            ALOGE("capture thread not existing.");
-            return;
-        }
-        thread = connection.mThread;
-    }
-    thread->onCaptured(seq, succeeded);
-    if (seq == 0) {
-        JNIEnv* env = AndroidRuntime::getJNIEnv();
-        env->CallVoidMethod(
-                mThiz,
-                gTvInputHalClassInfo.firstFrameCaptured,
-                deviceId,
-                streamId);
-    }
-}
-
-JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const TvInputEvent& event) {
-    mHal = hal;
-    mEvent = event;
-}
-
-void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
-    switch (mEvent.type) {
-        case TvInputEventType::DEVICE_AVAILABLE: {
-            mHal->onDeviceAvailable(mEvent.deviceInfo);
-        } break;
-        case TvInputEventType::DEVICE_UNAVAILABLE: {
-            mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
-        } break;
-        case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
-            int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
-            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
-        } break;
-        default:
-            ALOGE("Unrecognizable event");
-    }
-}
-
-JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) {
-    mHal = hal;
-}
-
-Return<void> JTvInputHal::TvInputCallback::notify(const TvInputEvent& event) {
-    mHal->mLooper->sendMessage(new NotifyHandler(mHal, event), static_cast<int>(event.type));
-    return Void();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 static jlong nativeOpen(JNIEnv* env, jobject thiz, jobject messageQueueObj) {
     sp<MessageQueue> messageQueue =
             android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
@@ -617,7 +55,7 @@
 static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
         jlong ptr, jint deviceId, jint generation) {
     JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
-    const hidl_vec<TvStreamConfig> configs = tvInputHal->getStreamConfigs(deviceId);
+    const std::vector<AidlTvStreamConfig> configs = tvInputHal->getStreamConfigs(deviceId);
 
     jobjectArray result = env->NewObjectArray(configs.size(), gTvStreamConfigClassInfo.clazz, NULL);
     for (size_t i = 0; i < configs.size(); ++i) {
diff --git a/services/core/jni/tvinput/BufferProducerThread.cpp b/services/core/jni/tvinput/BufferProducerThread.cpp
new file mode 100644
index 0000000..f39dcee
--- /dev/null
+++ b/services/core/jni/tvinput/BufferProducerThread.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "BufferProducerThread.h"
+
+namespace android {
+
+BufferProducerThread::BufferProducerThread(tv_input_device_t* device, int deviceId,
+                                           const tv_stream_t* stream)
+      : Thread(false),
+        mDevice(device),
+        mDeviceId(deviceId),
+        mBuffer(NULL),
+        mBufferState(RELEASED),
+        mSeq(0u),
+        mShutdown(false) {
+    memcpy(&mStream, stream, sizeof(mStream));
+}
+
+status_t BufferProducerThread::readyToRun() {
+    sp<ANativeWindow> anw(mSurface);
+    status_t err = native_window_set_usage(anw.get(), mStream.buffer_producer.usage);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = native_window_set_buffers_dimensions(anw.get(), mStream.buffer_producer.width,
+                                               mStream.buffer_producer.height);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    err = native_window_set_buffers_format(anw.get(), mStream.buffer_producer.format);
+    if (err != NO_ERROR) {
+        return err;
+    }
+    return NO_ERROR;
+}
+
+void BufferProducerThread::setSurface(const sp<Surface>& surface) {
+    Mutex::Autolock autoLock(&mLock);
+    setSurfaceLocked(surface);
+}
+
+void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) {
+    if (surface == mSurface) {
+        return;
+    }
+
+    if (mBufferState == CAPTURING) {
+        mDevice->cancel_capture(mDevice, mDeviceId, mStream.stream_id, mSeq);
+    }
+    while (mBufferState == CAPTURING) {
+        status_t err = mCondition.waitRelative(mLock, s2ns(1));
+        if (err != NO_ERROR) {
+            ALOGE("error %d while wating for buffer state to change.", err);
+            break;
+        }
+    }
+    mBuffer.clear();
+    mBufferState = RELEASED;
+
+    mSurface = surface;
+    mCondition.broadcast();
+}
+
+void BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) {
+    Mutex::Autolock autoLock(&mLock);
+    if (seq != mSeq) {
+        ALOGW("Incorrect sequence value: expected %u actual %u", mSeq, seq);
+    }
+    if (mBufferState != CAPTURING) {
+        ALOGW("mBufferState != CAPTURING : instead %d", mBufferState);
+    }
+    if (succeeded) {
+        mBufferState = CAPTURED;
+    } else {
+        mBuffer.clear();
+        mBufferState = RELEASED;
+    }
+    mCondition.broadcast();
+}
+
+void BufferProducerThread::shutdown() {
+    Mutex::Autolock autoLock(&mLock);
+    mShutdown = true;
+    setSurfaceLocked(NULL);
+    requestExitAndWait();
+}
+
+bool BufferProducerThread::threadLoop() {
+    Mutex::Autolock autoLock(&mLock);
+
+    status_t err = NO_ERROR;
+    if (mSurface == NULL) {
+        err = mCondition.waitRelative(mLock, s2ns(1));
+        // It's OK to time out here.
+        if (err != NO_ERROR && err != TIMED_OUT) {
+            ALOGE("error %d while wating for non-null surface to be set", err);
+            return false;
+        }
+        return true;
+    }
+    sp<ANativeWindow> anw(mSurface);
+    while (mBufferState == CAPTURING) {
+        err = mCondition.waitRelative(mLock, s2ns(1));
+        if (err != NO_ERROR) {
+            ALOGE("error %d while wating for buffer state to change.", err);
+            return false;
+        }
+    }
+    if (mBufferState == CAPTURED && anw != NULL) {
+        err = anw->queueBuffer(anw.get(), mBuffer.get(), -1);
+        if (err != NO_ERROR) {
+            ALOGE("error %d while queueing buffer to surface", err);
+            return false;
+        }
+        mBuffer.clear();
+        mBufferState = RELEASED;
+    }
+    if (mBuffer == NULL && !mShutdown && anw != NULL) {
+        ANativeWindowBuffer_t* buffer = NULL;
+        err = native_window_dequeue_buffer_and_wait(anw.get(), &buffer);
+        if (err != NO_ERROR) {
+            ALOGE("error %d while dequeueing buffer to surface", err);
+            return false;
+        }
+        mBuffer = buffer;
+        mBufferState = CAPTURING;
+        mDevice->request_capture(mDevice, mDeviceId, mStream.stream_id, buffer->handle, ++mSeq);
+    }
+
+    return true;
+}
+
+} // namespace android
diff --git a/services/core/jni/tvinput/BufferProducerThread.h b/services/core/jni/tvinput/BufferProducerThread.h
new file mode 100644
index 0000000..2e0fa91
--- /dev/null
+++ b/services/core/jni/tvinput/BufferProducerThread.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/Surface.h>
+#include <hardware/tv_input.h>
+#include <utils/Thread.h>
+
+namespace android {
+
+class BufferProducerThread : public Thread {
+public:
+    BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream);
+
+    virtual status_t readyToRun();
+
+    void setSurface(const sp<Surface>& surface);
+    void onCaptured(uint32_t seq, bool succeeded);
+    void shutdown();
+
+private:
+    Mutex mLock;
+    Condition mCondition;
+    sp<Surface> mSurface;
+    tv_input_device_t* mDevice;
+    int mDeviceId;
+    tv_stream_t mStream;
+    sp<ANativeWindowBuffer_t> mBuffer;
+    enum {
+        CAPTURING,
+        CAPTURED,
+        RELEASED,
+    } mBufferState;
+    uint32_t mSeq;
+    bool mShutdown;
+
+    virtual bool threadLoop();
+
+    void setSurfaceLocked(const sp<Surface>& surface);
+};
+
+} // namespace android
diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp
new file mode 100644
index 0000000..0f6ef03
--- /dev/null
+++ b/services/core/jni/tvinput/JTvInputHal.cpp
@@ -0,0 +1,378 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "JTvInputHal.h"
+
+namespace android {
+
+JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, std::shared_ptr<ITvInputWrapper> tvInput,
+                         const sp<Looper>& looper) {
+    mThiz = env->NewWeakGlobalRef(thiz);
+    mTvInput = tvInput;
+    mLooper = looper;
+    mTvInputCallback = ::ndk::SharedRefBase::make<TvInputCallback>(this);
+    mTvInput->setCallback(mTvInputCallback);
+}
+
+JTvInputHal::~JTvInputHal() {
+    mTvInput->setCallback(nullptr);
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->DeleteWeakGlobalRef(mThiz);
+    mThiz = NULL;
+}
+
+JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
+    sp<HidlITvInput> hidlITvInput = HidlITvInput::getService();
+    if (hidlITvInput != nullptr) {
+        ALOGD("tv.input service is HIDL.");
+        return new JTvInputHal(env, thiz,
+                               std::shared_ptr<ITvInputWrapper>(new ITvInputWrapper(hidlITvInput)),
+                               looper);
+    }
+    ::ndk::SpAIBinder binder(AServiceManager_waitForService(TV_INPUT_AIDL_SERVICE_NAME));
+    std::shared_ptr<AidlITvInput> aidlITvInput = AidlITvInput::fromBinder(binder);
+    if (aidlITvInput == nullptr) {
+        ALOGE("Couldn't get tv.input service.");
+        return nullptr;
+    }
+    return new JTvInputHal(env, thiz,
+                           std::shared_ptr<ITvInputWrapper>(new ITvInputWrapper(aidlITvInput)),
+                           looper);
+}
+
+int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
+    Mutex::Autolock autoLock(&mStreamLock);
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    if (connections.indexOfKey(streamId) < 0) {
+        connections.add(streamId, Connection());
+    }
+    Connection& connection = connections.editValueFor(streamId);
+    if (connection.mSurface == surface) {
+        // Nothing to do
+        return NO_ERROR;
+    }
+    // Clear the surface in the connection.
+    if (connection.mSurface != NULL) {
+        if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
+            if (Surface::isValid(connection.mSurface)) {
+                connection.mSurface->setSidebandStream(NULL);
+            }
+        }
+        connection.mSurface.clear();
+    }
+    if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
+        // Need to configure stream
+        ::ndk::ScopedAStatus status;
+        std::vector<AidlTvStreamConfig> list;
+        status = mTvInput->getStreamConfigurations(deviceId, &list);
+        if (!status.isOk()) {
+            ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId,
+                  status.getServiceSpecificError());
+            return UNKNOWN_ERROR;
+        }
+        int configIndex = -1;
+        for (size_t i = 0; i < list.size(); ++i) {
+            if (list[i].streamId == streamId) {
+                configIndex = i;
+                break;
+            }
+        }
+        if (configIndex == -1) {
+            ALOGE("Cannot find a config with given stream ID: %d", streamId);
+            return BAD_VALUE;
+        }
+        connection.mStreamType = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE;
+
+        AidlNativeHandle sidebandStream;
+        status = mTvInput->openStream(deviceId, streamId, &sidebandStream);
+        if (!status.isOk()) {
+            ALOGE("Couldn't open stream. device id:%d stream id:%d result:%d", deviceId, streamId,
+                  status.getServiceSpecificError());
+            return UNKNOWN_ERROR;
+        }
+        connection.mSourceHandle = NativeHandle::create(makeFromAidl(sidebandStream), true);
+    }
+    connection.mSurface = surface;
+    if (connection.mSurface != nullptr) {
+        connection.mSurface->setSidebandStream(connection.mSourceHandle);
+    }
+    return NO_ERROR;
+}
+
+int JTvInputHal::removeStream(int deviceId, int streamId) {
+    Mutex::Autolock autoLock(&mStreamLock);
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    if (connections.indexOfKey(streamId) < 0) {
+        return BAD_VALUE;
+    }
+    Connection& connection = connections.editValueFor(streamId);
+    if (connection.mSurface == NULL) {
+        // Nothing to do
+        return NO_ERROR;
+    }
+    if (Surface::isValid(connection.mSurface)) {
+        connection.mSurface->setSidebandStream(NULL);
+    }
+    connection.mSurface.clear();
+    if (connection.mThread != NULL) {
+        connection.mThread->shutdown();
+        connection.mThread.clear();
+    }
+    if (!mTvInput->closeStream(deviceId, streamId).isOk()) {
+        ALOGE("Couldn't close stream. device id:%d stream id:%d", deviceId, streamId);
+        return BAD_VALUE;
+    }
+    if (connection.mSourceHandle != NULL) {
+        connection.mSourceHandle.clear();
+    }
+    return NO_ERROR;
+}
+
+const std::vector<AidlTvStreamConfig> JTvInputHal::getStreamConfigs(int deviceId) {
+    std::vector<AidlTvStreamConfig> list;
+    ::ndk::ScopedAStatus status = mTvInput->getStreamConfigurations(deviceId, &list);
+    if (!status.isOk()) {
+        ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId,
+              status.getServiceSpecificError());
+        return std::vector<AidlTvStreamConfig>();
+    }
+    return list;
+}
+
+void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfoWrapper& info) {
+    {
+        Mutex::Autolock autoLock(&mLock);
+        mConnections.add(info.deviceId, KeyedVector<int, Connection>());
+    }
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    jobject builder = env->NewObject(gTvInputHardwareInfoBuilderClassInfo.clazz,
+                                     gTvInputHardwareInfoBuilderClassInfo.constructor);
+    env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.deviceId);
+    env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
+    if (info.type == TvInputType::HDMI) {
+        env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId,
+                              info.portId);
+    }
+    env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus,
+                          info.cableConnectionStatus);
+    if (info.isHidl) {
+        hidlSetUpAudioInfo(env, builder, info);
+    } else {
+        AidlAudioDeviceType audioType = info.aidlAudioDevice.type.type;
+        env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType, audioType);
+        if (audioType != AidlAudioDeviceType::NONE) {
+            std::stringstream ss;
+            switch (info.aidlAudioDevice.address.getTag()) {
+                case AidlAudioDeviceAddress::id:
+                    ss << info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::id>();
+                    break;
+                case AidlAudioDeviceAddress::mac: {
+                    std::vector<uint8_t> addrList =
+                            info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::mac>();
+                    for (int i = 0; i < addrList.size(); i++) {
+                        if (i != 0) {
+                            ss << ':';
+                        }
+                        ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex
+                           << static_cast<int32_t>(addrList[i]);
+                    }
+                } break;
+                case AidlAudioDeviceAddress::ipv4: {
+                    std::vector<uint8_t> addrList =
+                            info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv4>();
+                    for (int i = 0; i < addrList.size(); i++) {
+                        if (i != 0) {
+                            ss << '.';
+                        }
+                        ss << static_cast<int32_t>(addrList[i]);
+                    }
+                } break;
+                case AidlAudioDeviceAddress::ipv6: {
+                    std::vector<int32_t> addrList =
+                            info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv6>();
+                    for (int i = 0; i < addrList.size(); i++) {
+                        if (i != 0) {
+                            ss << ':';
+                        }
+                        ss << std::uppercase << std::setfill('0') << std::setw(4) << std::hex
+                           << addrList[i];
+                    }
+                } break;
+                case AidlAudioDeviceAddress::alsa: {
+                    std::vector<int32_t> addrList =
+                            info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::alsa>();
+                    ss << "card=" << addrList[0] << ";device=" << addrList[1];
+                } break;
+            }
+            std::string bufferStr = ss.str();
+            jstring audioAddress = env->NewStringUTF(bufferStr.c_str());
+            env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress,
+                                  audioAddress);
+            env->DeleteLocalRef(audioAddress);
+        }
+    }
+
+    jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
+
+    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceAvailable, infoObject);
+
+    env->DeleteLocalRef(builder);
+    env->DeleteLocalRef(infoObject);
+}
+
+void JTvInputHal::onDeviceUnavailable(int deviceId) {
+    {
+        Mutex::Autolock autoLock(&mLock);
+        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+        for (size_t i = 0; i < connections.size(); ++i) {
+            removeStream(deviceId, connections.keyAt(i));
+        }
+        connections.clear();
+        mConnections.removeItem(deviceId);
+    }
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceUnavailable, deviceId);
+}
+
+void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
+    {
+        Mutex::Autolock autoLock(&mLock);
+        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+        for (size_t i = 0; i < connections.size(); ++i) {
+            removeStream(deviceId, connections.keyAt(i));
+        }
+        connections.clear();
+    }
+    JNIEnv* env = AndroidRuntime::getJNIEnv();
+    env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
+                        cableConnectionStatus);
+}
+
+void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
+    sp<BufferProducerThread> thread;
+    {
+        Mutex::Autolock autoLock(&mLock);
+        KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+        Connection& connection = connections.editValueFor(streamId);
+        if (connection.mThread == NULL) {
+            ALOGE("capture thread not existing.");
+            return;
+        }
+        thread = connection.mThread;
+    }
+    thread->onCaptured(seq, succeeded);
+    if (seq == 0) {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->CallVoidMethod(mThiz, gTvInputHalClassInfo.firstFrameCaptured, deviceId, streamId);
+    }
+}
+
+JTvInputHal::TvInputDeviceInfoWrapper
+JTvInputHal::TvInputDeviceInfoWrapper::createDeviceInfoWrapper(
+        const AidlTvInputDeviceInfo& aidlTvInputDeviceInfo) {
+    TvInputDeviceInfoWrapper deviceInfo;
+    deviceInfo.isHidl = false;
+    deviceInfo.deviceId = aidlTvInputDeviceInfo.deviceId;
+    deviceInfo.type = aidlTvInputDeviceInfo.type;
+    deviceInfo.portId = aidlTvInputDeviceInfo.portId;
+    deviceInfo.cableConnectionStatus = aidlTvInputDeviceInfo.cableConnectionStatus;
+    deviceInfo.aidlAudioDevice = aidlTvInputDeviceInfo.audioDevice;
+    return deviceInfo;
+}
+
+JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWrapper(
+        const AidlTvInputEvent& aidlTvInputEvent) {
+    TvInputEventWrapper event;
+    event.type = aidlTvInputEvent.type;
+    event.deviceInfo =
+            TvInputDeviceInfoWrapper::createDeviceInfoWrapper(aidlTvInputEvent.deviceInfo);
+    return event;
+}
+
+JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event) {
+    mHal = hal;
+    mEvent = event;
+}
+
+void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
+    switch (mEvent.type) {
+        case TvInputEventType::DEVICE_AVAILABLE: {
+            mHal->onDeviceAvailable(mEvent.deviceInfo);
+        } break;
+        case TvInputEventType::DEVICE_UNAVAILABLE: {
+            mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
+        } break;
+        case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
+            int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
+            mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
+        } break;
+        default:
+            ALOGE("Unrecognizable event");
+    }
+}
+
+JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) {
+    mHal = hal;
+}
+
+::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notify(const AidlTvInputEvent& event) {
+    mHal->mLooper->sendMessage(new NotifyHandler(mHal,
+                                                 TvInputEventWrapper::createEventWrapper(event)),
+                               static_cast<int>(event.type));
+    return ::ndk::ScopedAStatus::ok();
+}
+
+JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput)
+      : mIsHidl(false), mAidlTvInput(aidlTvInput) {}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setCallback(
+        const std::shared_ptr<TvInputCallback>& in_callback) {
+    if (mIsHidl) {
+        return hidlSetCallback(in_callback);
+    } else {
+        return mAidlTvInput->setCallback(in_callback);
+    }
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getStreamConfigurations(
+        int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return) {
+    if (mIsHidl) {
+        return hidlGetStreamConfigurations(in_deviceId, _aidl_return);
+    } else {
+        return mAidlTvInput->getStreamConfigurations(in_deviceId, _aidl_return);
+    }
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::openStream(int32_t in_deviceId,
+                                                              int32_t in_streamId,
+                                                              AidlNativeHandle* _aidl_return) {
+    if (mIsHidl) {
+        return hidlOpenStream(in_deviceId, in_streamId, _aidl_return);
+    } else {
+        return mAidlTvInput->openStream(in_deviceId, in_streamId, _aidl_return);
+    }
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::closeStream(int32_t in_deviceId,
+                                                               int32_t in_streamId) {
+    if (mIsHidl) {
+        return hidlCloseStream(in_deviceId, in_streamId);
+    } else {
+        return mAidlTvInput->closeStream(in_deviceId, in_streamId);
+    }
+}
+
+} // namespace android
diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h
new file mode 100644
index 0000000..2697294
--- /dev/null
+++ b/services/core/jni/tvinput/JTvInputHal.h
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+#define TV_INPUT_AIDL_SERVICE_NAME "android.hardware.tv.input.ITvInput/default"
+
+#include <aidl/android/hardware/tv/input/BnTvInputCallback.h>
+#include <aidl/android/hardware/tv/input/CableConnectionStatus.h>
+#include <aidl/android/hardware/tv/input/ITvInput.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <android/binder_manager.h>
+#include <nativehelper/JNIHelp.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/NativeHandle.h>
+
+#include <iomanip>
+
+#include "BufferProducerThread.h"
+#include "TvInputHal_hidl.h"
+#include "android_os_MessageQueue.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "android_runtime/android_view_Surface.h"
+#include "tvinput/jstruct.h"
+
+using ::aidl::android::hardware::tv::input::BnTvInputCallback;
+using ::aidl::android::hardware::tv::input::CableConnectionStatus;
+using ::aidl::android::hardware::tv::input::TvInputEventType;
+using ::aidl::android::hardware::tv::input::TvInputType;
+
+using AidlAudioDevice = ::aidl::android::media::audio::common::AudioDevice;
+using AidlAudioDeviceAddress = ::aidl::android::media::audio::common::AudioDeviceAddress;
+using AidlAudioDeviceType = ::aidl::android::media::audio::common::AudioDeviceType;
+using AidlITvInput = ::aidl::android::hardware::tv::input::ITvInput;
+using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle;
+using AidlTvInputDeviceInfo = ::aidl::android::hardware::tv::input::TvInputDeviceInfo;
+using AidlTvInputEvent = ::aidl::android::hardware::tv::input::TvInputEvent;
+using AidlTvStreamConfig = ::aidl::android::hardware::tv::input::TvStreamConfig;
+
+extern gTvInputHalClassInfoType gTvInputHalClassInfo;
+extern gTvStreamConfigClassInfoType gTvStreamConfigClassInfo;
+extern gTvStreamConfigBuilderClassInfoType gTvStreamConfigBuilderClassInfo;
+extern gTvInputHardwareInfoBuilderClassInfoType gTvInputHardwareInfoBuilderClassInfo;
+
+namespace android {
+
+class JTvInputHal {
+public:
+    ~JTvInputHal();
+
+    static JTvInputHal* createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper);
+
+    int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface);
+    int removeStream(int deviceId, int streamId);
+    const std::vector<AidlTvStreamConfig> getStreamConfigs(int deviceId);
+
+private:
+    // Connection between a surface and a stream.
+    class Connection {
+    public:
+        Connection() {}
+
+        sp<Surface> mSurface;
+        tv_stream_type_t mStreamType;
+
+        // Only valid when mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE
+        sp<NativeHandle> mSourceHandle;
+        // Only valid when mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER
+        sp<BufferProducerThread> mThread;
+    };
+
+    class TvInputDeviceInfoWrapper {
+    public:
+        TvInputDeviceInfoWrapper() {}
+
+        static TvInputDeviceInfoWrapper createDeviceInfoWrapper(
+                const AidlTvInputDeviceInfo& aidlTvInputDeviceInfo);
+        static TvInputDeviceInfoWrapper createDeviceInfoWrapper(
+                const HidlTvInputDeviceInfo& hidlTvInputDeviceInfo);
+
+        bool isHidl;
+        int deviceId;
+        TvInputType type;
+        int portId;
+        CableConnectionStatus cableConnectionStatus;
+        AidlAudioDevice aidlAudioDevice;
+        HidlAudioDevice hidlAudioType;
+        ::android::hardware::hidl_array<uint8_t, 32> hidlAudioAddress;
+    };
+
+    class TvInputEventWrapper {
+    public:
+        TvInputEventWrapper() {}
+
+        static TvInputEventWrapper createEventWrapper(const AidlTvInputEvent& aidlTvInputEvent);
+        static TvInputEventWrapper createEventWrapper(const HidlTvInputEvent& hidlTvInputEvent);
+
+        TvInputEventType type;
+        TvInputDeviceInfoWrapper deviceInfo;
+    };
+
+    class NotifyHandler : public MessageHandler {
+    public:
+        NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event);
+
+        void handleMessage(const Message& message) override;
+
+    private:
+        TvInputEventWrapper mEvent;
+        JTvInputHal* mHal;
+    };
+
+    class TvInputCallback : public HidlITvInputCallback, public BnTvInputCallback {
+    public:
+        explicit TvInputCallback(JTvInputHal* hal);
+        ::ndk::ScopedAStatus notify(const AidlTvInputEvent& event) override;
+        Return<void> notify(const HidlTvInputEvent& event) override;
+
+    private:
+        JTvInputHal* mHal;
+    };
+
+    class ITvInputWrapper {
+    public:
+        ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput);
+        ITvInputWrapper(sp<HidlITvInput>& hidlTvInput);
+
+        ::ndk::ScopedAStatus setCallback(const std::shared_ptr<TvInputCallback>& in_callback);
+        ::ndk::ScopedAStatus getStreamConfigurations(int32_t in_deviceId,
+                                                     std::vector<AidlTvStreamConfig>* _aidl_return);
+        ::ndk::ScopedAStatus openStream(int32_t in_deviceId, int32_t in_streamId,
+                                        AidlNativeHandle* _aidl_return);
+        ::ndk::ScopedAStatus closeStream(int32_t in_deviceId, int32_t in_streamId);
+
+    private:
+        ::ndk::ScopedAStatus hidlSetCallback(const std::shared_ptr<TvInputCallback>& in_callback);
+        ::ndk::ScopedAStatus hidlGetStreamConfigurations(
+                int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return);
+        ::ndk::ScopedAStatus hidlOpenStream(int32_t in_deviceId, int32_t in_streamId,
+                                            AidlNativeHandle* _aidl_return);
+        ::ndk::ScopedAStatus hidlCloseStream(int32_t in_deviceId, int32_t in_streamId);
+
+        bool mIsHidl;
+        sp<HidlITvInput> mHidlTvInput;
+        std::shared_ptr<AidlITvInput> mAidlTvInput;
+    };
+
+    JTvInputHal(JNIEnv* env, jobject thiz, std::shared_ptr<ITvInputWrapper> tvInput,
+                const sp<Looper>& looper);
+
+    void hidlSetUpAudioInfo(JNIEnv* env, jobject& builder, const TvInputDeviceInfoWrapper& info);
+    void onDeviceAvailable(const TvInputDeviceInfoWrapper& info);
+    void onDeviceUnavailable(int deviceId);
+    void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus);
+    void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded);
+
+    Mutex mLock;
+    Mutex mStreamLock;
+    jweak mThiz;
+    sp<Looper> mLooper;
+
+    KeyedVector<int, KeyedVector<int, Connection> > mConnections;
+
+    std::shared_ptr<ITvInputWrapper> mTvInput;
+    std::shared_ptr<TvInputCallback> mTvInputCallback;
+};
+
+} // namespace android
diff --git a/services/core/jni/tvinput/OWNERS b/services/core/jni/tvinput/OWNERS
new file mode 100644
index 0000000..adc5827
--- /dev/null
+++ b/services/core/jni/tvinput/OWNERS
@@ -0,0 +1,3 @@
+include /media/java/android/media/tv/OWNERS
+
+yixiaoluo@google.com
diff --git a/services/core/jni/tvinput/TvInputHal_hidl.cpp b/services/core/jni/tvinput/TvInputHal_hidl.cpp
new file mode 100644
index 0000000..37cf844
--- /dev/null
+++ b/services/core/jni/tvinput/TvInputHal_hidl.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "JTvInputHal.h"
+
+// Implement all HIDL related functions here.
+
+namespace android {
+
+void JTvInputHal::hidlSetUpAudioInfo(JNIEnv* env, jobject& builder,
+                                     const TvInputDeviceInfoWrapper& info) {
+    env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType,
+                          info.hidlAudioType);
+    if (info.hidlAudioType != HidlAudioDevice::NONE) {
+        uint8_t buffer[info.hidlAudioAddress.size() + 1];
+        memcpy(buffer, info.hidlAudioAddress.data(), info.hidlAudioAddress.size());
+        buffer[info.hidlAudioAddress.size()] = '\0';
+        jstring audioAddress = env->NewStringUTF(reinterpret_cast<const char*>(buffer));
+        env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress,
+                              audioAddress);
+        env->DeleteLocalRef(audioAddress);
+    }
+}
+
+JTvInputHal::TvInputDeviceInfoWrapper
+JTvInputHal::TvInputDeviceInfoWrapper::createDeviceInfoWrapper(
+        const HidlTvInputDeviceInfo& hidlTvInputDeviceInfo) {
+    TvInputDeviceInfoWrapper deviceInfo;
+    deviceInfo.isHidl = true;
+    deviceInfo.deviceId = hidlTvInputDeviceInfo.deviceId;
+    deviceInfo.type = TvInputType(static_cast<int32_t>(hidlTvInputDeviceInfo.type));
+    deviceInfo.portId = hidlTvInputDeviceInfo.portId;
+    deviceInfo.cableConnectionStatus = CableConnectionStatus(
+            static_cast<int32_t>(hidlTvInputDeviceInfo.cableConnectionStatus));
+    deviceInfo.hidlAudioType = hidlTvInputDeviceInfo.audioType;
+    deviceInfo.hidlAudioAddress = hidlTvInputDeviceInfo.audioAddress;
+    return deviceInfo;
+}
+
+JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWrapper(
+        const HidlTvInputEvent& hidlTvInputEvent) {
+    TvInputEventWrapper event;
+    event.type = TvInputEventType(static_cast<int32_t>(hidlTvInputEvent.type));
+    event.deviceInfo =
+            TvInputDeviceInfoWrapper::createDeviceInfoWrapper(hidlTvInputEvent.deviceInfo);
+    return event;
+}
+
+Return<void> JTvInputHal::TvInputCallback::notify(const HidlTvInputEvent& event) {
+    mHal->mLooper->sendMessage(new NotifyHandler(mHal,
+                                                 TvInputEventWrapper::createEventWrapper(event)),
+                               static_cast<int>(event.type));
+    return Void();
+}
+
+JTvInputHal::ITvInputWrapper::ITvInputWrapper(sp<HidlITvInput>& hidlTvInput)
+      : mIsHidl(true), mHidlTvInput(hidlTvInput) {}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::hidlSetCallback(
+        const std::shared_ptr<TvInputCallback>& in_callback) {
+    mHidlTvInput->setCallback(in_callback == nullptr ? nullptr
+                                                     : sp<TvInputCallback>(in_callback.get()));
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::hidlGetStreamConfigurations(
+        int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return) {
+    Result result = Result::UNKNOWN;
+    hidl_vec<HidlTvStreamConfig> list;
+    mHidlTvInput->getStreamConfigurations(in_deviceId,
+                                          [&result, &list](Result res,
+                                                           hidl_vec<HidlTvStreamConfig> configs) {
+                                              result = res;
+                                              if (res == Result::OK) {
+                                                  list = configs;
+                                              }
+                                          });
+    if (result != Result::OK) {
+        ALOGE("Couldn't get stream configs for device id:%d result:%d", in_deviceId, result);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
+    }
+    for (size_t i = 0; i < list.size(); ++i) {
+        AidlTvStreamConfig config;
+        config.streamId = list[i].streamId;
+        config.maxVideoHeight = list[i].maxVideoHeight;
+        config.maxVideoWidth = list[i].maxVideoWidth;
+        _aidl_return->push_back(config);
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::hidlOpenStream(int32_t in_deviceId,
+                                                                  int32_t in_streamId,
+                                                                  AidlNativeHandle* _aidl_return) {
+    Result result = Result::UNKNOWN;
+    native_handle_t* sidebandStream;
+    mHidlTvInput->openStream(in_deviceId, in_streamId,
+                             [&result, &sidebandStream](Result res, const native_handle_t* handle) {
+                                 result = res;
+                                 if (res == Result::OK) {
+                                     if (handle) {
+                                         sidebandStream = native_handle_clone(handle);
+                                     }
+                                 }
+                             });
+    if (result != Result::OK) {
+        ALOGE("Couldn't open stream. device id:%d stream id:%d result:%d", in_deviceId, in_streamId,
+              result);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
+    }
+    *_aidl_return = makeToAidl(sidebandStream);
+    native_handle_delete(sidebandStream);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::hidlCloseStream(int32_t in_deviceId,
+                                                                   int32_t in_streamId) {
+    Result result = mHidlTvInput->closeStream(in_deviceId, in_streamId);
+    if (result != Result::OK) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(result));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace android
diff --git a/services/core/jni/tvinput/TvInputHal_hidl.h b/services/core/jni/tvinput/TvInputHal_hidl.h
new file mode 100644
index 0000000..948f86b
--- /dev/null
+++ b/services/core/jni/tvinput/TvInputHal_hidl.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 all HIDL related files/names here.
+
+#include <android/hardware/tv/input/1.0/ITvInput.h>
+#include <android/hardware/tv/input/1.0/ITvInputCallback.h>
+#include <android/hardware/tv/input/1.0/types.h>
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::input::V1_0::Result;
+
+using HidlAudioDevice = ::android::hardware::audio::common::V2_0::AudioDevice;
+using HidlITvInput = ::android::hardware::tv::input::V1_0::ITvInput;
+using HidlITvInputCallback = ::android::hardware::tv::input::V1_0::ITvInputCallback;
+using HidlTvInputDeviceInfo = ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
+using HidlTvInputEvent = ::android::hardware::tv::input::V1_0::TvInputEvent;
+using HidlTvStreamConfig = ::android::hardware::tv::input::V1_0::TvStreamConfig;
diff --git a/services/core/jni/tvinput/jstruct.h b/services/core/jni/tvinput/jstruct.h
new file mode 100644
index 0000000..0a4a64d
--- /dev/null
+++ b/services/core/jni/tvinput/jstruct.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "jni.h"
+
+typedef struct {
+    jmethodID deviceAvailable;
+    jmethodID deviceUnavailable;
+    jmethodID streamConfigsChanged;
+    jmethodID firstFrameCaptured;
+} gTvInputHalClassInfoType;
+
+typedef struct {
+    jclass clazz;
+} gTvStreamConfigClassInfoType;
+
+typedef struct {
+    jclass clazz;
+
+    jmethodID constructor;
+    jmethodID streamId;
+    jmethodID type;
+    jmethodID maxWidth;
+    jmethodID maxHeight;
+    jmethodID generation;
+    jmethodID build;
+} gTvStreamConfigBuilderClassInfoType;
+
+typedef struct {
+    jclass clazz;
+
+    jmethodID constructor;
+    jmethodID deviceId;
+    jmethodID type;
+    jmethodID hdmiPortId;
+    jmethodID cableConnectionStatus;
+    jmethodID audioType;
+    jmethodID audioAddress;
+    jmethodID build;
+} gTvInputHardwareInfoBuilderClassInfoType;
diff --git a/services/core/xsd/display-layout-config/display-layout-config.xsd b/services/core/xsd/display-layout-config/display-layout-config.xsd
index e14139a..842d97a 100644
--- a/services/core/xsd/display-layout-config/display-layout-config.xsd
+++ b/services/core/xsd/display-layout-config/display-layout-config.xsd
@@ -50,6 +50,7 @@
     <xs:complexType name="display">
         <xs:sequence>
             <xs:element name="address" type="xs:nonNegativeInteger"/>
+            <xs:element name="position" type="xs:string" minOccurs="0" maxOccurs="1" />
         </xs:sequence>
         <xs:attribute name="enabled" type="xs:boolean" use="optional" />
         <xs:attribute name="defaultDisplay" type="xs:boolean" use="optional" />
diff --git a/services/core/xsd/display-layout-config/schema/current.txt b/services/core/xsd/display-layout-config/schema/current.txt
index f391575..55f866c 100644
--- a/services/core/xsd/display-layout-config/schema/current.txt
+++ b/services/core/xsd/display-layout-config/schema/current.txt
@@ -4,11 +4,13 @@
   public class Display {
     ctor public Display();
     method public java.math.BigInteger getAddress();
+    method public String getPosition();
     method public boolean isDefaultDisplay();
     method public boolean isEnabled();
     method public void setAddress(java.math.BigInteger);
     method public void setDefaultDisplay(boolean);
     method public void setEnabled(boolean);
+    method public void setPosition(String);
   }
 
   public class Layout {
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 374da1c..d3b9e10 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -22,10 +22,11 @@
 import android.annotation.UserIdInt;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.credentials.ClearCredentialStateRequest;
 import android.credentials.CreateCredentialRequest;
 import android.credentials.GetCredentialOption;
 import android.credentials.GetCredentialRequest;
-import android.credentials.IClearCredentialSessionCallback;
+import android.credentials.IClearCredentialStateCallback;
 import android.credentials.ICreateCredentialCallback;
 import android.credentials.ICredentialManager;
 import android.credentials.IGetCredentialCallback;
@@ -34,6 +35,7 @@
 import android.os.ICancellationSignal;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.service.credentials.BeginCreateCredentialRequest;
 import android.service.credentials.GetCredentialsRequest;
 import android.text.TextUtils;
 import android.util.Log;
@@ -198,7 +200,7 @@
             // Iterate over all provider sessions and invoke the request
             providerSessions.forEach(providerCreateSession -> {
                 providerCreateSession.getRemoteCredentialService().onCreateCredential(
-                        (android.service.credentials.CreateCredentialRequest)
+                        (BeginCreateCredentialRequest)
                                 providerCreateSession.getProviderRequest(),
                         /*callback=*/providerCreateSession);
             });
@@ -206,8 +208,8 @@
         }
 
         @Override
-        public ICancellationSignal clearCredentialSession(
-                IClearCredentialSessionCallback callback, String callingPackage) {
+        public ICancellationSignal clearCredentialState(ClearCredentialStateRequest request,
+                IClearCredentialStateCallback callback, String callingPackage) {
             // TODO: implement.
             Log.i(TAG, "clearCredentialSession");
             ICancellationSignal cancelTransport = CancellationSignal.createTransport();
diff --git a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
index 4cdc457..d0bc074 100644
--- a/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
+++ b/services/credentials/java/com/android/server/credentials/PendingIntentResultHandler.java
@@ -22,7 +22,7 @@
 import android.credentials.Credential;
 import android.credentials.ui.ProviderPendingIntentResponse;
 import android.service.credentials.CredentialProviderService;
-import android.service.credentials.CredentialsDisplayContent;
+import android.service.credentials.CredentialsResponseContent;
 
 /**
  * Helper class for setting up pending intent, and extracting objects from it.
@@ -37,14 +37,15 @@
         return pendingIntentResponse.getResultCode() == Activity.RESULT_OK;
     }
 
-    /** Extracts the {@link CredentialsDisplayContent} object added to the result data. */
-    public static CredentialsDisplayContent extractCredentialsDisplayContent(Intent resultData) {
+    /** Extracts the {@link CredentialsResponseContent} object added to the result data. */
+    public static CredentialsResponseContent extractResponseContent(Intent resultData) {
         if (resultData == null) {
             return null;
         }
         return resultData.getParcelableExtra(
-                CredentialProviderService.EXTRA_GET_CREDENTIALS_DISPLAY_CONTENT,
-                CredentialsDisplayContent.class);
+                CredentialProviderService
+                        .EXTRA_GET_CREDENTIALS_CONTENT_RESULT,
+                CredentialsResponseContent.class);
     }
 
     /** Extracts the {@link CreateCredentialResponse} object added to the result data. */
@@ -53,7 +54,7 @@
             return null;
         }
         return resultData.getParcelableExtra(
-                CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESPONSE,
+                CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESULT,
                 CreateCredentialResponse.class);
     }
 
@@ -63,7 +64,7 @@
             return null;
         }
         return resultData.getParcelableExtra(
-                CredentialProviderService.EXTRA_GET_CREDENTIAL,
+                CredentialProviderService.EXTRA_CREDENTIAL_RESULT,
                 Credential.class);
     }
 }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index 6bb8c60..8854453 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -25,12 +25,12 @@
 import android.credentials.ui.CreateCredentialProviderData;
 import android.credentials.ui.Entry;
 import android.credentials.ui.ProviderPendingIntentResponse;
-import android.os.Bundle;
+import android.service.credentials.BeginCreateCredentialRequest;
+import android.service.credentials.BeginCreateCredentialResponse;
 import android.service.credentials.CreateCredentialRequest;
-import android.service.credentials.CreateCredentialResponse;
+import android.service.credentials.CreateEntry;
 import android.service.credentials.CredentialProviderInfo;
 import android.service.credentials.CredentialProviderService;
-import android.service.credentials.SaveEntry;
 import android.util.Log;
 import android.util.Slog;
 
@@ -44,14 +44,14 @@
  * Will likely split this into remote response state and UI state.
  */
 public final class ProviderCreateSession extends ProviderSession<
-        CreateCredentialRequest, CreateCredentialResponse> {
+        BeginCreateCredentialRequest, BeginCreateCredentialResponse> {
     private static final String TAG = "ProviderCreateSession";
 
     // Key to be used as an entry key for a save entry
     private static final String SAVE_ENTRY_KEY = "save_entry_key";
 
     @NonNull
-    private final Map<String, SaveEntry> mUiSaveEntries = new HashMap<>();
+    private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>();
     /** The complete request to be used in the second round. */
     private final CreateCredentialRequest mCompleteRequest;
 
@@ -62,13 +62,18 @@
             CredentialProviderInfo providerInfo,
             CreateRequestSession createRequestSession,
             RemoteCredentialService remoteCredentialService) {
-        CreateCredentialRequest providerRequest =
+        CreateCredentialRequest providerCreateRequest =
                 createProviderRequest(providerInfo.getCapabilities(),
                         createRequestSession.mClientRequest,
                         createRequestSession.mClientCallingPackage);
-        if (providerRequest != null) {
+        if (providerCreateRequest != null) {
+            BeginCreateCredentialRequest providerBeginCreateRequest =
+                    new BeginCreateCredentialRequest(
+                            providerCreateRequest.getCallingPackage(),
+                            providerCreateRequest.getType(),
+                            createRequestSession.mClientRequest.getCandidateQueryData());
             return new ProviderCreateSession(context, providerInfo, createRequestSession, userId,
-                    remoteCredentialService, providerRequest);
+                    remoteCredentialService, providerBeginCreateRequest, providerCreateRequest);
         }
         Log.i(TAG, "Unable to create provider session");
         return null;
@@ -81,42 +86,34 @@
         String capability = clientRequest.getType();
         if (providerCapabilities.contains(capability)) {
             return new CreateCredentialRequest(clientCallingPackage, capability,
-                    clientRequest.getData());
+                    clientRequest.getCredentialData());
         }
         Log.i(TAG, "Unable to create provider request - capabilities do not match");
         return null;
     }
 
-    private static CreateCredentialRequest getFirstRoundRequest(CreateCredentialRequest request) {
-        // TODO: Replace with first round bundle from request when ready
-        return new CreateCredentialRequest(
-                request.getCallingPackage(),
-                request.getType(),
-                new Bundle());
-    }
-
     private ProviderCreateSession(
             @NonNull Context context,
             @NonNull CredentialProviderInfo info,
             @NonNull ProviderInternalCallback callbacks,
             @UserIdInt int userId,
             @NonNull RemoteCredentialService remoteCredentialService,
-            @NonNull CreateCredentialRequest request) {
-        super(context, info, getFirstRoundRequest(request), callbacks, userId,
+            @NonNull BeginCreateCredentialRequest beginCreateRequest,
+            @NonNull CreateCredentialRequest completeCreateRequest) {
+        super(context, info, beginCreateRequest, callbacks, userId,
                 remoteCredentialService);
-        // TODO : Replace with proper splitting of request
-        mCompleteRequest = request;
+        mCompleteRequest = completeCreateRequest;
         setStatus(Status.PENDING);
     }
 
     /** Returns the save entry maintained in state by this provider session. */
-    public SaveEntry getUiSaveEntry(String entryId) {
+    public CreateEntry getUiSaveEntry(String entryId) {
         return mUiSaveEntries.get(entryId);
     }
 
     @Override
     public void onProviderResponseSuccess(
-            @Nullable CreateCredentialResponse response) {
+            @Nullable BeginCreateCredentialResponse response) {
         Log.i(TAG, "in onProviderResponseSuccess");
         onUpdateResponse(response);
     }
@@ -138,7 +135,7 @@
         }
     }
 
-    private void onUpdateResponse(CreateCredentialResponse response) {
+    private void onUpdateResponse(BeginCreateCredentialResponse response) {
         Log.i(TAG, "updateResponse with save entries");
         mProviderResponse = response;
         updateStatusAndInvokeCallback(Status.SAVE_ENTRIES_RECEIVED);
@@ -152,15 +149,15 @@
             Log.i(TAG, "In prepareUiData not in uiInvokingStatus");
             return null;
         }
-        final CreateCredentialResponse response = getProviderResponse();
+        final BeginCreateCredentialResponse response = getProviderResponse();
         if (response == null) {
             Log.i(TAG, "In prepareUiData response null");
             throw new IllegalStateException("Response must be in completion mode");
         }
-        if (response.getSaveEntries() != null) {
+        if (response.getCreateEntries() != null) {
             Log.i(TAG, "In prepareUiData save entries not null");
             return prepareUiProviderData(
-                    prepareUiSaveEntries(response.getSaveEntries()),
+                    prepareUiSaveEntries(response.getCreateEntries()),
                     null,
                     /*isDefaultProvider=*/false);
         }
@@ -192,24 +189,25 @@
         }
     }
 
-    private List<Entry> prepareUiSaveEntries(@NonNull List<SaveEntry> saveEntries) {
+    private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) {
         Log.i(TAG, "in populateUiSaveEntries");
         List<Entry> uiSaveEntries = new ArrayList<>();
 
         // Populate the save entries
-        for (SaveEntry saveEntry : saveEntries) {
+        for (CreateEntry createEntry : saveEntries) {
             String entryId = generateEntryId();
-            mUiSaveEntries.put(entryId, saveEntry);
+            mUiSaveEntries.put(entryId, createEntry);
             Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
-            uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, saveEntry.getSlice(),
-                    saveEntry.getPendingIntent(), setUpFillInIntent(saveEntry.getPendingIntent())));
+            uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, createEntry.getSlice(),
+                    createEntry.getPendingIntent(), setUpFillInIntent(
+                            createEntry.getPendingIntent())));
         }
         return uiSaveEntries;
     }
 
     private Intent setUpFillInIntent(PendingIntent pendingIntent) {
         Intent intent = pendingIntent.getIntent();
-        intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST_PARAMS,
+        intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST,
                 mCompleteRequest);
         return intent;
     }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index d63cdeb..6cd011b 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -29,7 +29,7 @@
 import android.service.credentials.Action;
 import android.service.credentials.CredentialEntry;
 import android.service.credentials.CredentialProviderInfo;
-import android.service.credentials.CredentialsDisplayContent;
+import android.service.credentials.CredentialsResponseContent;
 import android.service.credentials.GetCredentialsRequest;
 import android.service.credentials.GetCredentialsResponse;
 import android.util.Log;
@@ -211,20 +211,20 @@
                     prepareUiAuthenticationAction(mProviderResponse.getAuthenticationAction()),
                     /*remoteEntry=*/null);
         }
-        if (mProviderResponse.getCredentialsDisplayContent() != null) {
-            Log.i(TAG, "In prepareUiData displayContent not null");
+        if (mProviderResponse.getCredentialsResponseContent() != null) {
+            Log.i(TAG, "In prepareUiData credentialsResponseContent not null");
             return prepareUiProviderData(prepareUiActionEntries(
-                            mProviderResponse.getCredentialsDisplayContent().getActions()),
-                    prepareUiCredentialEntries(mProviderResponse.getCredentialsDisplayContent()
+                            mProviderResponse.getCredentialsResponseContent().getActions()),
+                    prepareUiCredentialEntries(mProviderResponse.getCredentialsResponseContent()
                             .getCredentialEntries()),
                     /*authenticationAction=*/null,
                     prepareUiRemoteEntry(mProviderResponse
-                            .getCredentialsDisplayContent().getRemoteCredentialEntry()));
+                            .getCredentialsResponseContent().getRemoteCredentialEntry()));
         }
         return null;
     }
 
-    private Entry prepareUiRemoteEntry(Action remoteCredentialEntry) {
+    private Entry prepareUiRemoteEntry(CredentialEntry remoteCredentialEntry) {
         if (remoteCredentialEntry == null) {
             return null;
         }
@@ -316,11 +316,11 @@
             @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
         if (providerPendingIntentResponse != null) {
             if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
-                CredentialsDisplayContent content = PendingIntentResultHandler
-                        .extractCredentialsDisplayContent(providerPendingIntentResponse
+                CredentialsResponseContent content = PendingIntentResultHandler
+                        .extractResponseContent(providerPendingIntentResponse
                                 .getResultData());
                 if (content != null) {
-                    onUpdateResponse(GetCredentialsResponse.createWithDisplayContent(content));
+                    onUpdateResponse(GetCredentialsResponse.createWithResponseContent(content));
                     return;
                 }
             }
@@ -342,7 +342,7 @@
         if (response.getAuthenticationAction() != null) {
             Log.i(TAG , "updateResponse with authentication entry");
             updateStatusAndInvokeCallback(Status.REQUIRES_AUTHENTICATION);
-        } else if (response.getCredentialsDisplayContent() != null) {
+        } else if (response.getCredentialsResponseContent() != null) {
             Log.i(TAG , "updateResponse with credentialEntries");
             // TODO validate response
             updateStatusAndInvokeCallback(Status.CREDENTIALS_RECEIVED);
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 4a07f0a..ac360bd 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -23,7 +23,7 @@
 import android.credentials.Credential;
 import android.credentials.ui.ProviderData;
 import android.credentials.ui.ProviderPendingIntentResponse;
-import android.service.credentials.Action;
+import android.service.credentials.CredentialEntry;
 import android.service.credentials.CredentialProviderException;
 import android.service.credentials.CredentialProviderInfo;
 import android.util.Pair;
@@ -50,7 +50,7 @@
     @Nullable protected Credential mFinalCredentialResponse;
     @NonNull protected final T mProviderRequest;
     @Nullable protected R mProviderResponse;
-    @Nullable protected Pair<String, Action> mUiRemoteEntry;
+    @Nullable protected Pair<String, CredentialEntry> mUiRemoteEntry;
 
     /**
      * Returns true if the given status reflects that the provider state is ready to be shown
diff --git a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
index c2464b5..e385bcb 100644
--- a/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
+++ b/services/credentials/java/com/android/server/credentials/RemoteCredentialService.java
@@ -24,14 +24,14 @@
 import android.os.Handler;
 import android.os.ICancellationSignal;
 import android.os.RemoteException;
-import android.service.credentials.CreateCredentialRequest;
-import android.service.credentials.CreateCredentialResponse;
+import android.service.credentials.BeginCreateCredentialRequest;
+import android.service.credentials.BeginCreateCredentialResponse;
 import android.service.credentials.CredentialProviderException;
 import android.service.credentials.CredentialProviderException.CredentialProviderError;
 import android.service.credentials.CredentialProviderService;
 import android.service.credentials.GetCredentialsRequest;
 import android.service.credentials.GetCredentialsResponse;
-import android.service.credentials.ICreateCredentialCallback;
+import android.service.credentials.IBeginCreateCredentialCallback;
 import android.service.credentials.ICredentialProviderService;
 import android.service.credentials.IGetCredentialsCallback;
 import android.text.format.DateUtils;
@@ -146,27 +146,27 @@
                 handleExecutionResponse(result, error, cancellationSink, callback)));
     }
 
-    /** Main entry point to be called for executing a createCredential call on the remote
+    /** Main entry point to be called for executing a beginCreateCredential call on the remote
      * provider service.
      * @param request the request to be sent to the provider
      * @param callback the callback to be used to send back the provider response to the
      *                 {@link ProviderCreateSession} class that maintains provider state
      */
-    public void onCreateCredential(@NonNull CreateCredentialRequest request,
-            ProviderCallbacks<CreateCredentialResponse> callback) {
+    public void onCreateCredential(@NonNull BeginCreateCredentialRequest request,
+            ProviderCallbacks<BeginCreateCredentialResponse> callback) {
         Log.i(TAG, "In onCreateCredential in RemoteCredentialService");
         AtomicReference<ICancellationSignal> cancellationSink = new AtomicReference<>();
-        AtomicReference<CompletableFuture<CreateCredentialResponse>> futureRef =
+        AtomicReference<CompletableFuture<BeginCreateCredentialResponse>> futureRef =
                 new AtomicReference<>();
 
-        CompletableFuture<CreateCredentialResponse> connectThenExecute = postAsync(service -> {
-            CompletableFuture<CreateCredentialResponse> createCredentialFuture =
+        CompletableFuture<BeginCreateCredentialResponse> connectThenExecute = postAsync(service -> {
+            CompletableFuture<BeginCreateCredentialResponse> createCredentialFuture =
                     new CompletableFuture<>();
-            ICancellationSignal cancellationSignal = service.onCreateCredential(
-                    request, new ICreateCredentialCallback.Stub() {
+            ICancellationSignal cancellationSignal = service.onBeginCreateCredential(
+                    request, new IBeginCreateCredentialCallback.Stub() {
                         @Override
-                        public void onSuccess(CreateCredentialResponse response) {
-                            Log.i(TAG, "In onSuccess onCreateCredential "
+                        public void onSuccess(BeginCreateCredentialResponse response) {
+                            Log.i(TAG, "In onSuccess onBeginCreateCredential "
                                     + "in RemoteCredentialService");
                             createCredentialFuture.complete(response);
                         }
@@ -179,7 +179,7 @@
                             createCredentialFuture.completeExceptionally(
                                     new CredentialProviderException(errorCode, errorMsg));
                         }});
-            CompletableFuture<CreateCredentialResponse> future = futureRef.get();
+            CompletableFuture<BeginCreateCredentialResponse> future = futureRef.get();
             if (future != null && future.isCancelled()) {
                 dispatchCancellationSignal(cancellationSignal);
             } else {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
index 8a8485a..9cb7533 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/BooleanPolicySerializer.java
@@ -16,24 +16,35 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Objects;
 
 final class BooleanPolicySerializer extends PolicySerializer<Boolean> {
 
     @Override
-    void saveToXml(TypedXmlSerializer serializer, String attributeName, Boolean value)
+    void saveToXml(TypedXmlSerializer serializer, String attributeName, @NonNull Boolean value)
             throws IOException {
+        Objects.requireNonNull(value);
         serializer.attributeBoolean(/* namespace= */ null, attributeName, value);
     }
 
+    @Nullable
     @Override
-    Boolean readFromXml(TypedXmlPullParser parser, String attributeName)
-            throws XmlPullParserException {
-        return parser.getAttributeBoolean(/* namespace= */ null, attributeName);
+    Boolean readFromXml(TypedXmlPullParser parser, String attributeName) {
+        try {
+            return parser.getAttributeBoolean(/* namespace= */ null, attributeName);
+        } catch (XmlPullParserException e) {
+            Log.e(DevicePolicyEngine.TAG, "Error parsing Boolean policy value", e);
+            return null;
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 61d93c7..775e3d8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -81,6 +81,7 @@
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
 import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_NOT_SUSPENDED;
 import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_EXPLICITLY;
 import static android.app.admin.DevicePolicyManager.PERSONAL_APPS_SUSPENDED_PROFILE_TIMEOUT;
@@ -140,6 +141,7 @@
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE;
 import static android.net.ConnectivityManager.PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK;
 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.provider.DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER;
 import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER;
 import static android.provider.Settings.Secure.MANAGED_PROVISIONING_DPC_DOWNLOADED;
 import static android.provider.Settings.Secure.USER_SETUP_COMPLETE;
@@ -309,6 +311,7 @@
 import android.provider.CalendarContract;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsInternal;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Telephony;
@@ -712,6 +715,17 @@
                     + "management app's authentication policy";
     private static final String NOT_SYSTEM_CALLER_MSG = "Only the system can %s";
 
+    private static final String ENABLE_COEXISTENCE_FLAG = "enable_coexistence";
+    private static final boolean DEFAULT_ENABLE_COEXISTENCE_FLAG = false;
+
+    /**
+     * For apps targeting U+
+     * Enable multiple admins to coexist on the same device.
+     */
+    @ChangeId
+    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+    static final long ENABLE_COEXISTENCE_CHANGE = 260560985L;
+
     final Context mContext;
     final Injector mInjector;
     final PolicyPathProvider mPathProvider;
@@ -795,6 +809,8 @@
     private final DeviceManagementResourcesProvider mDeviceManagementResourcesProvider;
     private final DevicePolicyManagementRoleObserver mDevicePolicyManagementRoleObserver;
 
+    private final DevicePolicyEngine mDevicePolicyEngine;
+
     private static final boolean ENABLE_LOCK_GUARD = true;
 
     /**
@@ -1864,6 +1880,8 @@
         mUserData = new SparseArray<>();
         mOwners = makeOwners(injector, pathProvider);
 
+        mDevicePolicyEngine = new DevicePolicyEngine(mContext);
+
         if (!mHasFeature) {
             // Skip the rest of the initialization
             mSetupContentObserver = null;
@@ -1908,6 +1926,9 @@
         mUserManagerInternal.addUserLifecycleListener(new UserLifecycleListener());
 
         mDeviceManagementResourcesProvider.load();
+        if (isCoexistenceFlagEnabled()) {
+            mDevicePolicyEngine.load();
+        }
 
         // The binder caches are not enabled until the first invalidation.
         invalidateBinderCaches();
@@ -7951,8 +7972,17 @@
         Preconditions.checkCallAuthorization(isProfileOwnerOnUser0(caller)
                 || isProfileOwnerOfOrganizationOwnedDevice(caller) || isDefaultDeviceOwner(caller));
 
-        mInjector.binderWithCleanCallingIdentity(() ->
-                mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
+        if (isCoexistenceEnabled(caller)) {
+            mDevicePolicyEngine.setGlobalPolicy(
+                    PolicyDefinition.AUTO_TIMEZONE,
+                    // TODO(b/260573124): add correct enforcing admin when permission changes are
+                    //  merged.
+                    EnforcingAdmin.createEnterpriseEnforcingAdmin(caller.getComponentName()),
+                    enabled);
+        } else {
+            mInjector.binderWithCleanCallingIdentity(() ->
+                    mInjector.settingsGlobalPutInt(Global.AUTO_TIME_ZONE, enabled ? 1 : 0));
+        }
 
         DevicePolicyEventLogger
                 .createEvent(DevicePolicyEnums.SET_AUTO_TIME_ZONE)
@@ -12245,8 +12275,38 @@
         synchronized (getLockObject()) {
             enforceCanCallLockTaskLocked(caller);
             checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_PACKAGES);
-            final int userHandle = caller.getUserId();
-            setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+        }
+
+        if (isCoexistenceEnabled(caller)) {
+            EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(who);
+            if (packages.length == 0) {
+                mDevicePolicyEngine.removeLocalPolicy(
+                        PolicyDefinition.LOCK_TASK,
+                        admin,
+                        caller.getUserId());
+            } else {
+                LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicy(
+                        PolicyDefinition.LOCK_TASK,
+                        caller.getUserId()).getPoliciesSetByAdmins().get(admin);
+                LockTaskPolicy policy;
+                if (currentPolicy == null) {
+                    policy = new LockTaskPolicy(Set.of(packages));
+                } else {
+                    policy = currentPolicy.clone();
+                    policy.setPackages(Set.of(packages));
+                }
+
+                mDevicePolicyEngine.setLocalPolicy(
+                        PolicyDefinition.LOCK_TASK,
+                        EnforcingAdmin.createEnterpriseEnforcingAdmin(who),
+                        policy,
+                        caller.getUserId());
+            }
+        } else {
+            synchronized (getLockObject()) {
+                final int userHandle = caller.getUserId();
+                setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
+            }
         }
     }
 
@@ -12267,8 +12327,21 @@
 
         synchronized (getLockObject()) {
             enforceCanCallLockTaskLocked(caller);
-            final List<String> packages = getUserData(userHandle).mLockTaskPackages;
-            return packages.toArray(new String[packages.size()]);
+        }
+
+        if (isCoexistenceEnabled(caller)) {
+            LockTaskPolicy policy = mDevicePolicyEngine.getLocalPolicy(
+                    PolicyDefinition.LOCK_TASK, userHandle).getCurrentResolvedPolicy();
+            if (policy == null) {
+                return new String[0];
+            } else {
+                return policy.getPackages().toArray(new String[policy.getPackages().size()]);
+            }
+        } else {
+            synchronized (getLockObject()) {
+                final List<String> packages = getUserData(userHandle).mLockTaskPackages;
+                return packages.toArray(new String[packages.size()]);
+            }
         }
     }
 
@@ -12284,8 +12357,19 @@
         }
 
         final int userId = mInjector.userHandleGetCallingUserId();
-        synchronized (getLockObject()) {
-            return getUserData(userId).mLockTaskPackages.contains(pkg);
+        // TODO(b/260560985): This is not the right check, as the flag could be enabled but there
+        //  could be an admin that hasn't targeted U.
+        if (isCoexistenceFlagEnabled()) {
+            LockTaskPolicy policy = mDevicePolicyEngine.getLocalPolicy(
+                    PolicyDefinition.LOCK_TASK, userId).getCurrentResolvedPolicy();
+            if (policy == null) {
+                return false;
+            }
+            return policy.getPackages().contains(pkg);
+        } else {
+            synchronized (getLockObject()) {
+                return getUserData(userId).mLockTaskPackages.contains(pkg);
+            }
         }
     }
 
@@ -12308,7 +12392,28 @@
             enforceCanCallLockTaskLocked(caller);
             enforceCanSetLockTaskFeaturesOnFinancedDevice(caller, flags);
             checkCanExecuteOrThrowUnsafe(DevicePolicyManager.OPERATION_SET_LOCK_TASK_FEATURES);
-            setLockTaskFeaturesLocked(userHandle, flags);
+        }
+        if (isCoexistenceEnabled(caller)) {
+            EnforcingAdmin admin = EnforcingAdmin.createEnterpriseEnforcingAdmin(who);
+            LockTaskPolicy currentPolicy = mDevicePolicyEngine.getLocalPolicy(
+                    PolicyDefinition.LOCK_TASK,
+                    caller.getUserId()).getPoliciesSetByAdmins().get(admin);
+            if (currentPolicy == null) {
+                throw new IllegalArgumentException("Can't set a lock task flags without setting "
+                        + "lock task packages first.");
+            }
+            LockTaskPolicy policy = currentPolicy.clone();
+            policy.setFlags(flags);
+
+            mDevicePolicyEngine.setLocalPolicy(
+                    PolicyDefinition.LOCK_TASK,
+                    EnforcingAdmin.createEnterpriseEnforcingAdmin(who),
+                    policy,
+                    caller.getUserId());
+        } else {
+            synchronized (getLockObject()) {
+                setLockTaskFeaturesLocked(userHandle, flags);
+            }
         }
     }
 
@@ -12326,7 +12431,21 @@
         final int userHandle = caller.getUserId();
         synchronized (getLockObject()) {
             enforceCanCallLockTaskLocked(caller);
-            return getUserData(userHandle).mLockTaskFeatures;
+        }
+
+        if (isCoexistenceEnabled(caller)) {
+            LockTaskPolicy policy = mDevicePolicyEngine.getLocalPolicy(
+                    PolicyDefinition.LOCK_TASK, userHandle).getCurrentResolvedPolicy();
+            if (policy == null) {
+                // We default on the power button menu, in order to be consistent with pre-P
+                // behaviour.
+                return DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
+            }
+            return policy.getFlags();
+        } else {
+            synchronized (getLockObject()) {
+                return getUserData(userHandle).mLockTaskFeatures;
+            }
         }
     }
 
@@ -13905,6 +14024,20 @@
             if (isFinancedDeviceOwner(caller)) {
                 enforcePermissionGrantStateOnFinancedDevice(packageName, permission);
             }
+        }
+        if (isCoexistenceEnabled(caller)) {
+            mDevicePolicyEngine.setLocalPolicy(
+                    PolicyDefinition.PERMISSION_GRANT(packageName, permission),
+                    // TODO(b/260573124): Add correct enforcing admin when permission changes are
+                    //  merged, and don't forget to handle delegates! Enterprise admins assume
+                    //  component name isn't null.
+                    EnforcingAdmin.createEnterpriseEnforcingAdmin(caller.getComponentName()),
+                    grantState,
+                    caller.getUserId());
+            // TODO: update javadoc to reflect that callback no longer return success/failure
+            callback.sendResult(Bundle.EMPTY);
+        } else {
+            synchronized (getLockObject()) {
             long ident = mInjector.binderClearCallingIdentity();
             try {
                 boolean isPostQAdmin = getTargetSdk(caller.getPackageName(), caller.getUserId())
@@ -13921,14 +14054,16 @@
                     callback.sendResult(null);
                     return;
                 }
-                if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
+                if (grantState == PERMISSION_GRANT_STATE_GRANTED
                         || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
                         || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
                     AdminPermissionControlParams permissionParams =
-                            new AdminPermissionControlParams(packageName, permission, grantState,
+                            new AdminPermissionControlParams(packageName, permission,
+                                    grantState,
                                     canAdminGrantSensorsPermissionsForUser(caller.getUserId()));
                     mInjector.getPermissionControllerManager(caller.getUserHandle())
-                            .setRuntimePermissionGrantStateByDeviceAdmin(caller.getPackageName(),
+                            .setRuntimePermissionGrantStateByDeviceAdmin(
+                                    caller.getPackageName(),
                                     permissionParams, mContext.getMainExecutor(),
                                     (permissionWasSet) -> {
                                         if (isPostQAdmin && !permissionWasSet) {
@@ -13947,13 +14082,14 @@
 
                                         callback.sendResult(Bundle.EMPTY);
                                     });
-                }
-            } catch (SecurityException e) {
-                Slogf.e(LOG_TAG, "Could not set permission grant state", e);
+                    }
+                } catch (SecurityException e) {
+                    Slogf.e(LOG_TAG, "Could not set permission grant state", e);
 
-                callback.sendResult(null);
-            } finally {
-                mInjector.binderRestoreCallingIdentity(ident);
+                    callback.sendResult(null);
+                } finally {
+                    mInjector.binderRestoreCallingIdentity(ident);
+                }
             }
         }
     }
@@ -19017,4 +19153,18 @@
             return result;
         });
     }
+
+    // TODO(b/260560985): properly gate coexistence changes
+    private boolean isCoexistenceEnabled(CallerIdentity caller) {
+        return isCoexistenceFlagEnabled()
+                && mInjector.isChangeEnabled(
+                        ENABLE_COEXISTENCE_CHANGE, caller.getPackageName(), caller.getUserId());
+    }
+
+    private boolean isCoexistenceFlagEnabled() {
+        return DeviceConfig.getBoolean(
+                NAMESPACE_DEVICE_POLICY_MANAGER,
+                ENABLE_COEXISTENCE_FLAG,
+                DEFAULT_ENABLE_COEXISTENCE_FLAG);
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
index 3152f0b..d5949dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/IntegerPolicySerializer.java
@@ -16,24 +16,35 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.Objects;
 
 final class IntegerPolicySerializer extends PolicySerializer<Integer> {
 
     @Override
-    void saveToXml(TypedXmlSerializer serializer, String attributeName, Integer value)
+    void saveToXml(TypedXmlSerializer serializer, String attributeName, @NonNull Integer value)
             throws IOException {
+        Objects.requireNonNull(value);
         serializer.attributeInt(/* namespace= */ null, attributeName, value);
     }
 
+    @Nullable
     @Override
-    Integer readFromXml(TypedXmlPullParser parser, String attributeName)
-            throws XmlPullParserException {
-        return parser.getAttributeInt(/* namespace= */ null, attributeName);
+    Integer readFromXml(TypedXmlPullParser parser, String attributeName) {
+        try {
+            return parser.getAttributeInt(/* namespace= */ null, attributeName);
+        } catch (XmlPullParserException e) {
+            Log.e(DevicePolicyEngine.TAG, "Error parsing Integer policy value", e);
+            return null;
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java
index 9360fd7..d3e8de4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/LockTaskPolicy.java
@@ -16,7 +16,10 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.admin.DevicePolicyManager;
+import android.util.Log;
 
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -24,19 +27,16 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
+import java.util.HashSet;
 import java.util.Objects;
 import java.util.Set;
 
 final class LockTaskPolicy {
-    private Set<String> mPackages;
-    private int mFlags;
+    static final int DEFAULT_LOCK_TASK_FLAG = DevicePolicyManager.LOCK_TASK_FEATURE_GLOBAL_ACTIONS;
+    private Set<String> mPackages = new HashSet<>();
+    private int mFlags = DEFAULT_LOCK_TASK_FLAG;
 
-    LockTaskPolicy(@Nullable Set<String> packages, int flags) {
-        mPackages = packages;
-        mFlags = flags;
-    }
-
-    @Nullable
+    @NonNull
     Set<String> getPackages() {
         return mPackages;
     }
@@ -45,8 +45,20 @@
         return mFlags;
     }
 
-    void setPackages(Set<String> packages) {
-        mPackages = packages;
+    LockTaskPolicy(Set<String> packages) {
+        Objects.requireNonNull(packages);
+        mPackages.addAll(packages);
+    }
+
+    private LockTaskPolicy(Set<String> packages, int flags) {
+        Objects.requireNonNull(packages);
+        mPackages = new HashSet<>(packages);
+        mFlags = flags;
+    }
+
+    void setPackages(@NonNull Set<String> packages) {
+        Objects.requireNonNull(packages);
+        mPackages = new HashSet<>(packages);
     }
 
     void setFlags(int flags) {
@@ -54,6 +66,13 @@
     }
 
     @Override
+    public LockTaskPolicy clone() {
+        LockTaskPolicy policy = new LockTaskPolicy(mPackages);
+        policy.setFlags(mFlags);
+        return policy;
+    }
+
+    @Override
     public boolean equals(@Nullable Object o) {
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
@@ -67,6 +86,11 @@
         return Objects.hash(mPackages, mFlags);
     }
 
+    @Override
+    public String toString() {
+        return "mPackages= " + String.join(", ", mPackages) + "; mFlags= " + mFlags;
+    }
+
     static final class LockTaskPolicySerializer extends PolicySerializer<LockTaskPolicy> {
 
         private static final String ATTR_PACKAGES = ":packages";
@@ -74,15 +98,17 @@
         private static final String ATTR_FLAGS = ":flags";
 
         @Override
-        void saveToXml(
-                TypedXmlSerializer serializer, String attributeNamePrefix, LockTaskPolicy value)
-                throws IOException {
-            if (value.mPackages != null) {
-                serializer.attribute(
-                        /* namespace= */ null,
-                        attributeNamePrefix + ATTR_PACKAGES,
-                        String.join(ATTR_PACKAGES_SEPARATOR, value.mPackages));
+        void saveToXml(TypedXmlSerializer serializer, String attributeNamePrefix,
+                @NonNull LockTaskPolicy value) throws IOException {
+            Objects.requireNonNull(value);
+            if (value.mPackages == null || value.mPackages.isEmpty()) {
+                throw new IllegalArgumentException("Error saving LockTaskPolicy to file, lock task "
+                        + "packages must be present");
             }
+            serializer.attribute(
+                    /* namespace= */ null,
+                    attributeNamePrefix + ATTR_PACKAGES,
+                    String.join(ATTR_PACKAGES_SEPARATOR, value.mPackages));
             serializer.attributeInt(
                     /* namespace= */ null,
                     attributeNamePrefix + ATTR_FLAGS,
@@ -90,18 +116,24 @@
         }
 
         @Override
-        LockTaskPolicy readFromXml(TypedXmlPullParser parser, String attributeNamePrefix)
-                throws XmlPullParserException {
+        LockTaskPolicy readFromXml(TypedXmlPullParser parser, String attributeNamePrefix) {
             String packagesStr = parser.getAttributeValue(
                     /* namespace= */ null,
                     attributeNamePrefix + ATTR_PACKAGES);
-            Set<String> packages = packagesStr == null
-                    ? null
-                    : Set.of(packagesStr.split(ATTR_PACKAGES_SEPARATOR));
-            int flags = parser.getAttributeInt(
-                    /* namespace= */ null,
-                    attributeNamePrefix + ATTR_FLAGS);
-            return new LockTaskPolicy(packages, flags);
+            if (packagesStr == null) {
+                Log.e(DevicePolicyEngine.TAG, "Error parsing LockTask policy value.");
+                return null;
+            }
+            Set<String> packages = Set.of(packagesStr.split(ATTR_PACKAGES_SEPARATOR));
+            try {
+                int flags = parser.getAttributeInt(
+                        /* namespace= */ null,
+                        attributeNamePrefix + ATTR_FLAGS);
+                return new LockTaskPolicy(packages, flags);
+            } catch (XmlPullParserException e) {
+                Log.e(DevicePolicyEngine.TAG, "Error parsing LockTask policy value", e);
+                return null;
+            }
         }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 3a18cb9..a787a0b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -25,8 +25,6 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.IOException;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -225,8 +223,8 @@
         mPolicySerializer.saveToXml(serializer, attributeName, value);
     }
 
-    V readPolicyValueFromXml(TypedXmlPullParser parser, String attributeName)
-            throws XmlPullParserException {
+    @Nullable
+    V readPolicyValueFromXml(TypedXmlPullParser parser, String attributeName) {
         return mPolicySerializer.readFromXml(parser, attributeName);
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index b645b97..74b6f9e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -29,6 +29,7 @@
 
 import com.android.server.utils.Slogf;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
@@ -53,7 +54,7 @@
     static boolean setPermissionGrantState(
             @Nullable Integer grantState, @NonNull Context context, int userId,
             @NonNull String[] args) {
-        Binder.withCleanCallingIdentity(() -> {
+        return Boolean.TRUE.equals(Binder.withCleanCallingIdentity(() -> {
             if (args == null || args.length < 2) {
                 throw new IllegalArgumentException("Package name and permission name must be "
                         + "provided as arguments");
@@ -84,8 +85,7 @@
                 // TODO: add logging
                 return false;
             }
-        });
-        return true;
+        }));
     }
 
     @NonNull
@@ -106,9 +106,14 @@
 
     static boolean setLockTask(
             @Nullable LockTaskPolicy policy, @NonNull Context context, int userId) {
-        DevicePolicyManagerService.updateLockTaskPackagesLocked(
-                context, List.copyOf(policy.getPackages()), userId);
-        DevicePolicyManagerService.updateLockTaskFeaturesLocked(policy.getFlags(), userId);
+        List<String> packages = Collections.emptyList();
+        int flags = LockTaskPolicy.DEFAULT_LOCK_TASK_FLAG;
+        if (policy != null) {
+            packages = List.copyOf(policy.getPackages());
+            flags = policy.getFlags();
+        }
+        DevicePolicyManagerService.updateLockTaskPackagesLocked(context, packages, userId);
+        DevicePolicyManagerService.updateLockTaskFeaturesLocked(flags, userId);
         return true;
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
index b3259d3..528d3b0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicySerializer.java
@@ -16,16 +16,15 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.NonNull;
+
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.IOException;
 
 abstract class PolicySerializer<V> {
-    abstract void saveToXml(TypedXmlSerializer serializer, String attributeName, V value)
+    abstract void saveToXml(TypedXmlSerializer serializer, String attributeName, @NonNull V value)
             throws IOException;
-    abstract V readFromXml(TypedXmlPullParser parser, String attributeName)
-            throws XmlPullParserException;
+    abstract V readFromXml(TypedXmlPullParser parser, String attributeName);
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
index aad82cd..d3dee98 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyState.java
@@ -40,7 +40,7 @@
     private static final String ATTR_RESOLVED_POLICY = "resolved-policy";
 
     private final PolicyDefinition<V> mPolicyDefinition;
-    private final LinkedHashMap<EnforcingAdmin, V> mAdminsPolicy = new LinkedHashMap<>();
+    private final LinkedHashMap<EnforcingAdmin, V> mPoliciesSetByAdmins = new LinkedHashMap<>();
     private V mCurrentResolvedPolicy;
 
     PolicyState(@NonNull PolicyDefinition<V> policyDefinition) {
@@ -49,13 +49,13 @@
 
     private PolicyState(
             @NonNull PolicyDefinition<V> policyDefinition,
-            @NonNull LinkedHashMap<EnforcingAdmin, V> adminsPolicy,
+            @NonNull LinkedHashMap<EnforcingAdmin, V> policiesSetByAdmins,
             V currentEnforcedPolicy) {
         Objects.requireNonNull(policyDefinition);
-        Objects.requireNonNull(adminsPolicy);
+        Objects.requireNonNull(policiesSetByAdmins);
 
         mPolicyDefinition = policyDefinition;
-        mAdminsPolicy.putAll(adminsPolicy);
+        mPoliciesSetByAdmins.putAll(policiesSetByAdmins);
         mCurrentResolvedPolicy = currentEnforcedPolicy;
     }
 
@@ -63,7 +63,7 @@
      * Returns {@code true} if the resolved policy has changed, {@code false} otherwise.
      */
     boolean setPolicy(@NonNull EnforcingAdmin admin, @NonNull V value) {
-        mAdminsPolicy.put(Objects.requireNonNull(admin), Objects.requireNonNull(value));
+        mPoliciesSetByAdmins.put(Objects.requireNonNull(admin), Objects.requireNonNull(value));
 
         return resolvePolicy();
     }
@@ -71,16 +71,20 @@
     boolean removePolicy(@NonNull EnforcingAdmin admin) {
         Objects.requireNonNull(admin);
 
-        if (mAdminsPolicy.remove(admin) == null) {
+        if (mPoliciesSetByAdmins.remove(admin) == null) {
             return false;
         }
 
         return resolvePolicy();
     }
 
+    LinkedHashMap<EnforcingAdmin, V> getPoliciesSetByAdmins() {
+        return mPoliciesSetByAdmins;
+    }
+
     private boolean resolvePolicy() {
-        V resolvedPolicy = mPolicyDefinition.resolvePolicy(mAdminsPolicy);
-        boolean policyChanged = Objects.equals(resolvedPolicy, mCurrentResolvedPolicy);
+        V resolvedPolicy = mPolicyDefinition.resolvePolicy(mPoliciesSetByAdmins);
+        boolean policyChanged = !Objects.equals(resolvedPolicy, mCurrentResolvedPolicy);
         mCurrentResolvedPolicy = resolvedPolicy;
 
         return policyChanged;
@@ -94,14 +98,16 @@
     void saveToXml(TypedXmlSerializer serializer) throws IOException {
         mPolicyDefinition.saveToXml(serializer);
 
-        mPolicyDefinition.savePolicyValueToXml(
-                serializer, ATTR_RESOLVED_POLICY, mCurrentResolvedPolicy);
+        if (mCurrentResolvedPolicy != null) {
+            mPolicyDefinition.savePolicyValueToXml(
+                    serializer, ATTR_RESOLVED_POLICY, mCurrentResolvedPolicy);
+        }
 
-        for (EnforcingAdmin admin : mAdminsPolicy.keySet()) {
+        for (EnforcingAdmin admin : mPoliciesSetByAdmins.keySet()) {
             serializer.startTag(/* namespace= */ null, TAG_ADMIN_POLICY_ENTRY);
 
             mPolicyDefinition.savePolicyValueToXml(
-                    serializer, ATTR_POLICY_VALUE, mAdminsPolicy.get(admin));
+                    serializer, ATTR_POLICY_VALUE, mPoliciesSetByAdmins.get(admin));
 
             serializer.startTag(/* namespace= */ null, TAG_ENFORCING_ADMIN_ENTRY);
             admin.saveToXml(serializer);
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 693f3a0..1bd5031 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -788,7 +788,7 @@
 
     private void updateDefaultSmsApp(@NonNull UserData userData) {
         ComponentName component = SmsApplication.getDefaultSmsApplicationAsUser(
-                mContext, /* updateIfNeeded= */ false, userData.getUserId());
+                mContext, /* updateIfNeeded= */ false, UserHandle.of(userData.getUserId()));
         String defaultSmsApp = component != null ? component.getPackageName() : null;
         userData.setDefaultSmsApp(defaultSmsApp);
     }
diff --git a/services/permission/Android.bp b/services/permission/Android.bp
index b03f17b..dc9b558 100644
--- a/services/permission/Android.bp
+++ b/services/permission/Android.bp
@@ -29,6 +29,8 @@
     ],
     static_libs: [
         "kotlin-stdlib",
+        // Adds reflection-less suppressed exceptions and AutoCloseable.use().
+        "kotlin-stdlib-jdk7",
     ],
     jarjar_rules: "jarjar-rules.txt",
     kotlincflags: [
diff --git a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
index c6ccc0f..7b96d42 100644
--- a/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessCheckingService.kt
@@ -40,46 +40,53 @@
     }
 
     fun getDecision(subject: AccessUri, `object`: AccessUri): Int =
-        policy.getDecision(subject, `object`, state)
+        getState {
+            with(policy) { getDecision(subject, `object`) }
+        }
 
     fun setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
-        mutateState { oldState, newState ->
-            policy.setDecision(subject, `object`, decision, oldState, newState)
+        mutateState {
+            with(policy) { setDecision(subject, `object`, decision) }
         }
     }
 
     fun onUserAdded(userId: Int) {
-        mutateState { oldState, newState ->
-            policy.onUserAdded(userId, oldState, newState)
+        mutateState {
+            with(policy) { onUserAdded(userId) }
         }
     }
 
     fun onUserRemoved(userId: Int) {
-        mutateState { oldState, newState ->
-            policy.onUserRemoved(userId, oldState, newState)
+        mutateState {
+            with(policy) { onUserRemoved(userId) }
         }
     }
 
     fun onPackageAdded(packageState: PackageState) {
-        mutateState { oldState, newState ->
-            policy.onPackageAdded(packageState, oldState, newState)
+        mutateState {
+            with(policy) { onPackageAdded(packageState) }
         }
     }
 
     fun onPackageRemoved(packageState: PackageState) {
-        mutateState { oldState, newState ->
-            policy.onPackageRemoved(packageState, oldState, newState)
+        mutateState {
+            with(policy) { onPackageRemoved(packageState) }
         }
     }
 
-    // TODO: Replace (oldState, newState) with Kotlin context receiver once it's stabilized.
-    private inline fun mutateState(action: (oldState: AccessState, newState: AccessState) -> Unit) {
+    internal inline fun <T> getState(action: GetStateScope.() -> T): T =
+        GetStateScope(state).action()
+
+    internal inline fun mutateState(action: MutateStateScope.() -> Unit) {
         synchronized(stateLock) {
             val oldState = state
             val newState = oldState.copy()
-            action(oldState, newState)
+            MutateStateScope(oldState, newState).action()
             persistence.write(newState)
             state = newState
         }
     }
+
+    internal fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
+        policy.getSchemePolicy(subjectScheme, objectScheme)
 }
diff --git a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
index 0efc1bd..022f09a 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPersistence.kt
@@ -44,13 +44,13 @@
         systemFile.parse {
             // This is the canonical way to call an extension function in a different class.
             // TODO(b/259469752): Use context receiver for this when it becomes stable.
-            with(policy) { this@parse.parseSystemState(systemState) }
+            with(policy) { parseSystemState(systemState) }
         }
     }
 
     private fun readUserState(userId: Int, userState: UserState) {
         getUserFile(userId).parse {
-            with(policy) { this@parse.parseUserState(userId, userState) }
+            with(policy) { parseUserState(userId, userState) }
         }
     }
 
@@ -82,13 +82,13 @@
 
     private fun writeSystemState(systemState: SystemState) {
         systemFile.serialize {
-            with(policy) { this@serialize.serializeSystemState(systemState) }
+            with(policy) { serializeSystemState(systemState) }
         }
     }
 
     private fun writeUserState(userId: Int, userState: UserState) {
         getUserFile(userId).serialize {
-            with(policy) { this@serialize.serializeUserState(userId, userState) }
+            with(policy) { serializeUserState(userId, userState) }
         }
     }
 
diff --git a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
index 4e53ce0..e9741c6 100644
--- a/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessPolicy.kt
@@ -41,38 +41,35 @@
         }
     )
 
-    fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int =
-        getSchemePolicy(subject, `object`).getDecision(subject, `object`, state)
-
-    fun setDecision(
-        subject: AccessUri,
-        `object`: AccessUri,
-        decision: Int,
-        oldState: AccessState,
-        newState: AccessState
-    ) {
-        getSchemePolicy(subject, `object`)
-            .setDecision(subject, `object`, decision, oldState, newState)
-    }
-
-    private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
-        checkNotNull(schemePolicies[subject.scheme]?.get(`object`.scheme)) {
-            "Scheme policy for subject=$subject object=$`object` does not exist"
+    fun getSchemePolicy(subjectScheme: String, objectScheme: String): SchemePolicy =
+        checkNotNull(schemePolicies[subjectScheme]?.get(objectScheme)) {
+            "Scheme policy for $subjectScheme and $objectScheme does not exist"
         }
 
-    fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
+    fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int =
+        with(getSchemePolicy(subject, `object`)){ getDecision(subject, `object`) }
+
+    fun MutateStateScope.setDecision(subject: AccessUri, `object`: AccessUri, decision: Int) {
+        with(getSchemePolicy(subject, `object`)) { setDecision(subject, `object`, decision) }
+    }
+
+    fun MutateStateScope.onUserAdded(userId: Int) {
         newState.systemState.userIds += userId
         newState.userStates[userId] = UserState()
-        forEachSchemePolicy { it.onUserAdded(userId, oldState, newState) }
+        forEachSchemePolicy {
+            with(it) { onUserAdded(userId) }
+        }
     }
 
-    fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {
+    fun MutateStateScope.onUserRemoved(userId: Int) {
         newState.systemState.userIds -= userId
         newState.userStates -= userId
-        forEachSchemePolicy { it.onUserRemoved(userId, oldState, newState) }
+        forEachSchemePolicy {
+            with(it) { onUserRemoved(userId) }
+        }
     }
 
-    fun onPackageAdded(packageState: PackageState, oldState: AccessState, newState: AccessState) {
+    fun MutateStateScope.onPackageAdded(packageState: PackageState) {
         var isAppIdAdded = false
         newState.systemState.apply {
             packageStates[packageState.packageName] = packageState
@@ -82,12 +79,16 @@
             }.add(packageState.packageName)
         }
         if (isAppIdAdded) {
-            forEachSchemePolicy { it.onAppIdAdded(packageState.appId, oldState, newState) }
+            forEachSchemePolicy {
+                with(it) { onAppIdAdded(packageState.appId) }
+            }
         }
-        forEachSchemePolicy { it.onPackageAdded(packageState, oldState, newState) }
+        forEachSchemePolicy {
+            with(it) { onPackageAdded(packageState) }
+        }
     }
 
-    fun onPackageRemoved(packageState: PackageState, oldState: AccessState, newState: AccessState) {
+    fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
         var isAppIdRemoved = false
         newState.systemState.apply {
             packageStates -= packageState.packageName
@@ -101,9 +102,13 @@
                 }
             }
         }
-        forEachSchemePolicy { it.onPackageRemoved(packageState, oldState, newState) }
+        forEachSchemePolicy {
+            with(it) { onPackageRemoved(packageState) }
+        }
         if (isAppIdRemoved) {
-            forEachSchemePolicy { it.onAppIdRemoved(packageState.appId, oldState, newState) }
+            forEachSchemePolicy {
+                with(it) { onAppIdRemoved(packageState.appId) }
+            }
         }
     }
 
@@ -113,7 +118,7 @@
                 TAG_ACCESS -> {
                     forEachTag {
                         forEachSchemePolicy {
-                            with(it) { this@parseSystemState.parseSystemState(systemState) }
+                            with(it) { parseSystemState(systemState) }
                         }
                     }
                 }
@@ -125,7 +130,7 @@
     fun BinaryXmlSerializer.serializeSystemState(systemState: SystemState) {
         tag(TAG_ACCESS) {
             forEachSchemePolicy {
-                with(it) { this@serializeSystemState.serializeSystemState(systemState) }
+                with(it) { serializeSystemState(systemState) }
             }
         }
     }
@@ -136,7 +141,7 @@
                 TAG_ACCESS -> {
                     forEachTag {
                         forEachSchemePolicy {
-                            with(it) { this@parseUserState.parseUserState(userId, userState) }
+                            with(it) { parseUserState(userId, userState) }
                         }
                     }
                 }
@@ -153,11 +158,14 @@
     fun BinaryXmlSerializer.serializeUserState(userId: Int, userState: UserState) {
         tag(TAG_ACCESS) {
             forEachSchemePolicy {
-                with(it) { this@serializeUserState.serializeUserState(userId, userState) }
+                with(it) { serializeUserState(userId, userState) }
             }
         }
     }
 
+    private fun getSchemePolicy(subject: AccessUri, `object`: AccessUri): SchemePolicy =
+        getSchemePolicy(subject.scheme, `object`.scheme)
+
     private inline fun forEachSchemePolicy(action: (SchemePolicy) -> Unit) {
         schemePolicies.forEachValueIndexed { _, objectSchemePolicies ->
             objectSchemePolicies.forEachValueIndexed { _, schemePolicy ->
@@ -182,14 +190,12 @@
 
     abstract val objectScheme: String
 
-    abstract fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int
+    abstract fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int
 
-    abstract fun setDecision(
+    abstract fun MutateStateScope.setDecision(
         subject: AccessUri,
         `object`: AccessUri,
-        decision: Int,
-        oldState: AccessState,
-        newState: AccessState
+        decision: Int
     )
 
     fun addOnDecisionChangedListener(listener: OnDecisionChangedListener) {
@@ -216,25 +222,17 @@
         }
     }
 
-    open fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {}
+    open fun MutateStateScope.onUserAdded(userId: Int) {}
 
-    open fun onUserRemoved(userId: Int, oldState: AccessState, newState: AccessState) {}
+    open fun MutateStateScope.onUserRemoved(userId: Int) {}
 
-    open fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {}
+    open fun MutateStateScope.onAppIdAdded(appId: Int) {}
 
-    open fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {}
+    open fun MutateStateScope.onAppIdRemoved(appId: Int) {}
 
-    open fun onPackageAdded(
-        packageState: PackageState,
-        oldState: AccessState,
-        newState: AccessState
-    ) {}
+    open fun MutateStateScope.onPackageAdded(packageState: PackageState) {}
 
-    open fun onPackageRemoved(
-        packageState: PackageState,
-        oldState: AccessState,
-        newState: AccessState
-    ) {}
+    open fun MutateStateScope.onPackageRemoved(packageState: PackageState) {}
 
     open fun BinaryXmlPullParser.parseSystemState(systemState: SystemState) {}
 
diff --git a/services/permission/java/com/android/server/permission/access/AccessState.kt b/services/permission/java/com/android/server/permission/access/AccessState.kt
index f496dbd..cf8f383 100644
--- a/services/permission/java/com/android/server/permission/access/AccessState.kt
+++ b/services/permission/java/com/android/server/permission/access/AccessState.kt
@@ -124,3 +124,12 @@
         }
     }
 }
+
+class GetStateScope(
+    val state: AccessState
+)
+
+class MutateStateScope(
+    val oldState: AccessState,
+    val newState: AccessState
+)
diff --git a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
index 0b052f9..a1a5e2d 100644
--- a/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/BaseAppOpPolicy.kt
@@ -19,44 +19,43 @@
 import android.app.AppOpsManager
 import com.android.modules.utils.BinaryXmlPullParser
 import com.android.modules.utils.BinaryXmlSerializer
-import com.android.server.permission.access.AccessState
 import com.android.server.permission.access.AccessUri
 import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.SchemePolicy
 import com.android.server.permission.access.UserState
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
 
 abstract class BaseAppOpPolicy(private val persistence: BaseAppOpPersistence) : SchemePolicy() {
-    override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
+    override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
         `object` as AppOpUri
-        return getModes(subject, state)
+        return getModes(subject)
             .getWithDefault(`object`.appOpName, opToDefaultMode(`object`.appOpName))
     }
 
-    override fun setDecision(
+    override fun MutateStateScope.setDecision(
         subject: AccessUri,
         `object`: AccessUri,
-        decision: Int,
-        oldState: AccessState,
-        newState: AccessState
+        decision: Int
     ) {
         `object` as AppOpUri
-        val modes = getOrCreateModes(subject, newState)
+        val modes = getOrCreateModes(subject)
         val oldMode = modes.putWithDefault(`object`.appOpName, decision,
             opToDefaultMode(`object`.appOpName))
         if (modes.isEmpty()) {
-            removeModes(subject, newState)
+            removeModes(subject)
         }
         if (oldMode != decision) {
             notifyOnDecisionChangedListeners(subject, `object`, oldMode, decision)
         }
     }
 
-    abstract fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>?
+    abstract fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>?
 
-    abstract fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>
+    abstract fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int>
 
-    abstract fun removeModes(subject: AccessUri, state: AccessState)
+    abstract fun MutateStateScope.removeModes(subject: AccessUri)
 
     // TODO need to check that [AppOpsManager.getSystemAlertWindowDefault] works; likely no issue
     //  since running in system process.
diff --git a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
index 7c3c14c..966489f 100644
--- a/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/PackageAppOpPolicy.kt
@@ -16,9 +16,10 @@
 
 package com.android.server.permission.access.appop
 
-import com.android.server.permission.access.AccessState
 import com.android.server.permission.access.AccessUri
 import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.PackageUri
 import com.android.server.permission.access.UserState
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
@@ -31,27 +32,23 @@
     override val objectScheme: String
         get() = AppOpUri.SCHEME
 
-    override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
+    override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
         subject as PackageUri
         return state.userStates[subject.userId]?.packageAppOpModes?.get(subject.packageName)
     }
 
-    override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
+    override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
         subject as PackageUri
-        return state.userStates.getOrPut(subject.userId) { UserState() }
+        return newState.userStates.getOrPut(subject.userId) { UserState() }
             .packageAppOpModes.getOrPut(subject.packageName) { IndexedMap() }
     }
 
-    override fun removeModes(subject: AccessUri, state: AccessState) {
+    override fun MutateStateScope.removeModes(subject: AccessUri) {
         subject as PackageUri
-        state.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
+        newState.userStates[subject.userId]?.packageAppOpModes?.remove(subject.packageName)
     }
 
-    override fun onPackageRemoved(
-        packageState: PackageState,
-        oldState: AccessState,
-        newState: AccessState
-    ) {
+    override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
         newState.userStates.forEachIndexed { _, _, userState ->
             userState.packageAppOpModes -= packageState.packageName
         }
diff --git a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
index 26d0114..862db8f 100644
--- a/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/appop/UidAppOpPolicy.kt
@@ -16,9 +16,10 @@
 
 package com.android.server.permission.access.appop
 
-import com.android.server.permission.access.AccessState
 import com.android.server.permission.access.AccessUri
 import com.android.server.permission.access.AppOpUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.UidUri
 import com.android.server.permission.access.UserState
 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
@@ -30,23 +31,23 @@
     override val objectScheme: String
         get() = AppOpUri.SCHEME
 
-    override fun getModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int>? {
+    override fun GetStateScope.getModes(subject: AccessUri): IndexedMap<String, Int>? {
         subject as UidUri
         return state.userStates[subject.userId]?.uidAppOpModes?.get(subject.appId)
     }
 
-    override fun getOrCreateModes(subject: AccessUri, state: AccessState): IndexedMap<String, Int> {
+    override fun MutateStateScope.getOrCreateModes(subject: AccessUri): IndexedMap<String, Int> {
         subject as UidUri
-        return state.userStates.getOrPut(subject.userId) { UserState() }
+        return newState.userStates.getOrPut(subject.userId) { UserState() }
             .uidAppOpModes.getOrPut(subject.appId) { IndexedMap() }
     }
 
-    override fun removeModes(subject: AccessUri, state: AccessState) {
+    override fun MutateStateScope.removeModes(subject: AccessUri) {
         subject as UidUri
-        state.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
+        newState.userStates[subject.userId]?.uidAppOpModes?.remove(subject.appId)
     }
 
-    override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
+    override fun MutateStateScope.onAppIdRemoved(appId: Int) {
         newState.userStates.forEachIndexed { _, _, userState ->
             userState.uidAppOpModes -= appId
         }
diff --git a/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt b/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt
new file mode 100644
index 0000000..cc51866
--- /dev/null
+++ b/services/permission/java/com/android/server/permission/access/permission/ModernPermissionManagerServiceImpl.kt
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.permission.access.permission
+
+import android.content.pm.PackageManager
+import android.content.pm.PackageManagerInternal
+import android.content.pm.PermissionGroupInfo
+import android.content.pm.PermissionInfo
+import android.content.pm.permission.SplitPermissionInfoParcelable
+import android.os.Binder
+import android.os.Build
+import android.os.Process
+import android.os.UserHandle
+import android.permission.IOnPermissionsChangeListener
+import com.android.server.LocalManagerRegistry
+import com.android.server.LocalServices
+import com.android.server.pm.PackageManagerLocal
+import com.android.server.pm.permission.PermissionManagerServiceInterface
+import com.android.server.permission.access.AccessCheckingService
+import com.android.server.permission.access.PermissionUri
+import com.android.server.permission.access.UidUri
+import com.android.server.permission.access.data.Permission
+import com.android.server.permission.access.util.hasBits
+import com.android.server.pm.permission.LegacyPermission
+import com.android.server.pm.permission.LegacyPermissionSettings
+import com.android.server.pm.permission.LegacyPermissionState
+import com.android.server.pm.permission.PermissionManagerServiceInternal
+import com.android.server.pm.pkg.AndroidPackage
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * Modern implementation of [PermissionManagerServiceInterface].
+ */
+class ModernPermissionManagerServiceImpl(
+    private val service: AccessCheckingService
+) : PermissionManagerServiceInterface {
+    private val policy =
+        service.getSchemePolicy(UidUri.SCHEME, PermissionUri.SCHEME) as UidPermissionPolicy
+
+    private val packageManagerInternal =
+        LocalServices.getService(PackageManagerInternal::class.java)
+
+    private val packageManagerLocal =
+        LocalManagerRegistry.getManagerOrThrow(PackageManagerLocal::class.java)
+
+    override fun getAllPermissionGroups(flags: Int): List<PermissionGroupInfo> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getPermissionGroupInfo(
+        permissionGroupName: String,
+        flags: Int
+    ): PermissionGroupInfo? {
+        val permissionGroup: PermissionGroupInfo
+        packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
+            val callingUid = Binder.getCallingUid()
+            if (snapshot.isUidInstantApp(callingUid)) {
+                return null
+            }
+
+            permissionGroup = service.getState {
+                with(policy) { getPermissionGroup(permissionGroupName) }
+            } ?: return null
+
+            val isPermissionGroupVisible =
+                snapshot.isPackageVisibleToUid(permissionGroup.packageName, callingUid)
+            if (!isPermissionGroupVisible) {
+                return null
+            }
+        }
+
+        return permissionGroup.generatePermissionGroupInfo(flags)
+    }
+
+    /**
+     * Generate a new [PermissionGroupInfo] from [PermissionGroupInfo] and adjust it accordingly.
+     */
+    private fun PermissionGroupInfo.generatePermissionGroupInfo(flags: Int): PermissionGroupInfo =
+        @Suppress("DEPRECATION")
+        PermissionGroupInfo(this).apply {
+            if (!flags.hasBits(PackageManager.GET_META_DATA)) {
+                metaData = null
+            }
+        }
+
+    override fun getPermissionInfo(
+        permissionName: String,
+        flags: Int,
+        opPackageName: String
+    ): PermissionInfo? {
+        val permission: Permission
+        val targetSdkVersion: Int
+        packageManagerLocal.withUnfilteredSnapshot().use { snapshot ->
+            val callingUid = Binder.getCallingUid()
+            if (snapshot.isUidInstantApp(callingUid)) {
+                return null
+            }
+
+            permission = service.getState {
+                with(policy) { getPermission(permissionName) }
+            } ?: return null
+
+            val isPermissionVisible =
+                snapshot.isPackageVisibleToUid(permission.packageName, callingUid)
+            if (!isPermissionVisible) {
+                return null
+            }
+
+            val callingAppId = UserHandle.getAppId(callingUid)
+            val opPackage = snapshot.packageStates[opPackageName]?.androidPackage
+            targetSdkVersion = when {
+                // System sees all flags.
+                callingAppId == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID ||
+                    callingAppId == Process.SHELL_UID -> Build.VERSION_CODES.CUR_DEVELOPMENT
+                opPackage != null -> opPackage.targetSdkVersion
+                else -> Build.VERSION_CODES.CUR_DEVELOPMENT
+            }
+        }
+
+        return permission.generatePermissionInfo(flags, targetSdkVersion)
+    }
+
+    /**
+     * Generate a new [PermissionInfo] from [Permission] and adjust it accordingly.
+     */
+    private fun Permission.generatePermissionInfo(
+        flags: Int,
+        targetSdkVersion: Int
+    ): PermissionInfo =
+        @Suppress("DEPRECATION")
+        PermissionInfo(permissionInfo).apply {
+            if (!flags.hasBits(PackageManager.GET_META_DATA)) {
+                metaData = null
+            }
+            if (targetSdkVersion < Build.VERSION_CODES.O) {
+                val protection = protection
+                // Signature permission's protection flags are always reported.
+                if (protection != PermissionInfo.PROTECTION_SIGNATURE) {
+                    protectionLevel = protection
+                }
+            }
+        }
+
+    override fun queryPermissionsByGroup(
+        permissionGroupName: String,
+        flags: Int
+    ): List<PermissionInfo> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getAllPermissionsWithProtection(protection: Int): List<PermissionInfo> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getAllPermissionsWithProtectionFlags(protectionFlags: Int): List<PermissionInfo> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getPermissionGids(permissionName: String, userId: Int): IntArray {
+        TODO("Not yet implemented")
+    }
+
+    override fun addPermission(permissionInfo: PermissionInfo, async: Boolean): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun removePermission(permissionName: String) {
+        TODO("Not yet implemented")
+    }
+
+    override fun checkPermission(packageName: String, permissionName: String, userId: Int): Int {
+        TODO("Not yet implemented")
+    }
+
+    override fun checkUidPermission(uid: Int, permissionName: String): Int {
+        TODO("Not yet implemented")
+    }
+
+    override fun getGrantedPermissions(packageName: String, userId: Int): Set<String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun grantRuntimePermission(packageName: String, permissionName: String, userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun revokeRuntimePermission(
+        packageName: String,
+        permissionName: String,
+        userId: Int,
+        reason: String?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun revokePostNotificationPermissionWithoutKillForTest(
+        packageName: String,
+        userId: Int
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun addOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
+        TODO("Not yet implemented")
+    }
+
+    override fun removeOnPermissionsChangeListener(listener: IOnPermissionsChangeListener) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getPermissionFlags(packageName: String, permissionName: String, userId: Int): Int {
+        TODO("Not yet implemented")
+    }
+
+    override fun isPermissionRevokedByPolicy(
+        packageName: String,
+        permissionName: String,
+        userId: Int
+    ): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun isPermissionsReviewRequired(packageName: String, userId: Int): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun shouldShowRequestPermissionRationale(
+        packageName: String,
+        permissionName: String,
+        userId: Int
+    ): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun updatePermissionFlags(
+        packageName: String,
+        permissionName: String,
+        flagMask: Int,
+        flagValues: Int,
+        checkAdjustPolicyFlagPermission: Boolean,
+        userId: Int
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun updatePermissionFlagsForAllApps(flagMask: Int, flagValues: Int, userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun addAllowlistedRestrictedPermission(
+        packageName: String,
+        permissionName: String,
+        flags: Int,
+        userId: Int
+    ): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun getAllowlistedRestrictedPermissions(
+        packageName: String,
+        flags: Int,
+        userId: Int
+    ): MutableList<String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun removeAllowlistedRestrictedPermission(
+        packageName: String,
+        permissionName: String,
+        flags: Int,
+        userId: Int
+    ): Boolean {
+        TODO("Not yet implemented")
+    }
+
+    override fun resetRuntimePermissions(androidPackage: AndroidPackage, userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun resetRuntimePermissionsForUser(userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun addOnRuntimePermissionStateChangedListener(
+        listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun removeOnRuntimePermissionStateChangedListener(
+        listener: PermissionManagerServiceInternal.OnRuntimePermissionStateChangedListener
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getSplitPermissions(): List<SplitPermissionInfoParcelable> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getAppOpPermissionPackages(permissionName: String): Array<String> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getAllAppOpPermissionPackages(): Map<String, Set<String>> {
+        TODO("Not yet implemented")
+    }
+
+    override fun getGidsForUid(uid: Int): IntArray {
+        TODO("Not yet implemented")
+    }
+
+    override fun backupRuntimePermissions(userId: Int): ByteArray? {
+        TODO("Not yet implemented")
+    }
+
+    override fun restoreRuntimePermissions(backup: ByteArray, userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun restoreDelayedRuntimePermissions(packageName: String, userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>?) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getPermissionTEMP(
+        permissionName: String
+    ): com.android.server.pm.permission.Permission? {
+        TODO("Not yet implemented")
+    }
+
+    override fun getLegacyPermissions(): List<LegacyPermission> {
+        TODO("Not yet implemented")
+    }
+
+    override fun readLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
+        TODO("Not yet implemented")
+    }
+
+    override fun writeLegacyPermissionsTEMP(legacyPermissionSettings: LegacyPermissionSettings) {
+        TODO("Not yet implemented")
+    }
+
+    override fun getLegacyPermissionState(appId: Int): LegacyPermissionState {
+        TODO("Not yet implemented")
+    }
+
+    override fun readLegacyPermissionStateTEMP() {
+        TODO("Not yet implemented")
+    }
+
+    override fun writeLegacyPermissionStateTEMP() {
+        TODO("Not yet implemented")
+    }
+
+    override fun onSystemReady() {
+        TODO("Not yet implemented")
+    }
+
+    override fun onUserCreated(userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onUserRemoved(userId: Int) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onStorageVolumeMounted(volumeUuid: String, fingerprintChanged: Boolean) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onPackageAdded(
+        androidPackage: AndroidPackage,
+        isInstantApp: Boolean,
+        oldPackage: AndroidPackage?
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onPackageInstalled(
+        androidPackage: AndroidPackage,
+        previousAppId: Int,
+        params: PermissionManagerServiceInternal.PackageInstalledParams,
+        userId: Int
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onPackageUninstalled(
+        packageName: String,
+        appId: Int,
+        androidPackage: AndroidPackage?,
+        sharedUserPkgs: MutableList<AndroidPackage>,
+        userId: Int
+    ) {
+        TODO("Not yet implemented")
+    }
+
+    override fun onPackageRemoved(androidPackage: AndroidPackage) {
+        TODO("Not yet implemented")
+    }
+
+    /**
+     * Check whether a UID belongs to an instant app.
+     */
+    private fun PackageManagerLocal.UnfilteredSnapshot.isUidInstantApp(uid: Int): Boolean {
+        if (Process.isIsolatedUid(uid)) {
+            // Unfortunately we don't have the API for getting the owner UID of an isolated UID yet,
+            // so for now we just keep calling the old API.
+            return packageManagerInternal.getInstantAppPackageName(uid) != null
+        }
+        val appId = UserHandle.getAppId(uid)
+        // Instant apps can't have shared UIDs, so we can just take the first package.
+        val firstPackageState = packageStates.values.firstOrNull { it.appId == appId }
+            ?: return false
+        val userId = UserHandle.getUserId(uid)
+        return firstPackageState.getUserStateOrDefault(userId).isInstantApp
+    }
+
+    /**
+     * Check whether a package is visible to a UID within the same user as the UID.
+     */
+    private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
+        packageName: String,
+        uid: Int
+    ): Boolean = isPackageVisibleToUid(packageName, UserHandle.getUserId(uid), uid)
+
+    /**
+     * Check whether a package in a particular user is visible to a UID.
+     */
+    private fun PackageManagerLocal.UnfilteredSnapshot.isPackageVisibleToUid(
+        packageName: String,
+        userId: Int,
+        uid: Int
+    ): Boolean {
+        val user = UserHandle.of(userId)
+        return filtered(uid, user).use { it.getPackageState(packageName) != null }
+    }
+}
diff --git a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
index 6479e6a..e081924 100644
--- a/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
+++ b/services/permission/java/com/android/server/permission/access/permission/UidPermissionPolicy.kt
@@ -18,6 +18,7 @@
 
 import android.Manifest
 import android.content.pm.PackageManager
+import android.content.pm.PermissionGroupInfo
 import android.content.pm.PermissionInfo
 import android.os.Build
 import android.os.UserHandle
@@ -26,6 +27,8 @@
 import com.android.modules.utils.BinaryXmlSerializer
 import com.android.server.permission.access.AccessState
 import com.android.server.permission.access.AccessUri
+import com.android.server.permission.access.GetStateScope
+import com.android.server.permission.access.MutateStateScope
 import com.android.server.permission.access.PermissionUri
 import com.android.server.permission.access.SchemePolicy
 import com.android.server.permission.access.SystemState
@@ -52,19 +55,17 @@
     override val objectScheme: String
         get() = PermissionUri.SCHEME
 
-    override fun getDecision(subject: AccessUri, `object`: AccessUri, state: AccessState): Int {
+    override fun GetStateScope.getDecision(subject: AccessUri, `object`: AccessUri): Int {
         subject as UidUri
         `object` as PermissionUri
         return state.userStates[subject.userId]?.permissionFlags?.get(subject.appId)
             ?.get(`object`.permissionName) ?: 0
     }
 
-    override fun setDecision(
+    override fun MutateStateScope.setDecision(
         subject: AccessUri,
         `object`: AccessUri,
-        decision: Int,
-        oldState: AccessState,
-        newState: AccessState
+        decision: Int
     ) {
         subject as UidUri
         `object` as PermissionUri
@@ -73,64 +74,58 @@
         uidFlags[`object`.permissionName] = decision
     }
 
-    override fun onUserAdded(userId: Int, oldState: AccessState, newState: AccessState) {
+    override fun MutateStateScope.onUserAdded(userId: Int) {
         newState.systemState.packageStates.forEachValueIndexed { _, packageState ->
-            evaluateAllPermissionStatesForPackageAndUser(
-                packageState, null, userId, oldState, newState
-            )
-            grantImplicitPermissions(packageState, userId, oldState, newState)
+            evaluateAllPermissionStatesForPackageAndUser(packageState, null, userId)
+            grantImplicitPermissions(packageState, userId)
         }
     }
 
-    override fun onAppIdAdded(appId: Int, oldState: AccessState, newState: AccessState) {
+    override fun MutateStateScope.onAppIdAdded(appId: Int) {
         newState.userStates.forEachIndexed { _, _, userState ->
             userState.permissionFlags.getOrPut(appId) { IndexedMap() }
         }
     }
 
-    override fun onAppIdRemoved(appId: Int, oldState: AccessState, newState: AccessState) {
+    override fun MutateStateScope.onAppIdRemoved(appId: Int) {
         newState.userStates.forEachIndexed { _, _, userState -> userState.permissionFlags -= appId }
     }
 
-    override fun onPackageAdded(
-        packageState: PackageState,
-        oldState: AccessState,
-        newState: AccessState
-    ) {
+    override fun MutateStateScope.onPackageAdded(packageState: PackageState) {
         val changedPermissionNames = IndexedSet<String>()
-        adoptPermissions(packageState, changedPermissionNames, newState)
-        addPermissionGroups(packageState, newState)
-        addPermissions(packageState, changedPermissionNames, newState)
+        adoptPermissions(packageState, changedPermissionNames)
+        addPermissionGroups(packageState)
+        addPermissions(packageState, changedPermissionNames)
         // TODO: revokeStoragePermissionsIfScopeExpandedInternal()
-        trimPermissions(packageState.packageName, newState)
-        changedPermissionNames.forEachIndexed { _, it ->
-            evaluatePermissionStateForAllPackages(it, packageState, oldState, newState)
+        trimPermissions(packageState.packageName)
+        changedPermissionNames.forEachIndexed { _, permissionName ->
+            evaluatePermissionStateForAllPackages(permissionName, packageState)
         }
 
-        evaluateAllPermissionStatesForPackage(packageState, packageState, oldState, newState)
-        newState.systemState.userIds.forEachIndexed { _, it ->
-            grantImplicitPermissions(packageState, it, oldState, newState)
+        evaluateAllPermissionStatesForPackage(packageState, packageState)
+        newState.systemState.userIds.forEachIndexed { _, userId ->
+            grantImplicitPermissions(packageState, userId)
         }
 
         // TODO: add trimPermissionStates() here for removing the permission states that are
         // no longer requested. (equivalent to revokeUnusedSharedUserPermissionsLocked())
     }
 
-    private fun adoptPermissions(
+    private fun MutateStateScope.adoptPermissions(
         packageState: PackageState,
-        changedPermissionNames: IndexedSet<String>,
-        newState: AccessState
+        changedPermissionNames: IndexedSet<String>
     ) {
         val `package` = packageState.androidPackage!!
         `package`.adoptPermissions.forEachIndexed { _, originalPackageName ->
             val packageName = `package`.packageName
-            if (!canAdoptPermissions(packageName, originalPackageName, newState)) {
+            if (!canAdoptPermissions(packageName, originalPackageName)) {
                 return@forEachIndexed
             }
             newState.systemState.permissions.let { permissions ->
-                permissions.forEachIndexed { i, permissionName, oldPermission ->
+                permissions.forEachIndexed permissions@ {
+                    permissionIndex, permissionName, oldPermission ->
                     if (oldPermission.packageName != originalPackageName) {
-                        return@forEachIndexed
+                        return@permissions
                     }
                     @Suppress("DEPRECATION")
                     val newPermissionInfo = PermissionInfo().apply {
@@ -140,16 +135,15 @@
                     }
                     val newPermission = Permission(newPermissionInfo, false, oldPermission.type, 0)
                     changedPermissionNames += permissionName
-                    permissions.setValueAt(i, newPermission)
+                    permissions.setValueAt(permissionIndex, newPermission)
                 }
             }
         }
     }
 
-    private fun canAdoptPermissions(
+    private fun MutateStateScope.canAdoptPermissions(
         packageName: String,
-        originalPackageName: String,
-        newState: AccessState
+        originalPackageName: String
     ): Boolean {
         val originalPackageState = newState.systemState.packageStates[originalPackageName]
             ?: return false
@@ -170,7 +164,7 @@
         return true
     }
 
-    private fun addPermissionGroups(packageState: PackageState, newState: AccessState) {
+    private fun MutateStateScope.addPermissionGroups(packageState: PackageState) {
         // Different from the old implementation, which decides whether the app is an instant app by
         // the install flags, now for consistent behavior we allow adding permission groups if the
         // app is non-instant in at least one user.
@@ -202,10 +196,9 @@
         }
     }
 
-    private fun addPermissions(
+    private fun MutateStateScope.addPermissions(
         packageState: PackageState,
-        changedPermissionNames: IndexedSet<String>,
-        newState: AccessState
+        changedPermissionNames: IndexedSet<String>
     ) {
         packageState.androidPackage!!.permissions.forEachIndexed { _, parsedPermission ->
             // TODO:
@@ -229,7 +222,7 @@
             // Different from the old implementation, which may add an (incomplete) signature
             // permission inside another package's permission tree, we now consistently ignore such
             // permissions.
-            val permissionTree = getPermissionTree(permissionName, newState)
+            val permissionTree = getPermissionTree(permissionName)
             val newPackageName = newPermissionInfo.packageName
             if (permissionTree != null && newPackageName != permissionTree.packageName) {
                 Log.w(
@@ -294,10 +287,7 @@
         }
     }
 
-    private fun trimPermissions(
-        packageName: String,
-        newState: AccessState,
-    ) {
+    private fun MutateStateScope.trimPermissions(packageName: String) {
         val packageState = newState.systemState.packageStates[packageName]
         val androidPackage = packageState?.androidPackage
         if (packageState != null && androidPackage == null) {
@@ -314,20 +304,20 @@
         }
 
         newState.systemState.permissions.removeAllIndexed { i, permissionName, permission ->
-            val updatedPermission = updatePermissionIfDynamic(permission, newState)
+            val updatedPermission = updatePermissionIfDynamic(permission)
             newState.systemState.permissions.setValueAt(i, updatedPermission)
             if (updatedPermission.packageName == packageName && (
                 packageState == null || androidPackage!!.permissions.noneIndexed { _, it ->
                     !it.isTree && it.name == permissionName
                 }
             )) {
-                if (!isPermissionDeclaredByDisabledSystemPackage(permission, newState)) {
+                if (!isPermissionDeclaredByDisabledSystemPackage(permission)) {
                     newState.userStates.forEachIndexed { _, userId, userState ->
                         userState.permissionFlags.forEachKeyIndexed { _, appId ->
                             setPermissionFlags(
                                 appId, permissionName, getPermissionFlags(
-                                    appId, permissionName, userId, newState
-                                ) and PermissionFlags.INSTALL_REVOKED, userId, newState
+                                    appId, permissionName, userId
+                                ) and PermissionFlags.INSTALL_REVOKED, userId
                             )
                         }
                     }
@@ -339,9 +329,8 @@
         }
     }
 
-    private fun isPermissionDeclaredByDisabledSystemPackage(
-        permission: Permission,
-        newState: AccessState
+    private fun MutateStateScope.isPermissionDeclaredByDisabledSystemPackage(
+        permission: Permission
     ): Boolean {
         val disabledSystemPackage = newState.systemState
             .disabledSystemPackageStates[permission.packageName]?.androidPackage ?: return false
@@ -350,14 +339,11 @@
         }
     }
 
-    private fun updatePermissionIfDynamic(
-        permission: Permission,
-        newState: AccessState
-    ): Permission {
+    private fun MutateStateScope.updatePermissionIfDynamic(permission: Permission): Permission {
         if (!permission.isDynamic) {
             return permission
         }
-        val permissionTree = getPermissionTree(permission.name, newState) ?: return permission
+        val permissionTree = getPermissionTree(permission.name) ?: return permission
         @Suppress("DEPRECATION")
         return permission.copy(
             permissionInfo = PermissionInfo(permission.permissionInfo).apply {
@@ -366,7 +352,7 @@
         )
     }
 
-    private fun getPermissionTree(permissionName: String, newState: AccessState): Permission? =
+    private fun MutateStateScope.getPermissionTree(permissionName: String): Permission? =
         newState.systemState.permissionTrees.firstNotNullOfOrNullIndexed {
             _, permissionTreeName, permissionTree ->
             if (permissionName.startsWith(permissionTreeName) &&
@@ -378,58 +364,48 @@
             }
         }
 
-    private fun evaluatePermissionStateForAllPackages(
+    private fun MutateStateScope.evaluatePermissionStateForAllPackages(
         permissionName: String,
-        installedPackageState: PackageState?,
-        oldState: AccessState,
-        newState: AccessState
+        installedPackageState: PackageState?
     ) {
         newState.systemState.userIds.forEachIndexed { _, userId ->
             oldState.userStates[userId]?.permissionFlags?.forEachIndexed {
                 _, appId, permissionFlags ->
                 if (permissionName in permissionFlags) {
-                    evaluatePermissionState(
-                        appId, permissionName, installedPackageState, userId, oldState, newState
-                    )
+                    evaluatePermissionState(appId, permissionName, installedPackageState, userId)
                 }
             }
         }
     }
 
-    private fun evaluateAllPermissionStatesForPackage(
+    private fun MutateStateScope.evaluateAllPermissionStatesForPackage(
         packageState: PackageState,
-        installedPackageState: PackageState?,
-        oldState: AccessState,
-        newState: AccessState
+        installedPackageState: PackageState?
     ) {
         newState.systemState.userIds.forEachIndexed { _, userId ->
             evaluateAllPermissionStatesForPackageAndUser(
-                packageState, installedPackageState, userId, oldState, newState
+                packageState, installedPackageState, userId
             )
         }
     }
 
-    private fun evaluateAllPermissionStatesForPackageAndUser(
+    private fun MutateStateScope.evaluateAllPermissionStatesForPackageAndUser(
         packageState: PackageState,
         installedPackageState: PackageState?,
-        userId: Int,
-        oldState: AccessState,
-        newState: AccessState
+        userId: Int
     ) {
-        packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, it ->
+        packageState.androidPackage?.requestedPermissions?.forEachIndexed { _, permissionName ->
             evaluatePermissionState(
-                packageState.appId, it, installedPackageState, userId, oldState, newState
+                packageState.appId, permissionName, installedPackageState, userId
             )
         }
     }
 
-    private fun evaluatePermissionState(
+    private fun MutateStateScope.evaluatePermissionState(
         appId: Int,
         permissionName: String,
         installedPackageState: PackageState?,
-        userId: Int,
-        oldState: AccessState,
-        newState: AccessState
+        userId: Int
     ) {
         val packageNames = newState.systemState.appIds[appId]
         val hasMissingPackage = packageNames.anyIndexed { _, packageName ->
@@ -440,17 +416,17 @@
             return
         }
         val permission = newState.systemState.permissions[permissionName] ?: return
-        val oldFlags = getPermissionFlags(appId, permissionName, userId, newState)
+        val oldFlags = getPermissionFlags(appId, permissionName, userId)
         if (permission.isNormal) {
             val wasGranted = oldFlags.hasBits(PermissionFlags.INSTALL_GRANTED)
             if (!wasGranted) {
                 val wasRevoked = oldFlags.hasBits(PermissionFlags.INSTALL_REVOKED)
                 val isRequestedByInstalledPackage = installedPackageState != null &&
                     permissionName in installedPackageState.androidPackage!!.requestedPermissions
-                val isRequestedBySystemPackage = anyPackageInAppId(appId, newState) {
+                val isRequestedBySystemPackage = anyPackageInAppId(appId) {
                     it.isSystem && permissionName in it.androidPackage!!.requestedPermissions
                 }
-                val isCompatibilityPermission = anyPackageInAppId(appId, newState) {
+                val isCompatibilityPermission = anyPackageInAppId(appId) {
                     isCompatibilityPermissionForPackage(it.androidPackage!!, permissionName)
                 }
                 // If this is an existing, non-system package,
@@ -462,7 +438,7 @@
                 } else {
                     PermissionFlags.INSTALL_REVOKED
                 }
-                setPermissionFlags(appId, permissionName, newFlags, userId, newState)
+                setPermissionFlags(appId, permissionName, newFlags, userId)
             }
         } else if (permission.isSignature || permission.isInternal) {
             val wasProtectionGranted = oldFlags.hasBits(PermissionFlags.PROTECTION_GRANTED)
@@ -471,17 +447,17 @@
                 PermissionFlags.PROTECTION_GRANTED
             } else {
                 val mayGrantByPrivileged = !permission.isPrivileged || (
-                    anyPackageInAppId(appId, newState) {
-                        checkPrivilegedPermissionAllowlist(it, permission, newState)
+                    anyPackageInAppId(appId) {
+                        checkPrivilegedPermissionAllowlist(it, permission)
                     }
                 )
                 val shouldGrantBySignature = permission.isSignature && (
-                    anyPackageInAppId(appId, newState) {
-                        shouldGrantPermissionBySignature(it, permission, newState)
+                    anyPackageInAppId(appId) {
+                        shouldGrantPermissionBySignature(it, permission)
                     }
                 )
-                val shouldGrantByProtectionFlags = anyPackageInAppId(appId, newState) {
-                    shouldGrantPermissionByProtectionFlags(it, permission, newState)
+                val shouldGrantByProtectionFlags = anyPackageInAppId(appId) {
+                    shouldGrantPermissionByProtectionFlags(it, permission)
                 }
                 if (mayGrantByPrivileged &&
                     (shouldGrantBySignature || shouldGrantByProtectionFlags)) {
@@ -501,7 +477,7 @@
             if (permission.isRole) {
                 newFlags = newFlags or (oldFlags and PermissionFlags.ROLE_GRANTED)
             }
-            setPermissionFlags(appId, permissionName, newFlags, userId, newState)
+            setPermissionFlags(appId, permissionName, newFlags, userId)
         } else if (permission.isRuntime) {
             // TODO: add runtime permissions
         } else {
@@ -513,12 +489,7 @@
         // TODO: revokePermissionsNoLongerImplicitLocked() for runtime permissions
     }
 
-    private fun grantImplicitPermissions(
-        packageState: PackageState,
-        userId: Int,
-        oldState: AccessState,
-        newState: AccessState
-    ) {
+    private fun MutateStateScope.grantImplicitPermissions(packageState: PackageState, userId: Int) {
         val appId = packageState.appId
         val androidPackage = packageState.androidPackage ?: return
         androidPackage.implicitPermissions.forEachIndexed implicitPermissions@ {
@@ -530,6 +501,7 @@
             if (!implicitPermission.isRuntime) {
                 return@implicitPermissions
             }
+            // Explicitly check against the old state to determine if this permission is new.
             val isNewPermission = getPermissionFlags(
                 appId, implicitPermissionName, userId, oldState
             ) == 0
@@ -544,7 +516,7 @@
                 checkNotNull(sourcePermission) {
                     "Unknown source permission $sourcePermissionName in split permissions"
                 }
-                val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId, newState)
+                val sourceFlags = getPermissionFlags(appId, sourcePermissionName, userId)
                 val isSourceGranted = sourceFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
                 val isNewGranted = newFlags.hasAnyBit(PermissionFlags.MASK_GRANTED)
                 val isGrantingNewFromRevoke = isSourceGranted && !isNewGranted
@@ -559,23 +531,22 @@
                 }
             }
             newFlags = newFlags or PermissionFlags.IMPLICIT
-            setPermissionFlags(appId, implicitPermissionName, newFlags, userId, newState)
+            setPermissionFlags(appId, implicitPermissionName, newFlags, userId)
         }
     }
 
-    private fun getPermissionFlags(
+    private fun MutateStateScope.getPermissionFlags(
         appId: Int,
         permissionName: String,
         userId: Int,
-        state: AccessState
+        state: AccessState = newState
     ): Int = state.userStates[userId].permissionFlags[appId].getWithDefault(permissionName, 0)
 
-    private fun setPermissionFlags(
+    private fun MutateStateScope.setPermissionFlags(
         appId: Int,
         permissionName: String,
         flags: Int,
-        userId: Int,
-        newState: AccessState
+        userId: Int
     ) {
         newState.userStates[userId].permissionFlags[appId]!!
             .putWithDefault(permissionName, flags, 0)
@@ -585,8 +556,9 @@
         androidPackage: AndroidPackage,
         permissionName: String
     ): Boolean {
-        for (info: CompatibilityPermissionInfo in CompatibilityPermissionInfo.COMPAT_PERMS) {
-            if (info.name == permissionName && androidPackage.targetSdkVersion < info.sdkVersion) {
+        for (compatibilityPermission in CompatibilityPermissionInfo.COMPAT_PERMS) {
+            if (compatibilityPermission.name == permissionName &&
+                androidPackage.targetSdkVersion < compatibilityPermission.sdkVersion) {
                 Log.i(
                     LOG_TAG, "Auto-granting $permissionName to old package" +
                     " ${androidPackage.packageName}"
@@ -597,10 +569,9 @@
         return false
     }
 
-    private fun shouldGrantPermissionBySignature(
+    private fun MutateStateScope.shouldGrantPermissionBySignature(
         packageState: PackageState,
-        permission: Permission,
-        newState: AccessState
+        permission: Permission
     ): Boolean {
         // check if the package is allow to use this signature permission.  A package is allowed to
         // use a signature permission if:
@@ -622,10 +593,9 @@
                     SigningDetails.CertCapabilities.PERMISSION)
     }
 
-    private fun checkPrivilegedPermissionAllowlist(
+    private fun MutateStateScope.checkPrivilegedPermissionAllowlist(
         packageState: PackageState,
-        permission: Permission,
-        newState: AccessState
+        permission: Permission
     ): Boolean {
         if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE) {
             return true
@@ -641,10 +611,10 @@
             newState.systemState.privilegedPermissionAllowlistSourcePackageNames) {
             return true
         }
-        if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name, newState)) {
+        if (isInSystemConfigPrivAppPermissions(androidPackage, permission.name)) {
             return true
         }
-        if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name, newState)) {
+        if (isInSystemConfigPrivAppDenyPermissions(androidPackage, permission.name)) {
             return false
         }
         // Updated system apps do not need to be allowlisted
@@ -655,10 +625,9 @@
         return !RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE
     }
 
-    private fun isInSystemConfigPrivAppPermissions(
+    private fun MutateStateScope.isInSystemConfigPrivAppPermissions(
         androidPackage: AndroidPackage,
-        permissionName: String,
-        newState: AccessState
+        permissionName: String
     ): Boolean {
         val apexModuleName = androidPackage.apexModuleName
         val systemState = newState.systemState
@@ -682,10 +651,9 @@
         return permissionNames?.contains(permissionName) == true
     }
 
-    private fun isInSystemConfigPrivAppDenyPermissions(
+    private fun MutateStateScope.isInSystemConfigPrivAppDenyPermissions(
         androidPackage: AndroidPackage,
-        permissionName: String,
-        newState: AccessState
+        permissionName: String
     ): Boolean {
         // Different from the previous implementation, which may incorrectly use the APEX package
         // name, we now use the APEX module name to be consistent with the allowlist.
@@ -713,22 +681,21 @@
         return permissionNames?.contains(permissionName) == true
     }
 
-    private fun anyPackageInAppId(
+    private fun MutateStateScope.anyPackageInAppId(
         appId: Int,
-        newState: AccessState,
+        state: AccessState = newState,
         predicate: (PackageState) -> Boolean
     ): Boolean {
-        val packageNames = newState.systemState.appIds[appId]
+        val packageNames = state.systemState.appIds[appId]
         return packageNames.anyIndexed { _, packageName ->
-            val packageState = newState.systemState.packageStates[packageName]!!
+            val packageState = state.systemState.packageStates[packageName]!!
             packageState.androidPackage != null && predicate(packageState)
         }
     }
 
-    private fun shouldGrantPermissionByProtectionFlags(
+    private fun MutateStateScope.shouldGrantPermissionByProtectionFlags(
         packageState: PackageState,
-        permission: Permission,
-        newState: AccessState
+        permission: Permission
     ): Boolean {
         val androidPackage = packageState.androidPackage!!
         val knownPackages = newState.systemState.knownPackages
@@ -741,11 +708,9 @@
                     .disabledSystemPackageStates[packageState.packageName]?.androidPackage
                 disabledSystemPackage != null &&
                     permission.name in disabledSystemPackage.requestedPermissions &&
-                    shouldGrantPrivilegedOrOemPermission(
-                        disabledSystemPackage, permission, newState
-                    )
+                    shouldGrantPrivilegedOrOemPermission(disabledSystemPackage, permission)
             } else {
-                shouldGrantPrivilegedOrOemPermission(androidPackage, permission, newState)
+                shouldGrantPrivilegedOrOemPermission(androidPackage, permission)
             }
             if (shouldGrant) {
                 return true
@@ -815,7 +780,7 @@
         }
         if (permission.isRetailDemo &&
             packageName in knownPackages[KnownPackages.PACKAGE_RETAIL_DEMO] &&
-            isDeviceOrProfileOwnerUid(packageState.appId, newState)) {
+            isDeviceOrProfileOwnerUid(packageState.appId)) {
             // Special permission granted only to the OEM specified retail demo app.
             // Note that the original code was passing app ID as UID, so this behavior is kept
             // unchanged.
@@ -829,10 +794,9 @@
         return false
     }
 
-    private fun shouldGrantPrivilegedOrOemPermission(
+    private fun MutateStateScope.shouldGrantPrivilegedOrOemPermission(
         androidPackage: AndroidPackage,
-        permission: Permission,
-        state: AccessState
+        permission: Permission
     ): Boolean {
         val permissionName = permission.name
         val packageName = androidPackage.packageName
@@ -855,7 +819,7 @@
             }
             permission.isOem -> {
                 if (androidPackage.isOem) {
-                    val isOemAllowlisted = state.systemState
+                    val isOemAllowlisted = newState.systemState
                         .oemPermissions[packageName]?.get(permissionName)
                     checkNotNull(isOemAllowlisted) {
                         "OEM permission $permissionName requested by package" +
@@ -868,19 +832,15 @@
         return false
     }
 
-    private fun isDeviceOrProfileOwnerUid(uid: Int, state: AccessState): Boolean {
+    private fun MutateStateScope.isDeviceOrProfileOwnerUid(uid: Int): Boolean {
         val userId = UserHandle.getUserId(uid)
-        val ownerPackageName = state.systemState.deviceAndProfileOwners[userId] ?: return false
-        val ownerPackageState = state.systemState.packageStates[ownerPackageName] ?: return false
+        val ownerPackageName = newState.systemState.deviceAndProfileOwners[userId] ?: return false
+        val ownerPackageState = newState.systemState.packageStates[ownerPackageName] ?: return false
         val ownerUid = UserHandle.getUid(userId, ownerPackageState.appId)
         return uid == ownerUid
     }
 
-    override fun onPackageRemoved(
-        packageState: PackageState,
-        oldState: AccessState,
-        newState: AccessState
-    ) {
+    override fun MutateStateScope.onPackageRemoved(packageState: PackageState) {
         // TODO
     }
 
@@ -892,6 +852,12 @@
         with(persistence) { this@serializeSystemState.serializeSystemState(systemState) }
     }
 
+    fun GetStateScope.getPermissionGroup(permissionGroupName: String): PermissionGroupInfo? =
+        state.systemState.permissionGroups[permissionGroupName]
+
+    fun GetStateScope.getPermission(permissionName: String): Permission? =
+        state.systemState.permissions[permissionName]
+
     companion object {
         private val LOG_TAG = UidPermissionPolicy::class.java.simpleName
 
diff --git a/services/proguard.flags b/services/proguard.flags
index 27fe505..6cdf11c 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -88,6 +88,7 @@
 -keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.GnssPowerStats { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.server.location.gnss.hal.GnssNative { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.server.pm.PackageManagerShellCommandDataLoader { *; }
+-keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$RuntimeSensorStateChangeCallback { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorManagerInternal$ProximityActiveListener { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.server.sensors.SensorService { *; }
 -keep,allowoptimization,allowaccessmodification class com.android.server.soundtrigger_middleware.SoundTriggerMiddlewareImpl$AudioSessionProvider$AudioSession { *; }
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 298cbf3..6af7269 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -74,6 +74,7 @@
 import android.app.Application;
 import android.app.IBackupAgent;
 import android.app.backup.BackupAgent;
+import android.app.backup.BackupAnnotations;
 import android.app.backup.BackupDataInput;
 import android.app.backup.BackupDataOutput;
 import android.app.backup.BackupManager;
@@ -183,7 +184,7 @@
     private static final String BACKUP_AGENT_SHARED_PREFS_SYNCHRONIZER_CLASS =
             "android.app.backup.BackupAgent$SharedPrefsSynchronizer";
     private static final int USER_ID = 10;
-    private static final int OPERATION_TYPE = BackupManager.OperationType.BACKUP;
+    private static final int BACKUP_DESTINATION = BackupAnnotations.BackupDestination.CLOUD;
 
     @Mock private TransportManager mTransportManager;
     @Mock private DataChangedJournal mOldJournal;
@@ -264,7 +265,8 @@
         LocalServices.removeServiceForTest(PackageManagerInternal.class);
         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
         mBackupEligibilityRules = new BackupEligibilityRules(mPackageManager,
-                LocalServices.getService(PackageManagerInternal.class), USER_ID, OPERATION_TYPE);
+                LocalServices.getService(PackageManagerInternal.class), USER_ID,
+                BACKUP_DESTINATION);
     }
 
     @After
diff --git a/services/tests/InputMethodSystemServerTests/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
index 12e7cfc..212ec14 100644
--- a/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/AndroidManifest.xml
@@ -18,6 +18,11 @@
           package="com.android.frameworks.inputmethodtests">
 
     <uses-sdk android:targetSdkVersion="31" />
+    <queries>
+        <intent>
+            <action android:name="android.view.InputMethod" />
+        </intent>
+    </queries>
 
     <!-- Permissions required for granting and logging -->
     <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
@@ -29,9 +34,23 @@
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
 
+    <uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
+    <uses-permission android:name="android.permission.BIND_INPUT_METHOD" />
+
     <application android:testOnly="true"
                  android:debuggable="true">
         <uses-library android:name="android.test.runner" />
+        <service android:name="com.android.server.inputmethod.InputMethodBindingControllerTest$EmptyInputMethodService"
+                 android:label="Empty IME"
+                 android:permission="android.permission.BIND_INPUT_METHOD"
+                 android:process=":service"
+                 android:exported="true">
+            <intent-filter>
+                <action android:name="android.view.InputMethod"/>
+            </intent-filter>
+            <meta-data android:name="android.view.im"
+                       android:resource="@xml/method"/>
+        </service>
     </application>
 
     <instrumentation
diff --git a/services/tests/InputMethodSystemServerTests/res/xml/method.xml b/services/tests/InputMethodSystemServerTests/res/xml/method.xml
new file mode 100644
index 0000000..89b06bb
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/res/xml/method.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<input-method xmlns:android="http://schemas.android.com/apk/res/android" />
\ No newline at end of file
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java
new file mode 100644
index 0000000..42d373b
--- /dev/null
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/InputMethodBindingControllerTest.java
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.inputmethod;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.inputmethodservice.InputMethodService;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.view.inputmethod.InputMethodInfo;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.inputmethod.InputBindResult;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@RunWith(AndroidJUnit4.class)
+public class InputMethodBindingControllerTest extends InputMethodManagerServiceTestBase {
+
+    private static final String PACKAGE_NAME = "com.android.frameworks.inputmethodtests";
+    private static final String TEST_SERVICE_NAME =
+            "com.android.server.inputmethod.InputMethodBindingControllerTest"
+                    + "$EmptyInputMethodService";
+    private static final String TEST_IME_ID = PACKAGE_NAME + "/" + TEST_SERVICE_NAME;
+    private static final long TIMEOUT_IN_SECONDS = 3;
+
+    private InputMethodBindingController mBindingController;
+    private Instrumentation mInstrumentation;
+    private final int mImeConnectionBindFlags =
+            InputMethodBindingController.IME_CONNECTION_BIND_FLAGS
+                    & ~Context.BIND_SCHEDULE_LIKE_TOP_APP;
+    private CountDownLatch mCountDownLatch;
+
+    public static class EmptyInputMethodService extends InputMethodService {}
+
+    @Before
+    public void setUp() throws RemoteException {
+        super.setUp();
+        mInstrumentation = InstrumentationRegistry.getInstrumentation();
+        mCountDownLatch = new CountDownLatch(1);
+        // Remove flag Context.BIND_SCHEDULE_LIKE_TOP_APP because in tests we are not calling
+        // from system.
+        mBindingController =
+                new InputMethodBindingController(
+                        mInputMethodManagerService, mImeConnectionBindFlags, mCountDownLatch);
+    }
+
+    @Test
+    public void testBindCurrentMethod_noIme() {
+        synchronized (ImfLock.class) {
+            mBindingController.setSelectedMethodId(null);
+            InputBindResult result = mBindingController.bindCurrentMethod();
+            assertThat(result).isEqualTo(InputBindResult.NO_IME);
+        }
+    }
+
+    @Test
+    public void testBindCurrentMethod_unknownId() {
+        synchronized (ImfLock.class) {
+            mBindingController.setSelectedMethodId("unknown ime id");
+        }
+        assertThrows(IllegalArgumentException.class, () -> {
+            synchronized (ImfLock.class) {
+                mBindingController.bindCurrentMethod();
+            }
+        });
+    }
+
+    @Test
+    public void testBindCurrentMethod_notConnected() {
+        synchronized (ImfLock.class) {
+            mBindingController.setSelectedMethodId(TEST_IME_ID);
+            doReturn(false)
+                    .when(mContext)
+                    .bindServiceAsUser(
+                            any(Intent.class),
+                            any(ServiceConnection.class),
+                            anyInt(),
+                            any(UserHandle.class));
+
+            InputBindResult result = mBindingController.bindCurrentMethod();
+            assertThat(result).isEqualTo(InputBindResult.IME_NOT_CONNECTED);
+        }
+    }
+
+    @Test
+    public void testBindAndUnbindMethod() throws Exception {
+        // Bind with main connection
+        testBindCurrentMethodWithMainConnection();
+
+        // Bind with visible connection
+        testBindCurrentMethodWithVisibleConnection();
+
+        // Unbind both main and visible connections
+        testUnbindCurrentMethod();
+    }
+
+    private void testBindCurrentMethodWithMainConnection() throws Exception {
+        synchronized (ImfLock.class) {
+            mBindingController.setSelectedMethodId(TEST_IME_ID);
+        }
+        InputMethodInfo info = mInputMethodManagerService.mMethodMap.get(TEST_IME_ID);
+        assertThat(info).isNotNull();
+        assertThat(info.getId()).isEqualTo(TEST_IME_ID);
+        assertThat(info.getServiceName()).isEqualTo(TEST_SERVICE_NAME);
+
+        // Bind input method with main connection. It is called on another thread because we should
+        // wait for onServiceConnected() to finish.
+        InputBindResult result = callOnMainSync(() -> {
+            synchronized (ImfLock.class) {
+                return mBindingController.bindCurrentMethod();
+            }
+        });
+
+        verify(mContext, times(1))
+                .bindServiceAsUser(
+                        any(Intent.class),
+                        any(ServiceConnection.class),
+                        eq(mImeConnectionBindFlags),
+                        any(UserHandle.class));
+        assertThat(result.result).isEqualTo(InputBindResult.ResultCode.SUCCESS_WAITING_IME_BINDING);
+        assertThat(result.id).isEqualTo(info.getId());
+        synchronized (ImfLock.class) {
+            assertThat(mBindingController.hasConnection()).isTrue();
+            assertThat(mBindingController.getCurId()).isEqualTo(info.getId());
+            assertThat(mBindingController.getCurToken()).isNotNull();
+        }
+        // Wait for onServiceConnected()
+        mCountDownLatch.await(TIMEOUT_IN_SECONDS, TimeUnit.SECONDS);
+
+        // Verify onServiceConnected() is called and bound successfully.
+        synchronized (ImfLock.class) {
+            assertThat(mBindingController.getCurMethod()).isNotNull();
+            assertThat(mBindingController.getCurMethodUid()).isNotEqualTo(Process.INVALID_UID);
+        }
+    }
+
+    private void testBindCurrentMethodWithVisibleConnection() {
+        mInstrumentation.runOnMainSync(() -> {
+            synchronized (ImfLock.class) {
+                mBindingController.setCurrentMethodVisible();
+            }
+        });
+        // Bind input method with visible connection
+        verify(mContext, times(1))
+                .bindServiceAsUser(
+                        any(Intent.class),
+                        any(ServiceConnection.class),
+                        eq(InputMethodBindingController.IME_VISIBLE_BIND_FLAGS),
+                        any(UserHandle.class));
+        synchronized (ImfLock.class) {
+            assertThat(mBindingController.isVisibleBound()).isTrue();
+        }
+    }
+
+    private void testUnbindCurrentMethod() {
+        mInstrumentation.runOnMainSync(() -> {
+            synchronized (ImfLock.class) {
+                mBindingController.unbindCurrentMethod();
+            }
+        });
+
+        synchronized (ImfLock.class) {
+            // Unbind both main connection and visible connection
+            assertThat(mBindingController.hasConnection()).isFalse();
+            assertThat(mBindingController.isVisibleBound()).isFalse();
+            verify(mContext, times(2)).unbindService(any(ServiceConnection.class));
+            assertThat(mBindingController.getCurToken()).isNull();
+            assertThat(mBindingController.getCurId()).isNull();
+            assertThat(mBindingController.getCurMethod()).isNull();
+            assertThat(mBindingController.getCurMethodUid()).isEqualTo(Process.INVALID_UID);
+        }
+    }
+
+    private static <V> V callOnMainSync(Callable<V> callable) {
+        AtomicReference<V> result = new AtomicReference<>();
+        InstrumentationRegistry.getInstrumentation()
+                .runOnMainSync(
+                        () -> {
+                            try {
+                                result.set(callable.call());
+                            } catch (Exception e) {
+                                throw new RuntimeException("Exception was thrown", e);
+                            }
+                        });
+        return result.get();
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayPathsUninstallSystemUpdatesTest.kt b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayPathsUninstallSystemUpdatesTest.kt
new file mode 100644
index 0000000..4044780
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/src/com/android/server/pm/test/OverlayPathsUninstallSystemUpdatesTest.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.pm.test
+
+import com.android.internal.util.test.SystemPreparer
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.ClassRule
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.RuleChain
+import org.junit.rules.TemporaryFolder
+import org.junit.runner.RunWith
+
+@RunWith(DeviceJUnit4ClassRunner::class)
+class OverlayPathsUninstallSystemUpdatesTest : BaseHostJUnit4Test() {
+
+    companion object {
+        private const val TEST_PKG_NAME = "com.android.server.pm.test.test_app"
+        private const val VERSION_ONE = "PackageManagerTestAppVersion1.apk"
+        private const val VERSION_TWO = "PackageManagerTestAppVersion2.apk"
+
+        @get:ClassRule
+        val deviceRebootRule = SystemPreparer.TestRuleDelegate(true)
+    }
+
+    private val tempFolder = TemporaryFolder()
+    private val preparer: SystemPreparer = SystemPreparer(tempFolder,
+            SystemPreparer.RebootStrategy.FULL, deviceRebootRule, true) { this.device }
+
+    @Rule
+    @JvmField
+    val rules = RuleChain.outerRule(tempFolder).around(preparer)!!
+    private val filePath = HostUtils.makePathForApk("PackageManagerTestApp.apk", Partition.PRODUCT)
+
+    @Before
+    @After
+    fun removeApk() {
+        device.uninstallPackage(TEST_PKG_NAME)
+    }
+
+    @Test
+    fun verify() {
+        // First, push a system app to the device and then update it so there's a data variant
+        preparer.pushResourceFile(VERSION_ONE, filePath.toString())
+                .reboot()
+
+        val versionTwoFile = HostUtils.copyResourceToHostFile(VERSION_TWO, tempFolder.newFile())
+
+        assertThat(device.installPackage(versionTwoFile, true)).isNull()
+
+        device.executeShellCommand(
+                "cmd overlay fabricate --target-name TestResources" +
+                " --target $TEST_PKG_NAME" +
+                " --name UninstallSystemUpdatesTest" +
+                " $TEST_PKG_NAME:color/overlay_test 0x1C 0xFFFFFFFF"
+        )
+
+        device.executeShellCommand(
+                "cmd overlay enable --user 0 com.android.shell:UninstallSystemUpdatesTest"
+        )
+
+        fun verifyValueOverlaid() {
+            assertThat(device.executeShellCommand(
+                    "cmd overlay lookup --user 0 $TEST_PKG_NAME $TEST_PKG_NAME:color/overlay_test"
+            ).trim()).isEqualTo("#ffffffff")
+        }
+
+        verifyValueOverlaid()
+
+        assertThat(
+                device.executeShellCommand("pm uninstall-system-updates $TEST_PKG_NAME"
+        ).trim()).endsWith("Success")
+
+        // Wait for paths to re-propagate. This doesn't do a retry loop in case the path clear also
+        // has some latency. There must be some minimum wait time for the paths to settle, and then
+        // a wait time for the paths to re-propagate. Rather than complicate the logic, just wait
+        // a long enough time for both events to occur.
+        Thread.sleep(5000)
+
+        verifyValueOverlaid()
+    }
+}
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/colors.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/colors.xml
new file mode 100644
index 0000000..5a41d88
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/colors.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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="overlay_test">#FF000000</color>
+</resources>
diff --git a/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/overlayable.xml b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/overlayable.xml
new file mode 100644
index 0000000..c5ba450
--- /dev/null
+++ b/services/tests/PackageManagerServiceTests/host/test-apps/Generic/res/values/overlayable.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT 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>
+    <overlayable name="TestResources">
+        <policy type="public">
+            <item type="color" name="overlay_test" />
+        </policy>
+    </overlayable>
+</resources>
diff --git a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageParserTest.java b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageParserTest.java
index 59f27ec..c8e2676 100644
--- a/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageParserTest.java
+++ b/services/tests/PackageManagerServiceTests/server/src/com/android/server/PackageParserTest.java
@@ -334,7 +334,7 @@
     }
 
     @Test
-    public void testParseActivityTargetDisplayCategoryValid() throws Exception {
+    public void testParseActivityRequiredDisplayCategoryValid() throws Exception {
         final File testFile = extractFile(TEST_APP4_APK);
         String actualDisplayCategory = null;
         try {
@@ -342,7 +342,7 @@
             final List<ParsedActivity> activities = pkg.getActivities();
             for (ParsedActivity activity : activities) {
                 if ((PACKAGE_NAME + ".MyActivity").equals(activity.getName())) {
-                    actualDisplayCategory = activity.getTargetDisplayCategory();
+                    actualDisplayCategory = activity.getRequiredDisplayCategory();
                 }
             }
         } finally {
@@ -352,7 +352,7 @@
     }
 
     @Test
-    public void testParseActivityTargetDisplayCategoryInvalid() throws Exception {
+    public void testParseActivityRequiredDisplayCategoryInvalid() throws Exception {
         final File testFile = extractFile(TEST_APP6_APK);
         String actualDisplayCategory = null;
         try {
@@ -360,12 +360,12 @@
             final List<ParsedActivity> activities = pkg.getActivities();
             for (ParsedActivity activity : activities) {
                 if ((PACKAGE_NAME + ".MyActivity").equals(activity.getName())) {
-                    actualDisplayCategory = activity.getTargetDisplayCategory();
+                    actualDisplayCategory = activity.getRequiredDisplayCategory();
                 }
             }
         } catch (PackageManagerException e) {
             assertThat(e.getMessage()).contains(
-                    "targetDisplayCategory attribute can only consists"
+                    "requiredDisplayCategory attribute can only consist"
                             + " of alphanumeric characters, '_', and '.'");
         } finally {
             testFile.delete();
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
index 1f66a11..7bf9a9e 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/AndroidPackageTest.kt
@@ -17,7 +17,12 @@
 package com.android.server.pm.test.parsing.parcelling
 
 import android.content.Intent
-import android.content.pm.*
+import android.content.pm.ApplicationInfo
+import android.content.pm.ConfigurationInfo
+import android.content.pm.FeatureGroupInfo
+import android.content.pm.FeatureInfo
+import android.content.pm.PackageManager
+import android.content.pm.SigningDetails
 import android.net.Uri
 import android.os.Bundle
 import android.os.Parcelable
@@ -27,16 +32,32 @@
 import com.android.internal.R
 import com.android.server.pm.parsing.pkg.PackageImpl
 import com.android.server.pm.pkg.AndroidPackage
-import com.android.server.pm.pkg.component.*
+import com.android.server.pm.pkg.component.ParsedActivityImpl
+import com.android.server.pm.pkg.component.ParsedApexSystemServiceImpl
+import com.android.server.pm.pkg.component.ParsedAttributionImpl
+import com.android.server.pm.pkg.component.ParsedComponentImpl
+import com.android.server.pm.pkg.component.ParsedInstrumentationImpl
+import com.android.server.pm.pkg.component.ParsedIntentInfoImpl
+import com.android.server.pm.pkg.component.ParsedPermissionGroupImpl
+import com.android.server.pm.pkg.component.ParsedPermissionImpl
+import com.android.server.pm.pkg.component.ParsedProcessImpl
+import com.android.server.pm.pkg.component.ParsedProviderImpl
+import com.android.server.pm.pkg.component.ParsedServiceImpl
+import com.android.server.pm.pkg.component.ParsedUsesPermissionImpl
 import com.android.server.testutils.mockThrowOnUnmocked
 import com.android.server.testutils.whenever
 import java.security.KeyPairGenerator
 import java.security.PublicKey
+import java.util.UUID
 import kotlin.contracts.ExperimentalContracts
 
 @ExperimentalContracts
 class AndroidPackageTest : ParcelableComponentTest(AndroidPackage::class, PackageImpl::class) {
 
+    companion object {
+        private val TEST_UUID = UUID.fromString("57554103-df3e-4475-ae7a-8feba49353ac")
+    }
+
     override val defaultImpl = PackageImpl.forTesting("com.example.test")
     override val creator = PackageImpl.CREATOR
 
@@ -72,8 +93,6 @@
         "getLongVersionCode",
         // Tested through constructor
         "getManifestPackageName",
-        // Utility methods
-        "getStorageUuid",
         // Removal not tested, irrelevant for parcelling concerns
         "removeUsesOptionalLibrary",
         "clearAdoptPermissions",
@@ -85,6 +104,7 @@
         // Tested manually
         "getMimeGroups",
         "getRequestedPermissions",
+        "getStorageUuid",
         // Tested through asSplit
         "asSplit",
         "getSplits",
@@ -155,7 +175,6 @@
         AndroidPackage::getResizeableActivity,
         AndroidPackage::getRestrictedAccountType,
         AndroidPackage::getRoundIconRes,
-        PackageImpl::getSeInfo,
         PackageImpl::getSecondaryCpuAbi,
         AndroidPackage::getSecondaryNativeLibraryDir,
         AndroidPackage::getSharedUserId,
@@ -241,7 +260,7 @@
     )
 
     override fun extraParams() = listOf(
-        getter(AndroidPackage::getVolumeUuid, "57554103-df3e-4475-ae7a-8feba49353ac"),
+        getter(AndroidPackage::getVolumeUuid, TEST_UUID.toString()),
         getter(AndroidPackage::isProfileable, true),
         getter(PackageImpl::getVersionCode, 3),
         getter(PackageImpl::getVersionCodeMajor, 9),
@@ -602,6 +621,8 @@
         expect.that(after.usesStaticLibrariesCertDigests!!.size).isEqualTo(1)
         expect.that(after.usesStaticLibrariesCertDigests!![0]).asList()
                 .containsExactly("testCertDigest2")
+
+        expect.that(after.storageUuid).isEqualTo(TEST_UUID)
     }
 
     private fun testKey() = KeyPairGenerator.getInstance("RSA")
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
index 4ceae96..0e2e35f 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/parsing/parcelling/ParsedActivityTest.kt
@@ -54,7 +54,7 @@
         ParsedActivity::getTheme,
         ParsedActivity::getUiOptions,
         ParsedActivity::isSupportsSizeChanges,
-        ParsedActivity::getTargetDisplayCategory
+        ParsedActivity::getRequiredDisplayCategory
     )
 
     override fun mainComponentSubclassExtraParams() = listOf(
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 51fa851..e7c384b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -252,6 +252,7 @@
         noteBoot(4);
         assertTrue(RescueParty.isRebootPropertySet());
 
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
         noteBoot(5);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -276,6 +277,7 @@
         noteAppCrash(4, true);
         assertTrue(RescueParty.isRebootPropertySet());
 
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
         noteAppCrash(5, true);
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
@@ -429,6 +431,27 @@
         for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
             noteBoot(i + 1);
         }
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        noteBoot(LEVEL_FACTORY_RESET + 1);
+        assertTrue(RescueParty.isAttemptingFactoryReset());
+        assertTrue(RescueParty.isFactoryResetPropertySet());
+    }
+
+    @Test
+    public void testIsAttemptingFactoryResetOnlyAfterRebootCompleted() {
+        for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
+            noteBoot(i + 1);
+        }
+        int mitigationCount = LEVEL_FACTORY_RESET + 1;
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        assertFalse(RescueParty.isFactoryResetPropertySet());
+        noteBoot(mitigationCount++);
+        SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+        noteBoot(mitigationCount + 1);
         assertTrue(RescueParty.isAttemptingFactoryReset());
         assertTrue(RescueParty.isFactoryResetPropertySet());
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
new file mode 100644
index 0000000..ea14ffb
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AsyncProcessStartTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import static android.os.Process.myPid;
+import static android.os.Process.myUid;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.app.ActivityManagerInternal;
+import android.app.IApplicationThread;
+import android.app.usage.UsageStatsManagerInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManagerInternal;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.SystemClock;
+import android.util.Log;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.server.DropBoxManagerInternal;
+import com.android.server.LocalServices;
+import com.android.server.am.ActivityManagerService.Injector;
+import com.android.server.appop.AppOpsService;
+import com.android.server.wm.ActivityTaskManagerInternal;
+import com.android.server.wm.ActivityTaskManagerService;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.File;
+import java.util.Arrays;
+
+
+/**
+ * Tests to verify process starts are completed or timeout correctly
+ */
+@MediumTest
+@SuppressWarnings("GuardedBy")
+public class AsyncProcessStartTest {
+    private static final String TAG = "AsyncProcessStartTest";
+
+    private static final String PACKAGE = "com.foo";
+
+    @Rule
+    public final ApplicationExitInfoTest.ServiceThreadRule
+            mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule();
+
+    private Context mContext;
+    private HandlerThread mHandlerThread;
+
+    @Mock
+    private AppOpsService mAppOpsService;
+    @Mock
+    private DropBoxManagerInternal mDropBoxManagerInt;
+    @Mock
+    private PackageManagerInternal mPackageManagerInt;
+    @Mock
+    private UsageStatsManagerInternal mUsageStatsManagerInt;
+    @Mock
+    private ActivityManagerInternal mActivityManagerInt;
+    @Mock
+    private ActivityTaskManagerInternal mActivityTaskManagerInt;
+    @Mock
+    private BatteryStatsService mBatteryStatsService;
+
+    private ActivityManagerService mRealAms;
+    private ActivityManagerService mAms;
+
+    private ProcessList mRealProcessList = new ProcessList();
+    private ProcessList mProcessList;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+
+        mHandlerThread = new HandlerThread(TAG);
+        mHandlerThread.start();
+
+        LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
+        LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt);
+
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
+
+        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInt);
+
+        LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class);
+        LocalServices.addService(ActivityTaskManagerInternal.class, mActivityTaskManagerInt);
+
+        doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
+        doReturn(true).when(mActivityTaskManagerInt).attachApplication(any());
+        doNothing().when(mActivityTaskManagerInt).onProcessMapped(anyInt(), any());
+
+        mRealAms = new ActivityManagerService(
+                new TestInjector(mContext), mServiceThreadRule.getThread());
+        mRealAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
+        mRealAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
+        mRealAms.mAtmInternal = mActivityTaskManagerInt;
+        mRealAms.mPackageManagerInt = mPackageManagerInt;
+        mRealAms.mUsageStatsService = mUsageStatsManagerInt;
+        mRealAms.mProcessesReady = true;
+        mAms = spy(mRealAms);
+        mRealProcessList.mService = mAms;
+        mProcessList = spy(mRealProcessList);
+
+        doAnswer((invocation) -> {
+            Log.v(TAG, "Intercepting isProcStartValidLocked() for "
+                    + Arrays.toString(invocation.getArguments()));
+            return null;
+        }).when(mProcessList).isProcStartValidLocked(any(), anyLong());
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quit();
+    }
+
+    private class TestInjector extends Injector {
+        TestInjector(Context context) {
+            super(context);
+        }
+
+        @Override
+        public AppOpsService getAppOpsService(File file, Handler handler) {
+            return mAppOpsService;
+        }
+
+        @Override
+        public Handler getUiHandler(ActivityManagerService service) {
+            return mHandlerThread.getThreadHandler();
+        }
+
+        @Override
+        public ProcessList getProcessList(ActivityManagerService service) {
+            return mRealProcessList;
+        }
+
+        @Override
+        public BatteryStatsService getBatteryStatsService() {
+            return mBatteryStatsService;
+        }
+    }
+
+    private ProcessRecord makeActiveProcessRecord(String packageName, boolean wedge)
+            throws Exception {
+        final ApplicationInfo ai = makeApplicationInfo(packageName);
+        return makeActiveProcessRecord(ai, wedge);
+    }
+
+    private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, boolean wedge)
+            throws Exception {
+        final IApplicationThread thread = mock(IApplicationThread.class);
+        final IBinder threadBinder = new Binder();
+        doReturn(threadBinder).when(thread).asBinder();
+        doAnswer((invocation) -> {
+            Log.v(TAG, "Intercepting bindApplication() for "
+                    + Arrays.toString(invocation.getArguments()));
+            if (!wedge) {
+                mRealAms.finishAttachApplication(0);
+            }
+            return null;
+        }).when(thread).bindApplication(
+                any(), any(),
+                any(), any(),
+                any(), any(),
+                any(), any(),
+                any(),
+                any(), anyInt(),
+                anyBoolean(), anyBoolean(),
+                anyBoolean(), anyBoolean(), any(),
+                any(), any(), any(),
+                any(), any(),
+                any(), any(),
+                any(),
+                anyLong(), anyLong());
+
+        final ProcessRecord r = spy(new ProcessRecord(mAms, ai, ai.processName, ai.uid));
+        r.setPid(myPid());
+        r.setStartUid(myUid());
+        r.setHostingRecord(new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST));
+        r.makeActive(thread, mAms.mProcessStats);
+        doNothing().when(r).killLocked(any(), any(), anyInt(), anyInt(), anyBoolean(),
+                anyBoolean());
+
+        return r;
+    }
+
+    static ApplicationInfo makeApplicationInfo(String packageName) {
+        final ApplicationInfo ai = new ApplicationInfo();
+        ai.packageName = packageName;
+        ai.processName = packageName;
+        ai.uid = myUid();
+        return ai;
+    }
+
+    /**
+     * Verify that we don't kill a normal process
+     */
+    @Test
+    public void testNormal() throws Exception {
+        ProcessRecord app = startProcessAndWait(false);
+
+        verify(app, never()).killLocked(any(), anyInt(), anyBoolean());
+    }
+
+    /**
+     * Verify that we kill a wedged process after the process start timeout
+     */
+    @Test
+    public void testWedged() throws Exception {
+        ProcessRecord app = startProcessAndWait(true);
+
+        verify(app).killLocked(any(), anyInt(), anyBoolean());
+    }
+
+    private ProcessRecord startProcessAndWait(boolean wedge) throws Exception {
+        final ProcessRecord app = makeActiveProcessRecord(PACKAGE, wedge);
+        final ApplicationInfo appInfo = makeApplicationInfo(PACKAGE);
+
+        mProcessList.handleProcessStartedLocked(app, app.getPid(), /* usingWrapper */ false,
+                /* expectedStartSeq */ 0, /* procAttached */ false);
+
+        app.getThread().bindApplication(PACKAGE, appInfo,
+                null, null,
+                null,
+                null,
+                null, null,
+                null,
+                null, 0,
+                false, false,
+                true, false,
+                null,
+                null, null,
+                null,
+                null, null, null,
+                null, null,
+                0, 0);
+
+        // Sleep until timeout should have triggered
+        SystemClock.sleep(ActivityManagerService.PROC_START_TIMEOUT + 1000);
+
+        return app;
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 66e7ec0..c87fd26 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -49,6 +49,7 @@
 import android.app.Activity;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
+import android.appwidget.AppWidgetManager;
 import android.content.IIntentReceiver;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -538,6 +539,59 @@
     }
 
     /**
+     * Verify that we don't let urgent broadcasts starve delivery of non-urgent
+     */
+    @Test
+    public void testUrgentStarvation() {
+        final BroadcastOptions optInteractive = BroadcastOptions.makeBasic();
+        optInteractive.setInteractive(true);
+
+        mConstants.MAX_CONSECUTIVE_URGENT_DISPATCHES = 2;
+        BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
+                PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
+
+        // mix of broadcasts, with more than 2 fg/urgent
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_TIMEZONE_CHANGED)), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_ALARM_CHANGED)), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_TIME_TICK)), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_LOCALE_CHANGED)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_APPLICATION_PREFERENCES),
+                        optInteractive), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE),
+                        optInteractive), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_INPUT_METHOD_CHANGED)
+                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)), 0);
+        queue.enqueueOrReplaceBroadcast(
+                makeBroadcastRecord(new Intent(Intent.ACTION_NEW_OUTGOING_CALL),
+                        optInteractive), 0);
+
+        queue.makeActiveNextPending();
+        assertEquals(Intent.ACTION_LOCALE_CHANGED, queue.getActive().intent.getAction());
+        queue.makeActiveNextPending();
+        assertEquals(Intent.ACTION_APPLICATION_PREFERENCES, queue.getActive().intent.getAction());
+        // after MAX_CONSECUTIVE_URGENT_DISPATCHES expect an ordinary one next
+        queue.makeActiveNextPending();
+        assertEquals(Intent.ACTION_TIMEZONE_CHANGED, queue.getActive().intent.getAction());
+        // and then back to prioritizing urgent ones
+        queue.makeActiveNextPending();
+        assertEquals(AppWidgetManager.ACTION_APPWIDGET_UPDATE,
+                queue.getActive().intent.getAction());
+        queue.makeActiveNextPending();
+        assertEquals(Intent.ACTION_INPUT_METHOD_CHANGED, queue.getActive().intent.getAction());
+        // verify the reset-count-then-resume worked too
+        queue.makeActiveNextPending();
+        assertEquals(Intent.ACTION_ALARM_CHANGED, queue.getActive().intent.getAction());
+    }
+
+    /**
      * Verify that sending a broadcast that removes any matching pending
      * broadcasts is applied as expected.
      */
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 55d1160..9234431 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -439,14 +439,25 @@
     @SuppressWarnings("GuardedBy")
     @Test
     public void testUpdateOomAdj_DoOne_FgService_ShortFgs() {
+        sService.mConstants.TOP_TO_FGS_GRACE_DURATION = 100_000;
+        sService.mConstants.mShortFgsProcStateExtraWaitDuration = 200_000;
+
+        ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(sService);
+        s.startRequested = true;
+        s.isForeground = true;
+        s.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+        s.setShortFgsInfo(SystemClock.uptimeMillis());
+
         // SHORT_SERVICE FGS will get IMP_FG and a slightly different recent-adjustment.
         {
             ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+            app.mServices.startService(s);
             app.mServices.setHasForegroundServices(true,
                     ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
             app.mState.setLastTopTime(SystemClock.uptimeMillis());
             sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+
             sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
 
             assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -461,9 +472,11 @@
                     MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
             app.mServices.setHasForegroundServices(true,
                     ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+            app.mServices.startService(s);
             app.mState.setLastTopTime(SystemClock.uptimeMillis()
                     - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
             sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+
             sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
 
             assertProcStates(app, PROCESS_STATE_IMPORTANT_FOREGROUND,
@@ -471,6 +484,33 @@
             // Still should get network access.
             assertTrue((app.mState.getSetCapability() & PROCESS_CAPABILITY_NETWORK) != 0);
         }
+
+        // SHORT_SERVICE, timed out already.
+        s = ServiceRecord.newEmptyInstanceForTest(sService);
+        s.startRequested = true;
+        s.isForeground = true;
+        s.foregroundServiceType = ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+        s.setShortFgsInfo(SystemClock.uptimeMillis()
+                - sService.mConstants.mShortFgsTimeoutDuration
+                - sService.mConstants.mShortFgsProcStateExtraWaitDuration);
+        {
+            ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                    MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+            app.mServices.setHasForegroundServices(true,
+                    ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE, /* hasNoneType=*/false);
+            app.mServices.startService(s);
+            app.mState.setLastTopTime(SystemClock.uptimeMillis()
+                    - sService.mConstants.TOP_TO_FGS_GRACE_DURATION);
+            sService.mWakefulness.set(PowerManagerInternal.WAKEFULNESS_AWAKE);
+
+            sService.mOomAdjuster.updateOomAdjLocked(app, OomAdjuster.OOM_ADJ_REASON_NONE);
+
+            // Procstate should be lower than FGS. (It should be SERVICE)
+            assertEquals(app.mState.getSetProcState(), PROCESS_STATE_SERVICE);
+
+            // Shouldn't have the network capability now.
+            assertTrue((app.mState.getSetCapability() & PROCESS_CAPABILITY_NETWORK) == 0);
+        }
     }
 
     @SuppressWarnings("GuardedBy")
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index dc77762..a8d8945 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -17,6 +17,11 @@
 package com.android.server.app;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.app.GameManagerService.CANCEL_GAME_LOADING_MODE;
+import static com.android.server.app.GameManagerService.LOADING_BOOST_MAX_DURATION;
+import static com.android.server.app.GameManagerService.SET_GAME_STATE;
+import static com.android.server.app.GameManagerService.WRITE_DELAY_MILLIS;
+import static com.android.server.app.GameManagerService.WRITE_GAME_MODE_INTERVENTION_LIST_FILE;
 import static com.android.server.app.GameManagerService.WRITE_SETTINGS;
 
 import static org.junit.Assert.assertArrayEquals;
@@ -58,6 +63,7 @@
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.hardware.power.Mode;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.PowerManagerInternal;
@@ -103,7 +109,8 @@
     private static final String PACKAGE_NAME_INVALID = "com.android.app";
     private static final int USER_ID_1 = 1001;
     private static final int USER_ID_2 = 1002;
-    private static final int DEFAULT_PACKAGE_UID = 12345;
+    // to pass the valid package check in some of the server methods
+    private static final int DEFAULT_PACKAGE_UID = Binder.getCallingUid();
 
     private MockitoSession mMockingSession;
     private String mPackageName;
@@ -204,28 +211,33 @@
                 .startMocking();
         mMockContext = new MockContext(InstrumentationRegistry.getContext());
         mPackageName = mMockContext.getPackageName();
-        final ApplicationInfo applicationInfo = new ApplicationInfo();
-        applicationInfo.category = ApplicationInfo.CATEGORY_GAME;
-        applicationInfo.packageName = mPackageName;
-        final PackageInfo pi = new PackageInfo();
-        pi.packageName = mPackageName;
-        pi.applicationInfo = applicationInfo;
-        final List<PackageInfo> packages = new ArrayList<>();
-        packages.add(pi);
-
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_GAME);
         final Resources resources =
                 InstrumentationRegistry.getInstrumentation().getContext().getResources();
         when(mMockPackageManager.getResourcesForApplication(anyString()))
                 .thenReturn(resources);
-        when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
-                .thenReturn(packages);
-        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
-                .thenReturn(applicationInfo);
         when(mMockPackageManager.getPackageUidAsUser(mPackageName, USER_ID_1)).thenReturn(
                 DEFAULT_PACKAGE_UID);
         LocalServices.addService(PowerManagerInternal.class, mMockPowerManager);
     }
 
+    private void mockAppCategory(String packageName, @ApplicationInfo.Category int category)
+            throws Exception {
+        reset(mMockPackageManager);
+        final ApplicationInfo gameApplicationInfo = new ApplicationInfo();
+        gameApplicationInfo.category = category;
+        gameApplicationInfo.packageName = packageName;
+        final PackageInfo pi = new PackageInfo();
+        pi.packageName = packageName;
+        pi.applicationInfo = gameApplicationInfo;
+        final List<PackageInfo> packages = new ArrayList<>();
+        packages.add(pi);
+        when(mMockPackageManager.getInstalledPackagesAsUser(anyInt(), anyInt()))
+                .thenReturn(packages);
+        when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+                .thenReturn(gameApplicationInfo);
+    }
+
     @After
     public void tearDown() throws Exception {
         LocalServices.removeServiceForTest(PowerManagerInternal.class);
@@ -456,17 +468,22 @@
      * By default game mode is set to STANDARD
      */
     @Test
-    public void testGameModeDefaultValue() {
-        GameManagerService gameManagerService =
-                new GameManagerService(mMockContext, mTestLooper.getLooper());
-
-        startUser(gameManagerService, USER_ID_1);
+    public void testGetGameMode_defaultValue() {
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
         mockModifyGameModeGranted();
-
         assertEquals(GameManager.GAME_MODE_STANDARD,
                 gameManagerService.getGameMode(mPackageName, USER_ID_1));
     }
 
+    @Test
+    public void testGetGameMode_nonGame() throws Exception {
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_AUDIO);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        mockModifyGameModeGranted();
+        assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+                gameManagerService.getGameMode(mPackageName, USER_ID_1));
+    }
+
     /**
      * Test the default behaviour for a nonexistent user.
      */
@@ -613,16 +630,21 @@
             int... requiredAvailableModes) {
         Arrays.sort(requiredAvailableModes);
         // check getAvailableGameModes
-        int[] reportedAvailableModes = gameManagerService.getAvailableGameModes(mPackageName);
+        int[] reportedAvailableModes = gameManagerService.getAvailableGameModes(mPackageName,
+                USER_ID_1);
         Arrays.sort(reportedAvailableModes);
         assertArrayEquals(requiredAvailableModes, reportedAvailableModes);
 
         // check GetModeInfo.getAvailableGameModes
         GameModeInfo info = gameManagerService.getGameModeInfo(mPackageName, USER_ID_1);
-        assertNotNull(info);
-        reportedAvailableModes = info.getAvailableGameModes();
-        Arrays.sort(reportedAvailableModes);
-        assertArrayEquals(requiredAvailableModes, reportedAvailableModes);
+        if (requiredAvailableModes.length == 0) {
+            assertNull(info);
+        } else {
+            assertNotNull(info);
+            reportedAvailableModes = info.getAvailableGameModes();
+            Arrays.sort(reportedAvailableModes);
+            assertArrayEquals(requiredAvailableModes, reportedAvailableModes);
+        }
     }
 
     private void checkReportedOptedInGameModes(GameManagerService gameManagerService,
@@ -725,6 +747,14 @@
                 GameManager.GAME_MODE_STANDARD, GameManager.GAME_MODE_CUSTOM);
     }
 
+    @Test
+    public void testDeviceConfig_nonGame() throws Exception {
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_AUDIO);
+        mockDeviceConfigAll();
+        mockModifyGameModeGranted();
+        checkReportedAvailableGameModes(createServiceAndStartUser(USER_ID_1));
+    }
+
     /**
      * Override device config for performance mode exists and is valid.
      */
@@ -1442,47 +1472,98 @@
     }
 
     @Test
-    public void testGameStateLoadingRequiresPerformanceMode() {
+    public void testSetGameState_loadingRequiresPerformanceMode() {
         mockDeviceConfigNone();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService =
-                new GameManagerService(mMockContext, mTestLooper.getLooper());
-        startUser(gameManagerService, USER_ID_1);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
         GameState gameState = new GameState(true, GameState.MODE_NONE);
         gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
         mTestLooper.dispatchAll();
         verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
     }
 
-    private void setGameState(boolean isLoading) {
+    @Test
+    public void testSetGameStateLoading_withNoDeviceConfig() {
         mockDeviceConfigNone();
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService =
-                new GameManagerService(mMockContext, mTestLooper.getLooper());
-        startUser(gameManagerService, USER_ID_1);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
         gameManagerService.setGameMode(
                 mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
-        int testMode = GameState.MODE_NONE;
+        assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1),
+                GameManager.GAME_MODE_PERFORMANCE);
+        int testMode = GameState.MODE_GAMEPLAY_INTERRUPTIBLE;
         int testLabel = 99;
         int testQuality = 123;
-        GameState gameState = new GameState(isLoading, testMode, testLabel, testQuality);
-        assertEquals(isLoading, gameState.isLoading());
+        GameState gameState = new GameState(true, testMode, testLabel, testQuality);
         assertEquals(testMode, gameState.getMode());
         assertEquals(testLabel, gameState.getLabel());
         assertEquals(testQuality, gameState.getQuality());
         gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
         mTestLooper.dispatchAll();
-        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        reset(mMockPowerManager);
+        assertTrue(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+        mTestLooper.moveTimeForward(GameManagerService.LOADING_BOOST_MAX_DURATION);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
     }
 
     @Test
-    public void testSetGameStateLoading() {
-        setGameState(true);
+    public void testSetGameStateLoading_withDeviceConfig() {
+        String configString = "mode=2,loadingBoost=2000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(
+                mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        GameState gameState = new GameState(true, GameState.MODE_GAMEPLAY_INTERRUPTIBLE, 99, 123);
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+        reset(mMockPowerManager);
+        assertTrue(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(2000);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
     }
 
     @Test
     public void testSetGameStateNotLoading() {
-        setGameState(false);
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(
+                mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        int testMode = GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE;
+        int testLabel = 99;
+        int testQuality = 123;
+        GameState gameState = new GameState(false, testMode, testLabel, testQuality);
+        assertFalse(gameState.isLoading());
+        assertEquals(testMode, gameState.getMode());
+        assertEquals(testLabel, gameState.getLabel());
+        assertEquals(testQuality, gameState.getQuality());
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        assertTrue(gameManagerService.mHandler.hasEqualMessages(SET_GAME_STATE, gameState));
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+        assertFalse(
+                gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
+
+    @Test
+    public void testSetGameState_nonGame() throws Exception {
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_AUDIO);
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        GameState gameState = new GameState(true, GameState.MODE_NONE);
+        gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+        assertFalse(gameManagerService.mHandler.hasMessages(SET_GAME_STATE));
     }
 
     private List<String> readGameModeInterventionList() throws Exception {
@@ -1756,9 +1837,7 @@
     public void testUpdateCustomGameModeConfiguration_permissionDenied() {
         mockModifyGameModeDenied();
         mockDeviceConfigAll();
-        GameManagerService gameManagerService =
-                new GameManagerService(mMockContext, mTestLooper.getLooper());
-        startUser(gameManagerService, USER_ID_1);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
         assertThrows(SecurityException.class, () -> {
             gameManagerService.updateCustomGameModeConfiguration(mPackageName,
                     new GameModeConfiguration.Builder().setScalingFactor(0.5f).build(),
@@ -1769,9 +1848,7 @@
     @Test
     public void testUpdateCustomGameModeConfiguration_noUserId() {
         mockModifyGameModeGranted();
-        GameManagerService gameManagerService =
-                new GameManagerService(mMockContext, mTestLooper.getLooper());
-        startUser(gameManagerService, USER_ID_2);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_2);
         assertThrows(IllegalArgumentException.class, () -> {
             gameManagerService.updateCustomGameModeConfiguration(mPackageName,
                     new GameModeConfiguration.Builder().setScalingFactor(0.5f).build(),
@@ -1780,6 +1857,63 @@
     }
 
     @Test
+    public void testUpdateCustomGameModeConfiguration_nonGame() throws Exception {
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.updateCustomGameModeConfiguration(mPackageName,
+                new GameModeConfiguration.Builder().setScalingFactor(0.35f).setFpsOverride(
+                        60).build(),
+                USER_ID_1);
+        assertFalse(gameManagerService.mHandler.hasMessages(WRITE_SETTINGS));
+        GameManagerService.GamePackageConfiguration pkgConfig = gameManagerService.getConfig(
+                mPackageName, USER_ID_1);
+        assertNull(pkgConfig);
+    }
+
+    @Test
+    public void testUpdateCustomGameModeConfiguration() throws InterruptedException {
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.updateCustomGameModeConfiguration(mPackageName,
+                new GameModeConfiguration.Builder().setScalingFactor(0.35f).setFpsOverride(
+                        60).build(),
+                USER_ID_1);
+
+        assertTrue(gameManagerService.mHandler.hasEqualMessages(WRITE_SETTINGS, USER_ID_1));
+        assertTrue(
+                gameManagerService.mHandler.hasEqualMessages(WRITE_GAME_MODE_INTERVENTION_LIST_FILE,
+                        USER_ID_1));
+
+        GameManagerService.GamePackageConfiguration pkgConfig = gameManagerService.getConfig(
+                mPackageName, USER_ID_1);
+        assertNotNull(pkgConfig);
+        GameManagerService.GamePackageConfiguration.GameModeConfiguration modeConfig =
+                pkgConfig.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
+        assertNotNull(modeConfig);
+        assertEquals(modeConfig.getScaling(), 0.35f, 0.01f);
+        assertEquals(modeConfig.getFps(), 60);
+        // creates a new service to check that no data has been stored
+        mTestLooper.dispatchAll();
+        gameManagerService = createServiceAndStartUser(USER_ID_1);
+        pkgConfig = gameManagerService.getConfig(mPackageName, USER_ID_1);
+        assertNull(pkgConfig);
+
+        mTestLooper.moveTimeForward(WRITE_DELAY_MILLIS + 500);
+        mTestLooper.dispatchAll();
+        // creates a new service to check that data is persisted after delay
+        gameManagerService = createServiceAndStartUser(USER_ID_1);
+        assertEquals(GameManager.GAME_MODE_STANDARD,
+                gameManagerService.getGameMode(mPackageName, USER_ID_1));
+        pkgConfig = gameManagerService.getConfig(mPackageName, USER_ID_1);
+        assertNotNull(pkgConfig);
+        modeConfig = pkgConfig.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
+        assertNotNull(modeConfig);
+        assertEquals(modeConfig.getScaling(), 0.35f, 0.01f);
+        assertEquals(modeConfig.getFps(), 60);
+    }
+
+    @Test
     public void testWritingSettingFile_onShutdown() throws InterruptedException {
         mockModifyGameModeGranted();
         mockDeviceConfigAll();
@@ -1939,4 +2073,111 @@
         }
         folder.delete();
     }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup() {
+        String configString = "mode=2,loadingBoost=2000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        reset(mMockPowerManager);
+        assertTrue(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(2000);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+    }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup_outOfBoundBoostValue() {
+        String configString = "mode=2,loadingBoost=0:mode=3,loadingBoost=7000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        reset(mMockPowerManager);
+        assertTrue(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(100);
+        mTestLooper.dispatchAll();
+        // 0 loading boost value should still trigger max timeout
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+        assertTrue(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(LOADING_BOOST_MAX_DURATION);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+        reset(mMockPowerManager);
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+
+        // 7000 loading boost value should exceed the max timeout of 5s and be bounded
+        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_BATTERY, USER_ID_1);
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+        reset(mMockPowerManager);
+        assertTrue(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+        mTestLooper.moveTimeForward(LOADING_BOOST_MAX_DURATION);
+        mTestLooper.dispatchAll();
+        verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup_noDeviceConfig() {
+        mockDeviceConfigNone();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup_noLoadingBoostValue() {
+        mockDeviceConfigAll();
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup_nonGame() throws Exception {
+        String configString = "mode=2,loadingBoost=2000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        mockAppCategory(mPackageName, ApplicationInfo.CATEGORY_IMAGE);
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        assertEquals(GameManager.GAME_MODE_UNSUPPORTED,
+                gameManagerService.getGameMode(mPackageName, USER_ID_1));
+        gameManagerService.notifyGraphicsEnvironmentSetup(mPackageName, USER_ID_1);
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
+
+    @Test
+    public void testNotifyGraphicsEnvironmentSetup_differentApp() throws Exception {
+        String configString = "mode=2,loadingBoost=2000";
+        when(DeviceConfig.getProperty(anyString(), anyString()))
+                .thenReturn(configString);
+        mockModifyGameModeGranted();
+        GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+        String someGamePkg = "some.game";
+        mockAppCategory(someGamePkg, ApplicationInfo.CATEGORY_GAME);
+        when(mMockPackageManager.getPackageUidAsUser(someGamePkg, USER_ID_1)).thenReturn(
+                DEFAULT_PACKAGE_UID + 1);
+        gameManagerService.setGameMode(someGamePkg, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+        assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+                gameManagerService.getGameMode(someGamePkg, USER_ID_1));
+        gameManagerService.notifyGraphicsEnvironmentSetup(someGamePkg, USER_ID_1);
+        verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
+        assertFalse(gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java
index 5dc1251..be13bad 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsLegacyRestrictionsTest.java
@@ -48,7 +48,7 @@
     StaticMockitoSession mSession;
 
     @Mock
-    AppOpsService.Constants mConstants;
+    AppOpsServiceImpl.Constants mConstants;
 
     @Mock
     Context mContext;
@@ -57,7 +57,7 @@
     Handler mHandler;
 
     @Mock
-    AppOpsServiceInterface mLegacyAppOpsService;
+    AppOpsCheckingServiceInterface mLegacyAppOpsService;
 
     AppOpsRestrictions mAppOpsRestrictions;
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
index c0688d1..7d4bc6f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java
@@ -22,6 +22,8 @@
 import static android.app.AppOpsManager.OP_READ_SMS;
 import static android.app.AppOpsManager.OP_WIFI_SCAN;
 import static android.app.AppOpsManager.OP_WRITE_SMS;
+import static android.app.AppOpsManager.resolvePackageName;
+import static android.os.Process.INVALID_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -39,6 +41,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
 
+import android.app.AppOpsManager;
 import android.app.AppOpsManager.OpEntry;
 import android.app.AppOpsManager.PackageOps;
 import android.content.ContentResolver;
@@ -86,13 +89,13 @@
 
     private File mAppOpsFile;
     private Handler mHandler;
-    private AppOpsService mAppOpsService;
+    private AppOpsServiceImpl mAppOpsService;
     private int mMyUid;
     private long mTestStartMillis;
     private StaticMockitoSession mMockingSession;
 
     private void setupAppOpsService() {
-        mAppOpsService = new AppOpsService(mAppOpsFile, mHandler, spy(sContext));
+        mAppOpsService = new AppOpsServiceImpl(mAppOpsFile, mHandler, spy(sContext));
         mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver());
 
         // Always approve all permission checks
@@ -161,17 +164,20 @@
 
     @Test
     public void testNoteOperationAndGetOpsForPackage() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED, null);
 
         // Note an op that's allowed.
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
 
         // Note another op that's not allowed.
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null,
-                false);
+        mAppOpsService.noteOperationUnchecked(OP_WRITE_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
         loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
         assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED);
@@ -185,18 +191,20 @@
     @Test
     public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() {
         // This op controls WIFI_SCAN
-        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED);
+        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED, null);
 
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
-                null, false).getOpMode()).isEqualTo(MODE_ALLOWED);
+        assertThat(mAppOpsService.noteOperationUnchecked(OP_WIFI_SCAN, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF)).isEqualTo(MODE_ALLOWED);
 
         assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1,
                 MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
 
         // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well.
-        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED);
-        assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName, null, false,
-                null, false).getOpMode()).isEqualTo(MODE_ERRORED);
+        mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED, null);
+        assertThat(mAppOpsService.noteOperationUnchecked(OP_WIFI_SCAN, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF)).isEqualTo(MODE_ERRORED);
 
         assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis,
                 MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */);
@@ -205,11 +213,14 @@
     // Tests the dumping and restoring of the in-memory state to/from XML.
     @Test
     public void testStatePersistence() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
-        mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName, null, false, null,
-                false);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED, null);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
+        mAppOpsService.noteOperationUnchecked(OP_WRITE_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
         mAppOpsService.writeState();
 
         // Create a new app ops service which will initialize its state from XML.
@@ -224,8 +235,10 @@
     // Tests that ops are persisted during shutdown.
     @Test
     public void testShutdown() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
         mAppOpsService.shutdown();
 
         // Create a new app ops service which will initialize its state from XML.
@@ -238,8 +251,10 @@
 
     @Test
     public void testGetOpsForPackage() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
 
         // Query all ops
         List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage(
@@ -267,8 +282,10 @@
 
     @Test
     public void testPackageRemoved() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
 
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
@@ -322,8 +339,10 @@
 
     @Test
     public void testUidRemoved() {
-        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED);
-        mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName, null, false, null, false);
+        mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED, null);
+        mAppOpsService.noteOperationUnchecked(OP_READ_SMS, mMyUid,
+                resolvePackageName(mMyUid, sMyPackageName), null,
+                INVALID_UID, null, null, AppOpsManager.OP_FLAG_SELF);
 
         List<PackageOps> loggedOps = getLoggedOps();
         assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED);
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
index 98e895a..3efd5e7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUidStateTrackerTest.java
@@ -76,7 +76,7 @@
     ActivityManagerInternal mAmi;
 
     @Mock
-    AppOpsService.Constants mConstants;
+    AppOpsServiceImpl.Constants mConstants;
 
     AppOpsUidStateTrackerTestExecutor mExecutor = new AppOpsUidStateTrackerTestExecutor();
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
index e08a715..298dbf4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsUpgradeTest.java
@@ -93,12 +93,13 @@
         }
     }
 
-    private void assertSameModes(SparseArray<AppOpsService.UidState> uidStates, int op1, int op2) {
+    private void assertSameModes(SparseArray<AppOpsServiceImpl.UidState> uidStates,
+            int op1, int op2) {
         int numberOfNonDefaultOps = 0;
         final int defaultModeOp1 = AppOpsManager.opToDefaultMode(op1);
         final int defaultModeOp2 = AppOpsManager.opToDefaultMode(op2);
         for(int i = 0; i < uidStates.size(); i++) {
-            final AppOpsService.UidState uidState = uidStates.valueAt(i);
+            final AppOpsServiceImpl.UidState uidState = uidStates.valueAt(i);
             SparseIntArray opModes = uidState.getNonDefaultUidModes();
             if (opModes != null) {
                 final int uidMode1 = opModes.get(op1, defaultModeOp1);
@@ -112,12 +113,12 @@
                 continue;
             }
             for (int j = 0; j < uidState.pkgOps.size(); j++) {
-                final AppOpsService.Ops ops = uidState.pkgOps.valueAt(j);
+                final AppOpsServiceImpl.Ops ops = uidState.pkgOps.valueAt(j);
                 if (ops == null) {
                     continue;
                 }
-                final AppOpsService.Op _op1 = ops.get(op1);
-                final AppOpsService.Op _op2 = ops.get(op2);
+                final AppOpsServiceImpl.Op _op1 = ops.get(op1);
+                final AppOpsServiceImpl.Op _op2 = ops.get(op2);
                 final int mode1 = (_op1 == null) ? defaultModeOp1 : _op1.getMode();
                 final int mode2 = (_op2 == null) ? defaultModeOp2 : _op2.getMode();
                 assertEquals(mode1, mode2);
@@ -158,8 +159,8 @@
         // Stub out package calls to disable AppOpsService#updatePermissionRevokedCompat
         when(testPM.getPackagesForUid(anyInt())).thenReturn(null);
 
-        AppOpsService testService = spy(
-                new AppOpsService(mAppOpsFile, mHandler, testContext)); // trigger upgrade
+        AppOpsServiceImpl testService = spy(
+                new AppOpsServiceImpl(mAppOpsFile, mHandler, testContext)); // trigger upgrade
         assertSameModes(testService.mUidStates, AppOpsManager.OP_RUN_IN_BACKGROUND,
                 AppOpsManager.OP_RUN_ANY_IN_BACKGROUND);
         mHandler.removeCallbacks(testService.mWriteRunner);
diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
new file mode 100644
index 0000000..7ab1363
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.cpu;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.server.cpu.CpuAvailabilityMonitoringConfig.CPUSET_ALL;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+
+import android.content.Context;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.Looper;
+import android.os.ServiceManager;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.LocalServices;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+
+public final class CpuMonitorServiceTest extends ExtendedMockitoTestCase {
+    private static final CpuAvailabilityMonitoringConfig TEST_CPU_AVAILABILITY_MONITORING_CONFIG =
+            new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL)
+                    .addThreshold(30).addThreshold(70).build();
+
+    private static final CpuAvailabilityMonitoringConfig TEST_CPU_AVAILABILITY_MONITORING_CONFIG_2 =
+            new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL)
+                    .addThreshold(10).addThreshold(90).build();
+
+    @Mock
+    private Context mContext;
+    private CpuMonitorService mService;
+    private HandlerExecutor mHandlerExecutor;
+    private CpuMonitorInternal mLocalService;
+
+    @Override
+    protected void initializeSession(StaticMockitoSessionBuilder builder) {
+        builder.mockStatic(ServiceManager.class);
+    }
+
+    @Before
+    public void setUp() {
+        mService = new CpuMonitorService(mContext);
+        mHandlerExecutor = new HandlerExecutor(new Handler(Looper.getMainLooper()));
+        doNothing().when(() -> ServiceManager.addService(eq("cpu_monitor"), any(Binder.class),
+                anyBoolean(), anyInt()));
+        mService.onStart();
+        mLocalService = LocalServices.getService(CpuMonitorInternal.class);
+    }
+
+    @After
+    public void tearDown() {
+        // The CpuMonitorInternal.class service is added by the mService.onStart call.
+        // Remove the service to ensure the setUp procedure can add this service again.
+        LocalServices.removeServiceForTest(CpuMonitorInternal.class);
+    }
+
+    @Test
+    public void testAddRemoveCpuAvailabilityCallback() {
+        CpuMonitorInternal.CpuAvailabilityCallback mockCallback = mock(
+                CpuMonitorInternal.CpuAvailabilityCallback.class);
+
+        mLocalService.addCpuAvailabilityCallback(mHandlerExecutor,
+                TEST_CPU_AVAILABILITY_MONITORING_CONFIG, mockCallback);
+
+        // TODO(b/242722241): Verify that {@link mockCallback.onAvailabilityChanged} and
+        //  {@link mockCallback.onMonitoringIntervalChanged} are called when the callback is added.
+
+        mLocalService.removeCpuAvailabilityCallback(mockCallback);
+    }
+
+
+    @Test
+    public void testDuplicateAddCpuAvailabilityCallback() {
+        CpuMonitorInternal.CpuAvailabilityCallback mockCallback = mock(
+                CpuMonitorInternal.CpuAvailabilityCallback.class);
+
+        mLocalService.addCpuAvailabilityCallback(mHandlerExecutor,
+                TEST_CPU_AVAILABILITY_MONITORING_CONFIG, mockCallback);
+
+        mLocalService.addCpuAvailabilityCallback(mHandlerExecutor,
+                TEST_CPU_AVAILABILITY_MONITORING_CONFIG_2, mockCallback);
+
+        // TODO(b/242722241): Verify that {@link mockCallback} is called only when CPU availability
+        //  thresholds cross the bounds specified in the
+        //  {@link TEST_CPU_AVAILABILITY_MONITORING_CONFIG_2} config.
+
+        mLocalService.removeCpuAvailabilityCallback(mockCallback);
+    }
+
+    @Test
+    public void testRemoveInvalidCpuAvailabilityCallback() {
+        CpuMonitorInternal.CpuAvailabilityCallback mockCallback = mock(
+                CpuMonitorInternal.CpuAvailabilityCallback.class);
+
+        mLocalService.removeCpuAvailabilityCallback(mockCallback);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
index 4c28c51..f2cba40 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerController2Test.java
@@ -237,8 +237,8 @@
         when(mLogicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
         when(mLogicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(mDisplayDeviceMock);
         when(mLogicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
-        when(mLogicalDisplayMock.isEnabled()).thenReturn(true);
-        when(mLogicalDisplayMock.getPhase()).thenReturn(LogicalDisplay.DISPLAY_PHASE_ENABLED);
+        when(mLogicalDisplayMock.isEnabledLocked()).thenReturn(true);
+        when(mLogicalDisplayMock.isInTransitionLocked()).thenReturn(false);
         when(mDisplayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
         when(mDisplayDeviceMock.getUniqueId()).thenReturn(uniqueId);
         when(mDisplayDeviceMock.getDisplayDeviceConfig()).thenReturn(mDisplayDeviceConfigMock);
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
index 9a4bb22..4f8cb88 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -219,8 +219,8 @@
         when(mLogicalDisplayMock.getDisplayIdLocked()).thenReturn(displayId);
         when(mLogicalDisplayMock.getPrimaryDisplayDeviceLocked()).thenReturn(mDisplayDeviceMock);
         when(mLogicalDisplayMock.getDisplayInfoLocked()).thenReturn(info);
-        when(mLogicalDisplayMock.isEnabled()).thenReturn(true);
-        when(mLogicalDisplayMock.getPhase()).thenReturn(LogicalDisplay.DISPLAY_PHASE_ENABLED);
+        when(mLogicalDisplayMock.isEnabledLocked()).thenReturn(true);
+        when(mLogicalDisplayMock.isInTransitionLocked()).thenReturn(false);
         when(mDisplayDeviceMock.getDisplayDeviceInfoLocked()).thenReturn(deviceInfo);
         when(mDisplayDeviceMock.getUniqueId()).thenReturn(uniqueId);
         when(mDisplayDeviceMock.getDisplayDeviceConfig()).thenReturn(mDisplayDeviceConfigMock);
@@ -233,4 +233,4 @@
                 });
         when(mDisplayDeviceConfigMock.getNits()).thenReturn(new float[]{2, 500});
     }
-}
\ No newline at end of file
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index d41ac70..be32b79 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -23,6 +23,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -58,6 +59,7 @@
 import com.google.common.truth.Truth;
 
 import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -84,6 +86,8 @@
 
     private static final long HANDLER_WAIT_MS = 100;
 
+    private static final int[] HDR_TYPES = new int[]{1, 2};
+
     private StaticMockitoSession mMockitoSession;
 
     private LocalDisplayAdapter mAdapter;
@@ -161,6 +165,10 @@
         when(mMockedResources.getIntArray(
                 com.android.internal.R.array.config_autoBrightnessLevels))
                 .thenReturn(new int[]{});
+        when(mMockedResources.obtainTypedArray(R.array.config_displayShapeArray))
+                .thenReturn(mockArray);
+        when(mMockedResources.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray))
+                .thenReturn(mockArray);
     }
 
     @After
@@ -198,6 +206,38 @@
                 PORT_C, false);
     }
 
+    @Test
+    public void testSupportedDisplayModesGetOverriddenWhenDisplayIsUpdated()
+            throws InterruptedException {
+        SurfaceControl.DisplayMode displayMode = createFakeDisplayMode(0, 1920, 1080, 0);
+        displayMode.supportedHdrTypes = new int[0];
+        FakeDisplay display = new FakeDisplay(PORT_A, new SurfaceControl.DisplayMode[]{displayMode},
+                0);
+        setUpDisplay(display);
+        updateAvailableDisplays();
+        mAdapter.registerLocked();
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+        DisplayDevice displayDevice = mListener.addedDisplays.get(0);
+        displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+        Display.Mode[] supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
+        Assert.assertEquals(1, supportedModes.length);
+        Assert.assertEquals(0, supportedModes[0].getSupportedHdrTypes().length);
+
+        displayMode.supportedHdrTypes = new int[]{3, 2};
+        display.dynamicInfo.supportedDisplayModes = new SurfaceControl.DisplayMode[]{displayMode};
+        setUpDisplay(display);
+        mInjector.getTransmitter().sendHotplug(display, true);
+        waitForHandlerToComplete(mHandler, HANDLER_WAIT_MS);
+
+        displayDevice = mListener.changedDisplays.get(0);
+        displayDevice.applyPendingDisplayDeviceInfoChangesLocked();
+        supportedModes = displayDevice.getDisplayDeviceInfoLocked().supportedModes;
+
+        Assert.assertEquals(1, supportedModes.length);
+        assertArrayEquals(new int[]{2, 3}, supportedModes[0].getSupportedHdrTypes());
+    }
+
     /**
      * Confirm that all local displays are public when config_localPrivateDisplayPorts is empty.
      */
@@ -1004,6 +1044,7 @@
         mode.xDpi = 100;
         mode.yDpi = 100;
         mode.group = group;
+        mode.supportedHdrTypes = HDR_TYPES;
         return mode;
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeUserInfoHelper.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeUserInfoHelper.java
index ac23d4e..014ef3d 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeUserInfoHelper.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/FakeUserInfoHelper.java
@@ -34,14 +34,16 @@
     public static final int DEFAULT_USERID = 0;
 
     private final IntArray mRunningUserIds;
+    private final IntArray mVisibleUserIds;
     private final SparseArray<IntArray> mProfiles;
 
     private int mCurrentUserId;
 
     public FakeUserInfoHelper() {
         mCurrentUserId = DEFAULT_USERID;
-        mRunningUserIds = IntArray.wrap(new int[]{DEFAULT_USERID});
+        mRunningUserIds = IntArray.wrap(new int[] {DEFAULT_USERID});
         mProfiles = new SparseArray<>();
+        mVisibleUserIds = IntArray.wrap(new int[] {DEFAULT_USERID});
     }
 
     public void startUser(int userId) {
@@ -65,6 +67,7 @@
             mRunningUserIds.remove(idx);
         }
 
+        setUserInvisibleInternal(userId);
         dispatchOnUserStopped(userId);
     }
 
@@ -82,16 +85,39 @@
         // ensure all profiles are started if they didn't exist before...
         for (int userId : currentProfileUserIds) {
             startUserInternal(userId, false);
+            setUserVisibleInternal(userId, true);
         }
 
         if (oldUserId != mCurrentUserId) {
             dispatchOnCurrentUserChanged(oldUserId, mCurrentUserId);
+            setUserVisibleInternal(mCurrentUserId, true);
         }
     }
 
-    @Override
-    public int[] getRunningUserIds() {
-        return mRunningUserIds.toArray();
+    private void setUserVisibleInternal(int userId, boolean alwaysDispatch) {
+        int idx = mVisibleUserIds.indexOf(userId);
+        if (idx < 0) {
+            mVisibleUserIds.add(userId);
+        } else if (!alwaysDispatch) {
+            return;
+        }
+        dispatchOnVisibleUserChanged(userId, true);
+    }
+
+    private void setUserInvisibleInternal(int userId) {
+        int idx = mVisibleUserIds.indexOf(userId);
+        if (idx >= 0) {
+            mVisibleUserIds.remove(userId);
+        }
+        dispatchOnVisibleUserChanged(userId, false);
+    }
+
+    public void setUserVisible(int userId, boolean visible) {
+        if (visible) {
+            setUserVisibleInternal(userId, true);
+        } else {
+            setUserInvisibleInternal(userId);
+        }
     }
 
     @Override
@@ -100,11 +126,21 @@
     }
 
     @Override
+    public int[] getRunningUserIds() {
+        return mRunningUserIds.toArray();
+    }
+
+    @Override
     public int getCurrentUserId() {
         return mCurrentUserId;
     }
 
     @Override
+    public boolean isVisibleUserId(int userId) {
+        return mVisibleUserIds.indexOf(userId) >= 0;
+    }
+
+    @Override
     protected int[] getProfileIds(int userId) {
         IntArray profiles = mProfiles.get(userId);
         if (profiles != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemUserInfoHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemUserInfoHelperTest.java
index 490b2e8..d9aa232 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemUserInfoHelperTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/injector/SystemUserInfoHelperTest.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.location.injector;
 
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.times;
@@ -31,6 +32,7 @@
 
 import com.android.server.LocalServices;
 import com.android.server.location.injector.UserInfoHelper.UserListener;
+import com.android.server.pm.UserManagerInternal;
 
 import org.junit.After;
 import org.junit.Before;
@@ -45,13 +47,14 @@
 
     private static final int USER1_ID = 1;
     private static final int USER1_MANAGED_ID = 11;
-    private static final int[] USER1_PROFILES = new int[]{USER1_ID, USER1_MANAGED_ID};
+    private static final int[] USER1_PROFILES = new int[] {USER1_ID, USER1_MANAGED_ID};
     private static final int USER2_ID = 2;
     private static final int USER2_MANAGED_ID = 12;
-    private static final int[] USER2_PROFILES = new int[]{USER2_ID, USER2_MANAGED_ID};
+    private static final int[] USER2_PROFILES = new int[] {USER2_ID, USER2_MANAGED_ID};
 
     @Mock private Context mContext;
     @Mock private UserManager mUserManager;
+    @Mock private UserManagerInternal mUserManagerInternal;
 
     private SystemUserInfoHelper mHelper;
 
@@ -63,12 +66,15 @@
         doReturn(USER1_PROFILES).when(mUserManager).getEnabledProfileIds(USER1_ID);
         doReturn(USER2_PROFILES).when(mUserManager).getEnabledProfileIds(USER2_ID);
 
+        LocalServices.addService(UserManagerInternal.class, mUserManagerInternal);
+
         mHelper = new SystemUserInfoHelper(mContext);
     }
 
     @After
     public void tearDown() {
         LocalServices.removeServiceForTest(ActivityManagerInternal.class);
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
     }
 
     @Test
@@ -77,11 +83,11 @@
         mHelper.addListener(listener);
 
         mHelper.dispatchOnCurrentUserChanged(USER1_ID, USER2_ID);
-        verify(listener, times(1)).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
-        verify(listener, times(1)).onUserChanged(USER1_MANAGED_ID,
+        verify(listener).onUserChanged(USER1_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener).onUserChanged(USER1_MANAGED_ID,
                 UserListener.CURRENT_USER_CHANGED);
-        verify(listener, times(1)).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
-        verify(listener, times(1)).onUserChanged(USER2_MANAGED_ID,
+        verify(listener).onUserChanged(USER2_ID, UserListener.CURRENT_USER_CHANGED);
+        verify(listener).onUserChanged(USER2_MANAGED_ID,
                 UserListener.CURRENT_USER_CHANGED);
 
         mHelper.dispatchOnCurrentUserChanged(USER2_ID, USER1_ID);
@@ -94,6 +100,25 @@
     }
 
     @Test
+    public void testListener_UserVisibilityChanged() {
+        mHelper.onSystemReady();
+        verify(mUserManagerInternal).addUserVisibilityListener(any());
+
+        UserListener listener = mock(UserListener.class);
+        mHelper.addListener(listener);
+
+        mHelper.dispatchOnVisibleUserChanged(USER1_ID, false);
+        mHelper.dispatchOnVisibleUserChanged(USER2_ID, true);
+        verify(listener).onUserChanged(USER1_ID, UserListener.USER_VISIBILITY_CHANGED);
+        verify(listener).onUserChanged(USER2_ID, UserListener.USER_VISIBILITY_CHANGED);
+
+        mHelper.dispatchOnVisibleUserChanged(USER2_ID, false);
+        mHelper.dispatchOnVisibleUserChanged(USER1_ID, true);
+        verify(listener, times(2)).onUserChanged(USER2_ID, UserListener.USER_VISIBILITY_CHANGED);
+        verify(listener, times(2)).onUserChanged(USER1_ID, UserListener.USER_VISIBILITY_CHANGED);
+    }
+
+    @Test
     public void testListener_StartUser() {
         UserListener listener = mock(UserListener.class);
         mHelper.addListener(listener);
diff --git a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
index 20e4e80..aa28ad4 100644
--- a/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/location/provider/LocationProviderManagerTest.java
@@ -175,7 +175,9 @@
         doReturn(mWakeLock).when(mPowerManager).newWakeLock(anyInt(), anyString());
 
         mInjector = new TestInjector(mContext);
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
         mInjector.getUserInfoHelper().startUser(OTHER_USER);
+        mInjector.getUserInfoHelper().setUserVisible(OTHER_USER, true);
 
         mPassive = new PassiveLocationProviderManager(mContext, mInjector);
         mPassive.startManager(null);
@@ -331,6 +333,20 @@
     }
 
     @Test
+    public void testGetLastLocation_InvisibleUser() {
+        Location loc = createLocation(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, false);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isNull();
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
+        assertThat(mManager.getLastLocation(new LastLocationRequest.Builder().build(), IDENTITY,
+                PERMISSION_FINE)).isEqualTo(loc);
+    }
+
+    @Test
     public void testGetLastLocation_Bypass() {
         mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
                 new PackageTagsList.Builder().add(
@@ -569,6 +585,25 @@
     }
 
     @Test
+    public void testRegisterListener_InvisibleUser() throws Exception {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0)
+                .setWorkSource(WORK_SOURCE)
+                .build();
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, false);
+        mProvider.setProviderLocation(createLocationResult(NAME, mRandom));
+        verify(listener, never()).onLocationChanged(any(List.class),
+                nullable(IRemoteCallback.class));
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
+        LocationResult loc = createLocationResult(NAME, mRandom);
+        mProvider.setProviderLocation(loc);
+        verify(listener).onLocationChanged(eq(loc.asList()), nullable(IRemoteCallback.class));
+    }
+
+    @Test
     public void testRegisterListener_ExpiringAlarm() throws Exception {
         ILocationListener listener = createMockLocationListener();
         LocationRequest request = new LocationRequest.Builder(0)
@@ -799,6 +834,17 @@
     }
 
     @Test
+    public void testGetCurrentLocation_InvisibleUser() throws Exception {
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, false);
+
+        ILocationCallback listener = createMockGetCurrentLocationListener();
+        LocationRequest request = new LocationRequest.Builder(0).setWorkSource(WORK_SOURCE).build();
+        mManager.getCurrentLocation(request, IDENTITY, PERMISSION_FINE, listener);
+
+        verify(listener).onLocation(isNull());
+    }
+
+    @Test
     public void testFlush() throws Exception {
         ILocationListener listener = createMockLocationListener();
         mManager.registerLocationRequest(
@@ -1008,6 +1054,21 @@
     }
 
     @Test
+    public void testProviderRequest_InvisibleUser() {
+        ILocationListener listener = createMockLocationListener();
+        LocationRequest request = new LocationRequest.Builder(5)
+                .setWorkSource(WORK_SOURCE)
+                .build();
+        mManager.registerLocationRequest(request, IDENTITY, PERMISSION_FINE, listener);
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, false);
+        assertThat(mProvider.getRequest().isActive()).isFalse();
+
+        mInjector.getUserInfoHelper().setUserVisible(CURRENT_USER, true);
+        assertThat(mProvider.getRequest().isActive()).isTrue();
+    }
+
+    @Test
     public void testProviderRequest_IgnoreLocationSettings() {
         mInjector.getSettingsHelper().setIgnoreSettingsAllowlist(
                 new PackageTagsList.Builder().add(
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/AsyncUserVisibilityListener.java b/services/tests/mockingservicestests/src/com/android/server/pm/AsyncUserVisibilityListener.java
index afcedd6..ddfbf16 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/AsyncUserVisibilityListener.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/AsyncUserVisibilityListener.java
@@ -30,7 +30,6 @@
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
-
 /**
  * {@link UserVisibilityListener} implementation that expects callback events to be asynchronously
  * received.
@@ -40,7 +39,6 @@
     private static final String TAG = AsyncUserVisibilityListener.class.getSimpleName();
 
     private static final long WAIT_TIMEOUT_MS = 2_000;
-
     private static final long WAIT_NO_EVENTS_TIMEOUT_MS = 100;
 
     private static int sNextId;
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
index 1be7e2e..01674bb 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundDexOptServiceUnitTest.java
@@ -17,6 +17,7 @@
 package com.android.server.pm;
 
 import static com.android.server.pm.BackgroundDexOptService.STATUS_DEX_OPT_FAILED;
+import static com.android.server.pm.BackgroundDexOptService.STATUS_FATAL_ERROR;
 import static com.android.server.pm.BackgroundDexOptService.STATUS_OK;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -24,7 +25,9 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.timeout;
@@ -105,12 +108,16 @@
     @Mock
     private BackgroundDexOptJobService mJobServiceForIdle;
 
-    private final JobParameters mJobParametersForPostBoot = new JobParameters(null,
-            BackgroundDexOptService.JOB_POST_BOOT_UPDATE, null, null, null,
-            0, false, false, null, null, null);
-    private final JobParameters mJobParametersForIdle = new JobParameters(null,
-            BackgroundDexOptService.JOB_IDLE_OPTIMIZE, null, null, null,
-            0, false, false, null, null, null);
+    private final JobParameters mJobParametersForPostBoot =
+            createJobParameters(BackgroundDexOptService.JOB_POST_BOOT_UPDATE);
+    private final JobParameters mJobParametersForIdle =
+            createJobParameters(BackgroundDexOptService.JOB_IDLE_OPTIMIZE);
+
+    private static JobParameters createJobParameters(int jobId) {
+        JobParameters params = mock(JobParameters.class);
+        when(params.getJobId()).thenReturn(jobId);
+        return params;
+    }
 
     private BackgroundDexOptService mService;
 
@@ -264,6 +271,20 @@
     }
 
     @Test
+    public void testIdleJobFullRunWithFatalError() {
+        initUntilBootCompleted();
+        runFullJob(mJobServiceForPostBoot, mJobParametersForPostBoot,
+                /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_OK,
+                /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
+
+        doThrow(RuntimeException.class).when(mDexOptHelper).performDexOptWithStatus(any());
+
+        runFullJob(mJobServiceForIdle, mJobParametersForIdle,
+                /* expectedReschedule= */ false, /* expectedStatus= */ STATUS_FATAL_ERROR,
+                /* totalJobFinishedWithParams= */ 1, /* expectedSkippedPackage= */ null);
+    }
+
+    @Test
     public void testSystemReadyWhenDisabled() {
         when(mInjector.isBackgroundDexOptDisabled()).thenReturn(true);
 
@@ -510,13 +531,21 @@
         ArgumentCaptor<Runnable> argThreadRunnable = ArgumentCaptor.forClass(Runnable.class);
         verify(mInjector, atLeastOnce()).createAndStartThread(any(), argThreadRunnable.capture());
 
-        argThreadRunnable.getValue().run();
+        try {
+            argThreadRunnable.getValue().run();
+        } catch (RuntimeException e) {
+            if (expectedStatus != STATUS_FATAL_ERROR) {
+                throw e;
+            }
+        }
 
         verify(jobService, times(totalJobFinishedWithParams)).jobFinished(params,
                 expectedReschedule);
         // Never block
         verify(mDexOptHelper, never()).controlDexOptBlocking(true);
-        verifyPerformDexOpt();
+        if (expectedStatus != STATUS_FATAL_ERROR) {
+            verifyPerformDexOpt();
+        }
         assertThat(getLastExecutionStatus()).isEqualTo(expectedStatus);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
index dd6c733..27d0662 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/MockSystem.kt
@@ -139,7 +139,7 @@
                 .strictness(Strictness.LENIENT)
                 .mockStatic(SystemProperties::class.java)
                 .mockStatic(SystemConfig::class.java)
-                .mockStatic(SELinuxMMAC::class.java)
+                .mockStatic(SELinuxMMAC::class.java, Mockito.CALLS_REAL_METHODS)
                 .mockStatic(FallbackCategoryProvider::class.java)
                 .mockStatic(PackageManagerServiceUtils::class.java)
                 .mockStatic(Environment::class.java)
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
deleted file mode 100644
index 6c85b7a..0000000
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceOrInternalTestCase.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.pm;
-
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
-
-import android.annotation.UserIdInt;
-import android.app.ActivityManagerInternal;
-import android.content.Context;
-import android.content.pm.UserInfo;
-import android.os.UserManager;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.test.annotation.UiThreadTest;
-
-import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
-import com.android.server.ExtendedMockitoTestCase;
-import com.android.server.LocalServices;
-import com.android.server.am.UserState;
-import com.android.server.pm.UserManagerService.UserData;
-
-import org.junit.After;
-import org.junit.Before;
-import org.mockito.Mock;
-
-/**
- * Base class for {@link UserManagerInternalTest} and {@link UserManagerInternalTest}.
- *
- * <p>{@link UserManagerService} and its {@link UserManagerInternal} implementation have a
- * "symbiotic relationship - some methods of the former simply call the latter and vice versa.
- *
- * <p>Ideally, only one of them should have the logic, but since that's not the case, this class
- * provides the infra to make it easier to test both (which in turn would make it easier / safer to
- * refactor their logic later).
- */
-// TODO(b/244644281): there is no UserManagerInternalTest anymore as the logic being tested there
-// moved to UserVisibilityController, so it might be simpler to merge this class into
-// UserManagerServiceTest (once the UserVisibilityController -> UserManagerService dependency is
-// fixed)
-abstract class UserManagerServiceOrInternalTestCase extends ExtendedMockitoTestCase {
-
-    private static final String TAG = UserManagerServiceOrInternalTestCase.class.getSimpleName();
-
-    /**
-     * Id for a simple user (that doesn't have profiles).
-     */
-    protected static final int USER_ID = 600;
-
-    /**
-     * Id for another simple user.
-     */
-    protected static final int OTHER_USER_ID = 666;
-
-    /**
-     * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
-     *
-     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
-     */
-    protected static final int PARENT_USER_ID = 642;
-
-    /**
-     * Id for a profile whose parent is {@link #PARENTUSER_ID}.
-     *
-     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
-     */
-    protected static final int PROFILE_USER_ID = 643;
-
-    private final Object mPackagesLock = new Object();
-    private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
-            .getTargetContext();
-    private final SparseArray<UserData> mUsers = new SparseArray<>();
-
-    private Context mSpiedContext;
-
-    private @Mock PackageManagerService mMockPms;
-    private @Mock UserDataPreparer mMockUserDataPreparer;
-    private @Mock ActivityManagerInternal mActivityManagerInternal;
-
-    /**
-     * Reference to the {@link UserManagerService} being tested.
-     */
-    protected UserManagerService mUms;
-
-    /**
-     * Reference to the {@link UserManagerInternal} being tested.
-     */
-    protected UserManagerInternal mUmi;
-
-    @Override
-    protected void initializeSession(StaticMockitoSessionBuilder builder) {
-        builder
-                .spyStatic(UserManager.class)
-                .spyStatic(LocalServices.class);
-    }
-
-    @Before
-    @UiThreadTest // Needed to initialize main handler
-    public final void setFixtures() {
-        mSpiedContext = spy(mRealContext);
-
-        // Called when WatchedUserStates is constructed
-        doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
-
-        // Must construct UserManagerService in the UiThread
-        mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
-                mPackagesLock, mRealContext.getDataDir(), mUsers);
-        mUmi = LocalServices.getService(UserManagerInternal.class);
-        assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mUmi)
-                .isNotNull();
-    }
-
-    @After
-    public final void resetUserManagerInternal() {
-        // LocalServices follows the "Highlander rule" - There can be only one!
-        LocalServices.removeServiceForTest(UserManagerInternal.class);
-    }
-
-    ///////////////////////////////////////////
-    // Helper methods exposed to sub-classes //
-    ///////////////////////////////////////////
-
-    protected final void mockCurrentUser(@UserIdInt int userId) {
-        mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
-
-        when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
-    }
-
-    protected final <T> void mockGetLocalService(Class<T> serviceClass, T service) {
-        doReturn(service).when(() -> LocalServices.getService(serviceClass));
-    }
-
-    protected final void addDefaultProfileAndParent() {
-        addUser(PARENT_USER_ID);
-        addProfile(PROFILE_USER_ID, PARENT_USER_ID);
-    }
-
-    protected final void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
-        TestUserData profileData = new TestUserData(profileId);
-        profileData.info.flags = UserInfo.FLAG_PROFILE;
-        profileData.info.profileGroupId = parentId;
-
-        addUserData(profileData);
-    }
-
-    protected final void addUser(@UserIdInt int userId) {
-        TestUserData userData = new TestUserData(userId);
-
-        addUserData(userData);
-    }
-
-    protected final void startDefaultProfile() {
-        startUser(PROFILE_USER_ID);
-    }
-
-    protected final void stopDefaultProfile() {
-        stopUser(PROFILE_USER_ID);
-    }
-
-    protected final void startUser(@UserIdInt int userId) {
-        setUserState(userId, UserState.STATE_RUNNING_UNLOCKED);
-    }
-
-    protected final void stopUser(@UserIdInt int userId) {
-        setUserState(userId, UserState.STATE_STOPPING);
-    }
-
-    protected final void setUserState(@UserIdInt int userId, int userState) {
-        mUmi.setUserState(userId, userState);
-    }
-
-    ///////////////////
-    // Private infra //
-    ///////////////////
-
-    private void addUserData(TestUserData userData) {
-        Log.d(TAG, "Adding " + userData);
-        mUsers.put(userData.info.id, userData);
-    }
-
-    private static final class TestUserData extends UserData {
-
-        @SuppressWarnings("deprecation")
-        TestUserData(@UserIdInt int userId) {
-            info = new UserInfo();
-            info.id = userId;
-        }
-
-        @Override
-        public String toString() {
-            return "TestUserData[" + info.toFullString() + "]";
-        }
-    }
-}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
index b5ffe5f..1367af8 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java
@@ -15,17 +15,116 @@
  */
 package com.android.server.pm;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+
 import static com.google.common.truth.Truth.assertWithMessage;
 
-import android.app.ActivityManagerInternal;
-import android.os.UserHandle;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
 
+import android.annotation.UserIdInt;
+import android.app.ActivityManagerInternal;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.Log;
+import android.util.SparseArray;
+
+import androidx.test.annotation.UiThreadTest;
+
+import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder;
+import com.android.server.ExtendedMockitoTestCase;
+import com.android.server.LocalServices;
+import com.android.server.am.UserState;
+import com.android.server.pm.UserManagerService.UserData;
+
+import org.junit.After;
+import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mock;
 
 /**
  * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest}
  */
-public final class UserManagerServiceTest extends UserManagerServiceOrInternalTestCase {
+public final class UserManagerServiceTest extends ExtendedMockitoTestCase {
+
+    private static final String TAG = UserManagerServiceTest.class.getSimpleName();
+
+    /**
+     * Id for a simple user (that doesn't have profiles).
+     */
+    private static final int USER_ID = 600;
+
+    /**
+     * Id for another simple user.
+     */
+    private static final int OTHER_USER_ID = 666;
+
+    /**
+     * Id for a user that has one profile (whose id is {@link #PROFILE_USER_ID}.
+     *
+     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+     */
+    private static final int PARENT_USER_ID = 642;
+
+    /**
+     * Id for a profile whose parent is {@link #PARENTUSER_ID}.
+     *
+     * <p>You can use {@link #addDefaultProfileAndParent()} to add both of this user to the service.
+     */
+    private static final int PROFILE_USER_ID = 643;
+
+    private final Object mPackagesLock = new Object();
+    private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation()
+            .getTargetContext();
+    private final SparseArray<UserData> mUsers = new SparseArray<>();
+
+    private Context mSpiedContext;
+
+    private @Mock PackageManagerService mMockPms;
+    private @Mock UserDataPreparer mMockUserDataPreparer;
+    private @Mock ActivityManagerInternal mActivityManagerInternal;
+
+    /**
+     * Reference to the {@link UserManagerService} being tested.
+     */
+    private UserManagerService mUms;
+
+    /**
+     * Reference to the {@link UserManagerInternal} being tested.
+     */
+    private UserManagerInternal mUmi;
+
+    @Override
+    protected void initializeSession(StaticMockitoSessionBuilder builder) {
+        builder
+                .spyStatic(UserManager.class)
+                .spyStatic(LocalServices.class);
+    }
+
+    @Before
+    @UiThreadTest // Needed to initialize main handler
+    public void setFixtures() {
+        mSpiedContext = spy(mRealContext);
+
+        // Called when WatchedUserStates is constructed
+        doNothing().when(() -> UserManager.invalidateIsUserUnlockedCache());
+
+        // Must construct UserManagerService in the UiThread
+        mUms = new UserManagerService(mSpiedContext, mMockPms, mMockUserDataPreparer,
+                mPackagesLock, mRealContext.getDataDir(), mUsers);
+        mUmi = LocalServices.getService(UserManagerInternal.class);
+        assertWithMessage("LocalServices.getService(UserManagerInternal.class)").that(mUmi)
+                .isNotNull();
+    }
+
+    @After
+    public void resetUserManagerInternal() {
+        // LocalServices follows the "Highlander rule" - There can be only one!
+        LocalServices.removeServiceForTest(UserManagerInternal.class);
+    }
 
     @Test
     public void testGetCurrentUserId_amInternalNotReady() {
@@ -123,4 +222,72 @@
         assertWithMessage("isUserRunning(%s)", PROFILE_USER_ID)
                 .that(mUms.isUserRunning(PROFILE_USER_ID)).isFalse();
     }
+
+    private void mockCurrentUser(@UserIdInt int userId) {
+        mockGetLocalService(ActivityManagerInternal.class, mActivityManagerInternal);
+
+        when(mActivityManagerInternal.getCurrentUserId()).thenReturn(userId);
+    }
+
+    private <T> void mockGetLocalService(Class<T> serviceClass, T service) {
+        doReturn(service).when(() -> LocalServices.getService(serviceClass));
+    }
+
+    private void addDefaultProfileAndParent() {
+        addUser(PARENT_USER_ID);
+        addProfile(PROFILE_USER_ID, PARENT_USER_ID);
+    }
+
+    private void addProfile(@UserIdInt int profileId, @UserIdInt int parentId) {
+        TestUserData profileData = new TestUserData(profileId);
+        profileData.info.flags = UserInfo.FLAG_PROFILE;
+        profileData.info.profileGroupId = parentId;
+
+        addUserData(profileData);
+    }
+
+    private void addUser(@UserIdInt int userId) {
+        TestUserData userData = new TestUserData(userId);
+
+        addUserData(userData);
+    }
+
+    private void startDefaultProfile() {
+        startUser(PROFILE_USER_ID);
+    }
+
+    private void stopDefaultProfile() {
+        stopUser(PROFILE_USER_ID);
+    }
+
+    private void startUser(@UserIdInt int userId) {
+        setUserState(userId, UserState.STATE_RUNNING_UNLOCKED);
+    }
+
+    private void stopUser(@UserIdInt int userId) {
+        setUserState(userId, UserState.STATE_STOPPING);
+    }
+
+    private void setUserState(@UserIdInt int userId, int userState) {
+        mUmi.setUserState(userId, userState);
+    }
+
+    private void addUserData(TestUserData userData) {
+        Log.d(TAG, "Adding " + userData);
+        mUsers.put(userData.info.id, userData);
+    }
+
+    private static final class TestUserData extends UserData {
+
+        @SuppressWarnings("deprecation")
+        TestUserData(@UserIdInt int userId) {
+            info = new UserInfo();
+            info.id = userId;
+        }
+
+        @Override
+        public String toString() {
+            return "TestUserData[" + info.toFullString() + "]";
+        }
+    }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java
index c5a8572..6d8910e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUMDTest.java
@@ -15,12 +15,14 @@
  */
 package com.android.server.pm;
 
+import static android.os.UserHandle.USER_NULL;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.Display.INVALID_DISPLAY;
 
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
+import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible;
 import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
 import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
 
@@ -40,6 +42,88 @@
     }
 
     @Test
+    public void testStartFgUser_onDefaultDisplay() throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(USER_ID));
+
+        int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(USER_ID);
+        expectUserIsVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+        expectVisibleUsers(USER_ID);
+
+        expectDisplayAssignedToUser(USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, USER_ID);
+        expectUserAssignedToDisplay(INVALID_DISPLAY, USER_ID);
+        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
+
+        expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
+
+        listener.verify();
+    }
+
+    @Test
+    public void testSwitchFgUser_onDefaultDisplay() throws Exception {
+        int previousCurrentUserId = OTHER_USER_ID;
+        int currentUserId = USER_ID;
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(previousCurrentUserId),
+                onInvisible(previousCurrentUserId),
+                onVisible(currentUserId));
+        startForegroundUser(previousCurrentUserId);
+
+        int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(currentUserId);
+        expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(currentUserId, SECONDARY_DISPLAY_ID);
+        expectVisibleUsers(currentUserId);
+
+        expectDisplayAssignedToUser(currentUserId, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, currentUserId);
+        expectUserAssignedToDisplay(INVALID_DISPLAY, currentUserId);
+        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, currentUserId);
+
+        expectUserIsNotVisibleAtAll(previousCurrentUserId);
+        expectNoDisplayAssignedToUser(previousCurrentUserId);
+
+        listener.verify();
+    }
+
+    @Test
+    public void testStartBgProfile_onDefaultDisplay_whenParentIsCurrentUser() throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(PARENT_USER_ID),
+                onVisible(PROFILE_USER_ID));
+        startForegroundUser(PARENT_USER_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(PROFILE_USER_ID);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
+
+        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+
+        listener.verify();
+    }
+
+    @Test
     public void testStartFgUser_onInvalidDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -89,15 +173,15 @@
         startDefaultProfile();
 
         // Make sure they were visible before
-        expectUserIsVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
-        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsNotVisibleOnDisplay("before", PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsNotVisibleOnDisplay("before", PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
 
         int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, BG,
                 SECONDARY_DISPLAY_ID);
         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
 
-        expectUserIsNotVisibleOnDisplay(PARENT_USER_ID, SECONDARY_DISPLAY_ID);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsNotVisibleOnDisplay("after", PARENT_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsNotVisibleOnDisplay("after", PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
index fc0287f..1065392 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorSUSDTest.java
@@ -15,7 +15,15 @@
  */
 package com.android.server.pm;
 
+import static android.os.UserHandle.USER_NULL;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.INVALID_DISPLAY;
+
 import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE;
+import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
+import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible;
+import static com.android.server.pm.UserVisibilityChangedEvent.onVisible;
+import static com.android.server.pm.UserVisibilityMediator.INITIAL_CURRENT_USER_ID;
 
 import org.junit.Test;
 
@@ -33,6 +41,88 @@
     }
 
     @Test
+    public void testStartFgUser_onDefaultDisplay() throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(USER_ID));
+
+        int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(USER_ID);
+        expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
+        expectUserIsVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY);
+        expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID);
+        expectVisibleUsers(USER_ID);
+
+        expectDisplayAssignedToUser(USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, USER_ID);
+        expectUserAssignedToDisplay(INVALID_DISPLAY, USER_ID);
+        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
+
+        expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
+
+        listener.verify();
+    }
+
+    @Test
+    public void testSwitchFgUser_onDefaultDisplay() throws Exception {
+        int previousCurrentUserId = OTHER_USER_ID;
+        int currentUserId = USER_ID;
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(previousCurrentUserId),
+                onInvisible(previousCurrentUserId),
+                onVisible(currentUserId));
+        startForegroundUser(previousCurrentUserId);
+
+        int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(currentUserId);
+        expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
+        expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
+        expectUserIsVisibleOnDisplay(currentUserId, SECONDARY_DISPLAY_ID);
+        expectVisibleUsers(currentUserId);
+
+        expectDisplayAssignedToUser(currentUserId, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, currentUserId);
+        expectUserAssignedToDisplay(INVALID_DISPLAY, currentUserId);
+        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, currentUserId);
+
+        expectUserIsNotVisibleAtAll(previousCurrentUserId);
+        expectNoDisplayAssignedToUser(previousCurrentUserId);
+
+        listener.verify();
+    }
+
+    @Test
+    public void testStartBgProfile_onDefaultDisplay_whenParentIsCurrentUser() throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(PARENT_USER_ID),
+                onVisible(PROFILE_USER_ID));
+        startForegroundUser(PARENT_USER_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
+                DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+
+        expectUserIsVisible(PROFILE_USER_ID);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
+
+        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+
+        listener.verify();
+    }
+
+    @Test
     public void testStartBgUser_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
index 6ceb38a..4487d13 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
@@ -37,6 +37,7 @@
 
 import android.annotation.UserIdInt;
 import android.os.Handler;
+import android.text.TextUtils;
 import android.util.IntArray;
 import android.util.Log;
 
@@ -135,66 +136,6 @@
     }
 
     @Test
-    public final void testStartFgUser_onDefaultDisplay() throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(
-                onInvisible(INITIAL_CURRENT_USER_ID),
-                onVisible(USER_ID));
-
-        int result = mMediator.assignUserToDisplayOnStart(USER_ID, USER_ID, FG,
-                DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-
-        expectUserIsVisible(USER_ID);
-        expectUserIsNotVisibleOnDisplay(USER_ID, INVALID_DISPLAY);
-        expectUserIsVisibleOnDisplay(USER_ID, DEFAULT_DISPLAY);
-        // TODO(b/244644281): once isUserVisible() is fixed (see note there), this assertion will
-        // fail on MUMD, so we'll need to refactor / split this test (and possibly others)
-        expectUserIsVisibleOnDisplay(USER_ID, SECONDARY_DISPLAY_ID);
-        expectVisibleUsers(USER_ID);
-
-        expectDisplayAssignedToUser(USER_ID, DEFAULT_DISPLAY);
-        expectUserAssignedToDisplay(DEFAULT_DISPLAY, USER_ID);
-        expectUserAssignedToDisplay(INVALID_DISPLAY, USER_ID);
-        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, USER_ID);
-
-        expectDisplayAssignedToUser(USER_NULL, INVALID_DISPLAY);
-
-        listener.verify();
-    }
-
-    @Test
-    public final void testSwitchFgUser_onDefaultDisplay() throws Exception {
-        int previousCurrentUserId = OTHER_USER_ID;
-        int currentUserId = USER_ID;
-        AsyncUserVisibilityListener listener = addListenerForEvents(
-                onInvisible(INITIAL_CURRENT_USER_ID),
-                onVisible(previousCurrentUserId),
-                onInvisible(previousCurrentUserId),
-                onVisible(currentUserId));
-        startForegroundUser(previousCurrentUserId);
-
-        int result = mMediator.assignUserToDisplayOnStart(currentUserId, currentUserId, FG,
-                DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-
-        expectUserIsVisible(currentUserId);
-        expectUserIsNotVisibleOnDisplay(currentUserId, INVALID_DISPLAY);
-        expectUserIsVisibleOnDisplay(currentUserId, DEFAULT_DISPLAY);
-        expectUserIsVisibleOnDisplay(currentUserId, SECONDARY_DISPLAY_ID);
-        expectVisibleUsers(currentUserId);
-
-        expectDisplayAssignedToUser(currentUserId, DEFAULT_DISPLAY);
-        expectUserAssignedToDisplay(DEFAULT_DISPLAY, currentUserId);
-        expectUserAssignedToDisplay(INVALID_DISPLAY, currentUserId);
-        expectUserAssignedToDisplay(SECONDARY_DISPLAY_ID, currentUserId);
-
-        expectUserIsNotVisibleAtAll(previousCurrentUserId);
-        expectNoDisplayAssignedToUser(previousCurrentUserId);
-
-        listener.verify();
-    }
-
-    @Test
     public final void testStartFgUser_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -245,31 +186,6 @@
     }
 
     @Test
-    public final void testStartBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(
-                onInvisible(INITIAL_CURRENT_USER_ID),
-                onVisible(PARENT_USER_ID),
-                onVisible(PROFILE_USER_ID));
-        startForegroundUser(PARENT_USER_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
-                DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-
-        expectUserIsVisible(PROFILE_USER_ID);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
-        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
-
-        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
-
-        listener.verify();
-    }
-
-    @Test
     public final void testStopVisibleProfile() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForEvents(
                 onInvisible(INITIAL_CURRENT_USER_ID),
@@ -413,6 +329,15 @@
         listener.verify();
     }
 
+    @Test
+    public final void testOnSystemUserVisibilityChanged() throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(USER_SYSTEM));
+
+        mMediator.onSystemUserVisibilityChanged(/* visible= */ true);
+
+        listener.verify();
+    }
+
     /**
      * Starts a user in foreground on the default display, asserting it was properly started.
      *
@@ -530,6 +455,14 @@
                 .isFalse();
     }
 
+    protected void expectUserIsNotVisibleOnDisplay(String when, @UserIdInt int userId,
+            int displayId) {
+        String suffix = TextUtils.isEmpty(when) ? "" : " on " + when;
+        expectWithMessage("mediator.isUserVisible(%s, %s)%s", userId, displayId, suffix)
+                .that(mMediator.isUserVisible(userId, displayId))
+                .isFalse();
+    }
+
     protected void expectUserIsNotVisibleAtAll(@UserIdInt int userId) {
         expectWithMessage("mediator.isUserVisible(%s)", userId)
                 .that(mMediator.isUserVisible(userId))
diff --git a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
index 234d70b..93a1f30 100644
--- a/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/power/ScreenUndimDetectorTest.java
@@ -20,7 +20,6 @@
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
-import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR;
 import static android.provider.DeviceConfig.NAMESPACE_ATTENTION_MANAGER_SERVICE;
 import static android.view.Display.DEFAULT_DISPLAY_GROUP;
 
@@ -59,8 +58,7 @@
             Arrays.asList(POLICY_OFF,
                     POLICY_DOZE,
                     POLICY_DIM,
-                    POLICY_BRIGHT,
-                    POLICY_VR);
+                    POLICY_BRIGHT);
     private static final int OTHER_DISPLAY_GROUP = DEFAULT_DISPLAY_GROUP + 1;
 
     @ClassRule
@@ -291,7 +289,7 @@
 
     @Test
     public void recordScreenPolicy_dimToNonBright_resets() {
-        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE)) {
             setup();
             mScreenUndimDetector.mUndimCounter = 1;
             mScreenUndimDetector.mUndimCounterStartedMillis = 123;
@@ -309,7 +307,7 @@
 
     @Test
     public void recordScreenPolicy_brightToNonDim_resets() {
-        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE, POLICY_VR)) {
+        for (int to : Arrays.asList(POLICY_OFF, POLICY_DOZE)) {
             setup();
             mScreenUndimDetector.mUndimCounter = 1;
             mScreenUndimDetector.mUndimCounterStartedMillis = 123;
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
index d477cb6..799a7fe 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/AgentTrendCalculatorTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -108,7 +109,7 @@
     @Before
     public void setUp() {
         final InternalResourceService irs = mock(InternalResourceService.class);
-        when(irs.isVip(anyInt(), anyString())).thenReturn(false);
+        when(irs.isVip(anyInt(), anyString(), anyLong())).thenReturn(false);
         mEconomicPolicy = new MockEconomicPolicy(irs);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
index ddfa05c..c46ebf2 100644
--- a/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/tare/ScribeTest.java
@@ -402,6 +402,6 @@
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.uid = UserHandle.getUid(userId, Math.abs(pkgName.hashCode()));
         pkgInfo.applicationInfo = applicationInfo;
-        mInstalledPackages.add(userId, pkgName, new InstalledPackageInfo(pkgInfo));
+        mInstalledPackages.add(userId, pkgName, new InstalledPackageInfo(getContext(), pkgInfo));
     }
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
index ae25c1b..cb59d37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
@@ -44,7 +44,7 @@
 
     private MockitoSession mSession;
 
-    private final Exception mException = new Exception("D'OH!");
+    private final Throwable mThrowable = new Throwable("D'OH!");
 
     @Before
     public void setup() {
@@ -78,10 +78,10 @@
     }
 
     @Test
-    public void testV_msgAndException() {
-        Slogf.v(TAG, "msg", mException);
+    public void testV_msgAndThrowable() {
+        Slogf.v(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.v(TAG, "msg", mException));
+        verify(()-> Slog.v(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -103,12 +103,12 @@
     }
 
     @Test
-    public void testV_msgFormattedWithException_enabled() {
+    public void testV_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.VERBOSE);
 
-        Slogf.v(TAG, mException, "msg in a %s", "bottle");
+        Slogf.v(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.v(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.v(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
@@ -128,10 +128,10 @@
     }
 
     @Test
-    public void testD_msgAndException() {
-        Slogf.d(TAG, "msg", mException);
+    public void testD_msgAndThrowable() {
+        Slogf.d(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.d(TAG, "msg", mException));
+        verify(()-> Slog.d(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -153,19 +153,19 @@
     }
 
     @Test
-    public void testD_msgFormattedWithException_enabled() {
+    public void testD_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.DEBUG);
 
-        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+        Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.d(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.d(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testD_msgFormattedWithException_disabled() {
         disableLogging(Log.DEBUG);
 
-        Slogf.d(TAG, mException, "msg in a %s", "bottle");
+        Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.d(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -178,10 +178,10 @@
     }
 
     @Test
-    public void testI_msgAndException() {
-        Slogf.i(TAG, "msg", mException);
+    public void testI_msgAndThrowable() {
+        Slogf.i(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.i(TAG, "msg", mException));
+        verify(()-> Slog.i(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -203,19 +203,19 @@
     }
 
     @Test
-    public void testI_msgFormattedWithException_enabled() {
+    public void testI_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.INFO);
 
-        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+        Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.i(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.i(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testI_msgFormattedWithException_disabled() {
         disableLogging(Log.INFO);
 
-        Slogf.i(TAG, mException, "msg in a %s", "bottle");
+        Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.i(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -228,17 +228,17 @@
     }
 
     @Test
-    public void testW_msgAndException() {
-        Slogf.w(TAG, "msg", mException);
+    public void testW_msgAndThrowable() {
+        Slogf.w(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.w(TAG, "msg", mException));
+        verify(()-> Slog.w(TAG, "msg", mThrowable));
     }
 
     @Test
-    public void testW_exception() {
-        Slogf.w(TAG, mException);
+    public void testW_Throwable() {
+        Slogf.w(TAG, mThrowable);
 
-        verify(()-> Slog.w(TAG, mException));
+        verify(()-> Slog.w(TAG, mThrowable));
     }
 
     @Test
@@ -260,19 +260,19 @@
     }
 
     @Test
-    public void testW_msgFormattedWithException_enabled() {
+    public void testW_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.WARN);
 
-        Slogf.w(TAG, mException, "msg in a %s", "bottle");
+        Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.w(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.w(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testW_msgFormattedWithException_disabled() {
         disableLogging(Log.WARN);
 
-        Slogf.w(TAG, mException, "msg in a %s", "bottle");
+        Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.w(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -285,10 +285,10 @@
     }
 
     @Test
-    public void testE_msgAndException() {
-        Slogf.e(TAG, "msg", mException);
+    public void testE_msgAndThrowable() {
+        Slogf.e(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.e(TAG, "msg", mException));
+        verify(()-> Slog.e(TAG, "msg", mThrowable));
     }
 
     @Test
@@ -310,19 +310,19 @@
     }
 
     @Test
-    public void testE_msgFormattedWithException_enabled() {
+    public void testE_msgFormattedWithThrowable_enabled() {
         enableLogging(Log.ERROR);
 
-        Slogf.e(TAG, mException, "msg in a %s", "bottle");
+        Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.e(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.e(TAG, "msg in a bottle", mThrowable));
     }
 
     @Test
     public void testE_msgFormattedWithException_disabled() {
         disableLogging(Log.ERROR);
 
-        Slogf.e(TAG, mException, "msg in a %s", "bottle");
+        Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
 
         verify(()-> Slog.e(eq(TAG), any(String.class), any(Throwable.class)), never());
     }
@@ -335,17 +335,17 @@
     }
 
     @Test
-    public void testWtf_msgAndException() {
-        Slogf.wtf(TAG, "msg", mException);
+    public void testWtf_msgAndThrowable() {
+        Slogf.wtf(TAG, "msg", mThrowable);
 
-        verify(()-> Slog.wtf(TAG, "msg", mException));
+        verify(()-> Slog.wtf(TAG, "msg", mThrowable));
     }
 
     @Test
-    public void testWtf_exception() {
-        Slogf.wtf(TAG, mException);
+    public void testWtf_Throwable() {
+        Slogf.wtf(TAG, mThrowable);
 
-        verify(()-> Slog.wtf(TAG, mException));
+        verify(()-> Slog.wtf(TAG, mThrowable));
     }
 
     @Test
@@ -377,10 +377,10 @@
     }
 
     @Test
-    public void testWtf_msgFormattedWithException() {
-        Slogf.wtf(TAG, mException, "msg in a %s", "bottle");
+    public void testWtf_msgFormattedWithThrowable() {
+        Slogf.wtf(TAG, mThrowable, "msg in a %s", "bottle");
 
-        verify(()-> Slog.wtf(TAG, "msg in a bottle", mException));
+        verify(()-> Slog.wtf(TAG, "msg in a bottle", mThrowable));
     }
 
     private void enableLogging(@Log.Level int level) {
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index fbd1293..80305fa 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -54,7 +54,6 @@
         "hamcrest-library",
         "servicestests-utils",
         "service-jobscheduler",
-        "service-permission.impl",
         // TODO: remove once Android migrates to JUnit 4.12,
         // which provides assertThrows
         "testng",
@@ -115,6 +114,7 @@
         ":SimpleServiceTestApp3",
         ":StubTestApp",
         ":SuspendTestApp",
+        ":MediaButtonReceiverHolderTestHelperApp",
     ],
 
     java_resources: [
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 0be321a..9eb3b92 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -110,6 +110,9 @@
 
     <queries>
         <package android:name="com.android.servicestests.apps.suspendtestapp" />
+        <intent>
+            <action android:name="android.media.browse.MediaBrowserService" />
+        </intent>
     </queries>
 
     <!-- Uses API introduced in O (26) -->
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 9052f58..d967647 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -33,6 +33,7 @@
         <option name="test-file-name" value="SimpleServiceTestApp1.apk" />
         <option name="test-file-name" value="SimpleServiceTestApp2.apk" />
         <option name="test-file-name" value="SimpleServiceTestApp3.apk" />
+        <option name="test-file-name" value="MediaButtonReceiverHolderTestHelperApp.apk" />
     </target_preparer>
 
     <!-- Create place to store apks -->
diff --git a/services/tests/servicestests/src/com/android/server/DockObserverTest.java b/services/tests/servicestests/src/com/android/server/DockObserverTest.java
index c325778..ee09074 100644
--- a/services/tests/servicestests/src/com/android/server/DockObserverTest.java
+++ b/services/tests/servicestests/src/com/android/server/DockObserverTest.java
@@ -20,6 +20,7 @@
 
 import android.content.Intent;
 import android.os.Looper;
+import android.provider.Settings;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
 import android.testing.TestableLooper;
@@ -74,6 +75,11 @@
                 .isEqualTo(Intent.EXTRA_DOCK_STATE_UNDOCKED);
     }
 
+    void setDeviceProvisioned(boolean provisioned) {
+        Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED,
+                provisioned ? 1 : 0);
+    }
+
     @Before
     public void setUp() {
         if (Looper.myLooper() == null) {
@@ -131,4 +137,25 @@
         assertDockEventIntentWithExtraThenUndock(observer, "DOCK=1\nKEY5=5",
                 Intent.EXTRA_DOCK_STATE_HE_DESK);
     }
+
+    @Test
+    public void testDockIntentBroadcast_deviceNotProvisioned()
+            throws ExecutionException, InterruptedException {
+        DockObserver observer = new DockObserver(mInterceptingContext);
+        // Set the device as not provisioned.
+        setDeviceProvisioned(false);
+        observer.onBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY);
+
+        BroadcastInterceptingContext.FutureIntent futureIntent =
+                updateExtconDockState(observer, "DOCK=1");
+        TestableLooper.get(this).processAllMessages();
+        // Verify no broadcast was sent as device was not provisioned.
+        futureIntent.assertNotReceived();
+
+        // Ensure we send the broadcast when the device is provisioned.
+        setDeviceProvisioned(true);
+        TestableLooper.get(this).processAllMessages();
+        assertThat(futureIntent.get().getIntExtra(Intent.EXTRA_DOCK_STATE, -1))
+                .isEqualTo(Intent.EXTRA_DOCK_STATE_DESK);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
index 0f09252..52a550b 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java
@@ -58,7 +58,6 @@
 import android.view.DisplayAdjustments;
 import android.view.DisplayInfo;
 import android.view.WindowManager;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityWindowAttributes;
 
 import androidx.test.InstrumentationRegistry;
@@ -106,8 +105,6 @@
             LABEL,
             DESCRIPTION,
             TEST_PENDING_INTENT);
-    private static final AccessibilityAction NEW_ACCESSIBILITY_ACTION =
-            new AccessibilityAction(ACTION_ID, LABEL);
 
     private static final int TEST_DISPLAY = Display.DEFAULT_DISPLAY + 1;
 
@@ -282,10 +279,12 @@
     @Test
     public void testRegisterProxy() throws Exception {
         mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY);
-        verify(mProxyManager).registerProxy(mMockServiceClient, TEST_DISPLAY);
+        verify(mProxyManager).registerProxy(eq(mMockServiceClient), eq(TEST_DISPLAY),
+                eq(mTestableContext), anyInt(), any(), eq(mMockSecurityPolicy),
+                eq(mA11yms), eq(mA11yms.getTraceManager()),
+                eq(mMockWindowManagerService), eq(mMockA11yWindowManager));
     }
 
-
     @SmallTest
     @Test
     public void testRegisterProxyWithoutPermission() throws Exception {
@@ -296,7 +295,8 @@
             Assert.fail();
         } catch (SecurityException expected) {
         }
-        verify(mProxyManager, never()).registerProxy(mMockServiceClient, TEST_DISPLAY);
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+                any(), any(), any(), any());
     }
 
     @SmallTest
@@ -307,7 +307,8 @@
             Assert.fail();
         } catch (IllegalArgumentException expected) {
         }
-        verify(mProxyManager, never()).registerProxy(mMockServiceClient, Display.DEFAULT_DISPLAY);
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+                any(), any(), any(), any());
     }
 
     @SmallTest
@@ -318,7 +319,30 @@
             Assert.fail();
         } catch (IllegalArgumentException expected) {
         }
-        verify(mProxyManager, never()).registerProxy(mMockServiceClient, Display.INVALID_DISPLAY);
+        verify(mProxyManager, never()).registerProxy(any(), anyInt(), any(), anyInt(), any(), any(),
+                any(), any(), any(), any());
+    }
+
+    @SmallTest
+    @Test
+    public void testUnRegisterProxyWithPermission() throws Exception {
+        mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY);
+        mA11yms.unregisterProxyForDisplay(TEST_DISPLAY);
+
+        verify(mProxyManager).unregisterProxy(TEST_DISPLAY);
+    }
+
+    @SmallTest
+    @Test
+    public void testUnRegisterProxyWithoutPermission() throws Exception {
+        doThrow(SecurityException.class).when(mMockSecurityPolicy)
+                .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY);
+        try {
+            mA11yms.unregisterProxyForDisplay(TEST_DISPLAY);
+            Assert.fail();
+        } catch (SecurityException expected) {
+        }
+        verify(mProxyManager, never()).unregisterProxy(TEST_DISPLAY);
     }
 
     @SmallTest
@@ -417,6 +441,8 @@
     @SmallTest
     @Test
     public void testOnClientChange_magnificationEnabledAndCapabilityAll_requestConnection() {
+        when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false);
+
         final AccessibilityUserState userState = mA11yms.mUserStates.get(
                 mA11yms.getCurrentUserIdLocked());
         userState.mAccessibilityShortcutKeyTargets.add(MAGNIFICATION_CONTROLLER_NAME);
@@ -432,6 +458,8 @@
     @SmallTest
     @Test
     public void testOnClientChange_boundServiceCanControlMagnification_requestConnection() {
+        when(mProxyManager.canRetrieveInteractiveWindowsLocked()).thenReturn(false);
+
         setupAccessibilityServiceConnection(0);
         when(mMockSecurityPolicy.canControlMagnification(any())).thenReturn(true);
 
diff --git a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
index a49214f..6e446f0 100644
--- a/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/UserControllerTest.java
@@ -38,9 +38,6 @@
 import static com.android.server.am.UserController.USER_CURRENT_MSG;
 import static com.android.server.am.UserController.USER_START_MSG;
 import static com.android.server.am.UserController.USER_SWITCH_TIMEOUT_MSG;
-import static com.android.server.am.UserController.USER_VISIBILITY_CHANGED_MSG;
-import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
-import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
 
 import static com.google.android.collect.Lists.newArrayList;
 import static com.google.android.collect.Sets.newHashSet;
@@ -102,7 +99,6 @@
 import com.android.server.SystemService;
 import com.android.server.am.UserState.KeyEvictedCallback;
 import com.android.server.pm.UserManagerInternal;
-import com.android.server.pm.UserManagerInternal.UserAssignmentResult;
 import com.android.server.pm.UserManagerService;
 import com.android.server.wm.WindowManagerService;
 
@@ -117,6 +113,8 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Tests for {@link UserController}.
@@ -150,9 +148,11 @@
 
     private static final List<String> START_FOREGROUND_USER_ACTIONS = newArrayList(
             Intent.ACTION_USER_STARTED,
-            Intent.ACTION_USER_SWITCHED,
             Intent.ACTION_USER_STARTING);
 
+    private static final List<String> START_FOREGROUND_USER_DEFERRED_ACTIONS = newArrayList(
+            Intent.ACTION_USER_SWITCHED);
+
     private static final List<String> START_BACKGROUND_USER_ACTIONS = newArrayList(
             Intent.ACTION_USER_STARTED,
             Intent.ACTION_LOCKED_BOOT_COMPLETED,
@@ -162,18 +162,12 @@
             REPORT_USER_SWITCH_MSG,
             USER_SWITCH_TIMEOUT_MSG,
             USER_START_MSG,
-            USER_VISIBILITY_CHANGED_MSG,
             USER_CURRENT_MSG);
 
-    private static final Set<Integer> START_INVISIBLE_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
+    private static final Set<Integer> START_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
             USER_START_MSG,
             REPORT_LOCKED_BOOT_COMPLETE_MSG);
 
-    private static final Set<Integer> START_VISIBLE_BACKGROUND_USER_MESSAGE_CODES = newHashSet(
-            USER_START_MSG,
-            USER_VISIBILITY_CHANGED_MSG,
-            REPORT_LOCKED_BOOT_COMPLETE_MSG);
-
     @Before
     public void setUp() throws Exception {
         runWithDexmakerShareClassLoader(() -> {
@@ -225,14 +219,12 @@
 
     @Test
     public void testStartUser_background() {
-        mockAssignUserToMainDisplay(TEST_USER_ID, /* foreground= */ false,
-                USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
         boolean started = mUserController.startUser(TEST_USER_ID, /* foreground= */ false);
         assertWithMessage("startUser(%s, foreground=false)", TEST_USER_ID).that(started).isTrue();
         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
         verify(mInjector, never()).clearAllLockedTasks(anyString());
-        startBackgroundUserAssertions(/*visible= */ false);
+        startBackgroundUserAssertions();
         verifyUserAssignedToDisplay(TEST_USER_ID, Display.DEFAULT_DISPLAY);
     }
 
@@ -263,11 +255,10 @@
                 .isTrue();
         verifyUserAssignedToDisplay(TEST_USER_ID, 42);
 
-        // TODO(b/239982558): might need to change assertions
         verify(mInjector.getWindowManager(), never()).startFreezingScreen(anyInt(), anyInt());
         verify(mInjector.getWindowManager(), never()).setSwitchingUser(anyBoolean());
         verify(mInjector, never()).clearAllLockedTasks(anyString());
-        startBackgroundUserAssertions(/*visible= */ true);
+        startBackgroundUserAssertions();
     }
 
     @Test
@@ -293,8 +284,6 @@
 
     @Test
     public void testStartPreCreatedUser_background() throws Exception {
-        mockAssignUserToMainDisplay(TEST_PRE_CREATED_USER_ID, /* foreground= */ false,
-                USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
         assertTrue(mUserController.startUser(TEST_PRE_CREATED_USER_ID, /* foreground= */ false));
         // Make sure no intents have been fired for pre-created users.
         assertTrue(mInjector.mSentIntents.isEmpty());
@@ -322,10 +311,8 @@
         assertEquals("Unexpected message sent", expectedMessageCodes, actualCodes);
     }
 
-    private void startBackgroundUserAssertions(boolean visible) {
-        startUserAssertions(START_BACKGROUND_USER_ACTIONS,
-                visible ? START_VISIBLE_BACKGROUND_USER_MESSAGE_CODES
-                        : START_INVISIBLE_BACKGROUND_USER_MESSAGE_CODES);
+    private void startBackgroundUserAssertions() {
+        startUserAssertions(START_BACKGROUND_USER_ACTIONS, START_BACKGROUND_USER_MESSAGE_CODES);
     }
 
     private void startForegroundUserAssertions() {
@@ -413,11 +400,11 @@
     private void continueAndCompleteUserSwitch(UserState userState, int oldUserId, int newUserId) {
         mUserController.continueUserSwitch(userState, oldUserId, newUserId);
         mInjector.mHandler.removeMessages(UserController.COMPLETE_USER_SWITCH_MSG);
-        mUserController.completeUserSwitch(newUserId);
+        mUserController.completeUserSwitch(oldUserId, newUserId);
     }
 
     @Test
-    public void testContinueUserSwitch() throws RemoteException {
+    public void testContinueUserSwitch() {
         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
         // Start user -- this will update state of mUserController
@@ -432,12 +419,12 @@
         continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
         verify(mInjector, times(0)).dismissKeyguard(any(), anyString());
         verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
-        continueUserSwitchAssertions(TEST_USER_ID, false);
-        verifySystemUserVisibilityChangedNotified(/* visible= */ false);
+        continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
+        verifySystemUserVisibilityChangesNeverNotified();
     }
 
     @Test
-    public void testContinueUserSwitchDismissKeyguard() throws RemoteException {
+    public void testContinueUserSwitchDismissKeyguard() {
         when(mInjector.mKeyguardManagerMock.isDeviceSecure(anyInt())).thenReturn(false);
         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ true,
                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
@@ -453,12 +440,12 @@
         continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
         verify(mInjector, times(1)).dismissKeyguard(any(), anyString());
         verify(mInjector.getWindowManager(), times(1)).stopFreezingScreen();
-        continueUserSwitchAssertions(TEST_USER_ID, false);
-        verifySystemUserVisibilityChangedNotified(/* visible= */ false);
+        continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
+        verifySystemUserVisibilityChangesNeverNotified();
     }
 
     @Test
-    public void testContinueUserSwitchUIDisabled() throws RemoteException {
+    public void testContinueUserSwitchUIDisabled() {
         mUserController.setInitialConfig(/* userSwitchUiEnabled= */ false,
                 /* maxRunningUsers= */ 3, /* delayUserDataLocking= */ false);
 
@@ -473,11 +460,11 @@
         // Verify that continueUserSwitch worked as expected
         continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
         verify(mInjector.getWindowManager(), never()).stopFreezingScreen();
-        continueUserSwitchAssertions(TEST_USER_ID, false);
+        continueUserSwitchAssertions(oldUserId, TEST_USER_ID, false);
     }
 
-    private void continueUserSwitchAssertions(int expectedUserId, boolean backgroundUserStopping)
-            throws RemoteException {
+    private void continueUserSwitchAssertions(int expectedOldUserId, int expectedNewUserId,
+            boolean backgroundUserStopping) {
         Set<Integer> expectedCodes = new LinkedHashSet<>();
         expectedCodes.add(COMPLETE_USER_SWITCH_MSG);
         expectedCodes.add(REPORT_USER_SWITCH_COMPLETE_MSG);
@@ -489,7 +476,8 @@
         assertEquals("Unexpected message sent", expectedCodes, actualCodes);
         Message msg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_COMPLETE_MSG);
         assertNotNull(msg);
-        assertEquals("Unexpected userId", expectedUserId, msg.arg1);
+        assertEquals("Unexpected oldUserId", expectedOldUserId, msg.arg1);
+        assertEquals("Unexpected newUserId", expectedNewUserId, msg.arg2);
     }
 
     @Test
@@ -502,16 +490,21 @@
         mUserController.startUser(TEST_USER_ID, true);
         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
         assertNotNull(reportMsg);
+        int oldUserId = reportMsg.arg1;
         int newUserId = reportMsg.arg2;
         mInjector.mHandler.clearAllRecordedMessages();
         // Mockito can't reset only interactions, so just verify that this hasn't been
         // called with 'false' until after dispatchUserSwitchComplete.
         verify(mInjector.getWindowManager(), never()).setSwitchingUser(false);
         // Call dispatchUserSwitchComplete
-        mUserController.dispatchUserSwitchComplete(newUserId);
+        mUserController.dispatchUserSwitchComplete(oldUserId, newUserId);
         verify(observer, times(1)).onUserSwitchComplete(anyInt());
         verify(observer).onUserSwitchComplete(TEST_USER_ID);
         verify(mInjector.getWindowManager(), times(1)).setSwitchingUser(false);
+        startUserAssertions(Stream.concat(
+                        START_FOREGROUND_USER_ACTIONS.stream(),
+                        START_FOREGROUND_USER_DEFERRED_ACTIONS.stream()
+                ).collect(Collectors.toList()), Collections.emptySet());
     }
 
     @Test
@@ -561,7 +554,7 @@
         assertFalse(mUserController.canStartMoreUsers());
         assertEquals(Arrays.asList(new Integer[] {0, TEST_USER_ID1, TEST_USER_ID2}),
                 mUserController.getRunningUsersLU());
-        verifySystemUserVisibilityChangedNotified(/* visible= */ false);
+        verifySystemUserVisibilityChangesNeverNotified();
     }
 
     /**
@@ -709,24 +702,19 @@
 
     @Test
     public void testStartProfile() throws Exception {
-        mockAssignUserToMainDisplay(TEST_PRE_CREATED_USER_ID, /* foreground= */ false,
-                USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
         setUpAndStartProfileInBackground(TEST_USER_ID1);
 
-        startBackgroundUserAssertions(/*visible= */ true);
+        startBackgroundUserAssertions();
         verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
     }
 
     @Test
     public void testStartProfile_whenUsersOnSecondaryDisplaysIsEnabled() throws Exception {
-        mockAssignUserToMainDisplay(TEST_USER_ID1, /* foreground= */ false,
-                USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-
         mockIsUsersOnSecondaryDisplaysEnabled(true);
 
         setUpAndStartProfileInBackground(TEST_USER_ID1);
 
-        startBackgroundUserAssertions(/*visible= */ true);
+        startBackgroundUserAssertions();
         verifyUserAssignedToDisplay(TEST_USER_ID1, Display.DEFAULT_DISPLAY);
     }
 
@@ -923,8 +911,7 @@
     }
 
     private void addForegroundUserAndContinueUserSwitch(int newUserId, int expectedOldUserId,
-            int expectedNumberOfCalls, boolean expectOldUserStopping)
-            throws RemoteException {
+            int expectedNumberOfCalls, boolean expectOldUserStopping) {
         // Start user -- this will update state of mUserController
         mUserController.startUser(newUserId, true);
         Message reportMsg = mInjector.mHandler.getMessageForCode(REPORT_USER_SWITCH_MSG);
@@ -939,7 +926,7 @@
         continueAndCompleteUserSwitch(userState, oldUserId, newUserId);
         verify(mInjector.getWindowManager(), times(expectedNumberOfCalls))
                 .stopFreezingScreen();
-        continueUserSwitchAssertions(newUserId, expectOldUserStopping);
+        continueUserSwitchAssertions(oldUserId, newUserId, expectOldUserStopping);
     }
 
     private void setUpUser(@UserIdInt int userId, @UserInfoFlag int flags) {
@@ -983,13 +970,6 @@
         when(mInjector.isUsersOnSecondaryDisplaysEnabled()).thenReturn(value);
     }
 
-    private void mockAssignUserToMainDisplay(@UserIdInt int userId, boolean foreground,
-            @UserAssignmentResult int result) {
-        when(mInjector.mUserManagerInternalMock.assignUserToDisplayOnStart(eq(userId),
-                /* profileGroupId= */ anyInt(), eq(foreground), eq(Display.DEFAULT_DISPLAY)))
-                        .thenReturn(result);
-    }
-
     private void verifyUserAssignedToDisplay(@UserIdInt int userId, int displayId) {
         verify(mInjector.getUserManagerInternal()).assignUserToDisplayOnStart(eq(userId), anyInt(),
                 anyBoolean(), eq(displayId));
@@ -1008,8 +988,8 @@
         verify(mInjector.getUserManagerInternal(), never()).unassignUserFromDisplayOnStop(userId);
     }
 
-    private void verifySystemUserVisibilityChangedNotified(boolean visible) {
-        verify(mInjector).onUserVisibilityChanged(UserHandle.USER_SYSTEM, visible);
+    private void verifySystemUserVisibilityChangesNeverNotified() {
+        verify(mInjector, never()).onSystemUserVisibilityChanged(anyBoolean());
     }
 
     // Should be public to allow mocking
@@ -1154,8 +1134,8 @@
         }
 
         @Override
-        void onUserVisibilityChanged(@UserIdInt int userId, boolean visible) {
-            Log.i(TAG, "onUserVisibilityChanged(" + userId + ", " + visible + ")");
+        void onSystemUserVisibilityChanged(boolean visible) {
+            Log.i(TAG, "onSystemUserVisibilityChanged(" + visible + ")");
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
index 582c78b..fde3422 100644
--- a/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/app/GameManagerServiceSettingsTests.java
@@ -52,6 +52,8 @@
     private static final String PACKAGE_NAME_1 = "com.android.app1";
     private static final String PACKAGE_NAME_2 = "com.android.app2";
     private static final String PACKAGE_NAME_3 = "com.android.app3";
+    private static final String PACKAGE_NAME_4 = "com.android.app4";
+
 
     private void writeFile(File file, byte[] data) {
         file.mkdirs();
@@ -69,16 +71,23 @@
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
                         "system/game-manager-service.xml"),
                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                        + "<packages>\n"
-                        + "  <package name=\"com.android.app1\" gameMode=\"1\">\n"
-                        + "  </package>\n"
+                        + "<packages>"
+                        + "\n" // app1: no package config setting
+                        + "\n" // app2: performance mode is selected with override
                         + "  <package name=\"com.android.app2\" gameMode=\"2\">\n"
                         + "     <gameModeConfig gameMode=\"2\" scaling=\"0.99\" "
                         + "useAngle=\"true\" fps=\"90\" loadingBoost=\"123\"></gameModeConfig>\n"
                         + "     <gameModeConfig gameMode=\"3\"></gameModeConfig>\n"
-                        + "  </package>\n"
+                        + "  </package>"
+                        + "\n" // app3: only battery mode is selected
                         + "  <package name=\"com.android.app3\" gameMode=\"3\">\n"
-                        + "  </package>\n"
+                        + "  </package>"
+                        + "\n" // app4: no game mode selected but custom game mode config
+                        + "  <package name=\"com.android.app4\">\n"
+                        + "     <gameModeConfig gameMode=\"4\" scaling=\"0.4\" "
+                        + "fps=\"30\"></gameModeConfig>\n"
+                        + "  </package>"
+                        + "\n"
                         + "</packages>\n").getBytes());
     }
 
@@ -115,14 +124,15 @@
         assertTrue(settings.readPersistentDataLocked());
 
         // test game modes
-        assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_1));
-        assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
-        assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_3));
+        assertEquals(GameManager.GAME_MODE_STANDARD, settings.getGameModeLocked(PACKAGE_NAME_1));
+        assertEquals(GameManager.GAME_MODE_PERFORMANCE, settings.getGameModeLocked(PACKAGE_NAME_2));
+        assertEquals(GameManager.GAME_MODE_BATTERY, settings.getGameModeLocked(PACKAGE_NAME_3));
+        assertEquals(GameManager.GAME_MODE_STANDARD, settings.getGameModeLocked(PACKAGE_NAME_4));
 
         // test game mode configs
         assertNull(settings.getConfigOverride(PACKAGE_NAME_1));
         assertNull(settings.getConfigOverride(PACKAGE_NAME_3));
-        final GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
+        GamePackageConfiguration config = settings.getConfigOverride(PACKAGE_NAME_2);
         assertNotNull(config);
 
         assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_STANDARD));
@@ -141,6 +151,14 @@
                 GameModeConfiguration.DEFAULT_LOADING_BOOST_DURATION);
         assertEquals(batteryConfig.getFpsStr(), GameModeConfiguration.DEFAULT_FPS);
         assertFalse(batteryConfig.getUseAngle());
+
+        config = settings.getConfigOverride(PACKAGE_NAME_4);
+        assertNotNull(config);
+        GameModeConfiguration customConfig = config.getGameModeConfiguration(
+                GameManager.GAME_MODE_CUSTOM);
+        assertNotNull(customConfig);
+        assertEquals(customConfig.getScaling(), 0.4f, 0.1f);
+        assertEquals(customConfig.getFps(), 30);
     }
 
     @Test
@@ -176,16 +194,20 @@
         writeFile(new File(InstrumentationRegistry.getContext().getFilesDir(),
                         "system/game-manager-service.xml"),
                 ("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>"
-                        + "<packages>\n"
+                        + "<packages>"
+                        + "\n" // missing package name
                         + "  <package gameMode=\"1\">\n"
-                        + "  </package>\n"
+                        + "  </package>"
+                        + "\n" // app2 with unknown sub element
                         + "  <package name=\"com.android.app2\" gameMode=\"2\">\n"
                         + "     <unknown></unknown>"
                         + "     <gameModeConfig gameMode=\"3\" fps=\"90\"></gameModeConfig>\n"
                         + "     foo bar"
-                        + "  </package>\n"
+                        + "  </package>"
+                        + "\n" // unknown package element
                         + "  <unknownTag></unknownTag>\n"
-                        + "    foo bar\n"
+                        + "    foo bar"
+                        + "\n" // app3 after unknown element
                         + "  <package name=\"com.android.app3\" gameMode=\"3\">\n"
                         + "  </package>\n"
                         + "</packages>\n").getBytes());
@@ -214,6 +236,8 @@
         settings.setGameModeLocked(PACKAGE_NAME_1, GameManager.GAME_MODE_BATTERY);
         settings.setGameModeLocked(PACKAGE_NAME_2, GameManager.GAME_MODE_PERFORMANCE);
         settings.setGameModeLocked(PACKAGE_NAME_3, GameManager.GAME_MODE_STANDARD);
+
+        // set config for app2
         GamePackageConfiguration config = new GamePackageConfiguration(PACKAGE_NAME_2);
         GameModeConfiguration performanceConfig = config.getOrAddDefaultGameModeConfiguration(
                 GameManager.GAME_MODE_PERFORMANCE);
@@ -225,18 +249,29 @@
                 GameManager.GAME_MODE_BATTERY);
         batteryConfig.setScaling(0.77f);
         settings.setConfigOverride(PACKAGE_NAME_2, config);
+
+        // set config for app4
+        config = new GamePackageConfiguration(PACKAGE_NAME_4);
+        GameModeConfiguration customConfig = config.getOrAddDefaultGameModeConfiguration(
+                GameManager.GAME_MODE_CUSTOM);
+        customConfig.setScaling(0.4f);
+        customConfig.setFpsStr("30");
+        settings.setConfigOverride(PACKAGE_NAME_4, config);
+
         settings.writePersistentDataLocked();
 
         // clear the settings in memory
         settings.removeGame(PACKAGE_NAME_1);
         settings.removeGame(PACKAGE_NAME_2);
         settings.removeGame(PACKAGE_NAME_3);
+        settings.removeGame(PACKAGE_NAME_4);
 
         // read back in and verify
         assertTrue(settings.readPersistentDataLocked());
         assertEquals(3, settings.getGameModeLocked(PACKAGE_NAME_1));
         assertEquals(2, settings.getGameModeLocked(PACKAGE_NAME_2));
         assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_3));
+        assertEquals(1, settings.getGameModeLocked(PACKAGE_NAME_4));
 
         config = settings.getConfigOverride(PACKAGE_NAME_1);
         assertNull(config);
@@ -256,5 +291,14 @@
         assertEquals(performanceConfig.getLoadingBoostDuration(), 321);
         assertEquals(performanceConfig.getFpsStr(), "60");
         assertTrue(performanceConfig.getUseAngle());
+
+        config = settings.getConfigOverride(PACKAGE_NAME_4);
+        assertNotNull(config);
+        customConfig = config.getGameModeConfiguration(GameManager.GAME_MODE_CUSTOM);
+        assertNotNull(customConfig);
+        assertEquals(customConfig.getScaling(), 0.4f, 0.1f);
+        assertEquals(customConfig.getFps(), 30);
+        assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_PERFORMANCE));
+        assertNull(config.getGameModeConfiguration(GameManager.GAME_MODE_BATTERY));
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
index 6016558..cd2f205 100644
--- a/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -29,7 +29,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.backup.BackupAgent;
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.app.backup.IBackupManagerMonitor;
 import android.app.backup.IBackupObserver;
 import android.content.Context;
@@ -148,18 +148,18 @@
     }
 
     @Test
-    public void testGetOperationTypeFromTransport_returnsBackupByDefault()
+    public void testGetBackupDestinationFromTransport_returnsCloudByDefault()
             throws Exception {
         when(mTransportConnection.connectOrThrow(any())).thenReturn(mBackupTransport);
         when(mBackupTransport.getTransportFlags()).thenReturn(0);
 
-        int operationType = mService.getOperationTypeFromTransport(mTransportConnection);
+        int backupDestination = mService.getBackupDestinationFromTransport(mTransportConnection);
 
-        assertThat(operationType).isEqualTo(OperationType.BACKUP);
+        assertThat(backupDestination).isEqualTo(BackupDestination.CLOUD);
     }
 
     @Test
-    public void testGetOperationTypeFromTransport_returnsMigrationForMigrationTransport()
+    public void testGetBackupDestinationFromTransport_returnsDeviceTransferForD2dTransport()
             throws Exception {
         // This is a temporary flag to control the new behaviour until it's ready to be fully
         // rolled out.
@@ -169,9 +169,9 @@
         when(mBackupTransport.getTransportFlags()).thenReturn(
                 BackupAgent.FLAG_DEVICE_TO_DEVICE_TRANSFER);
 
-        int operationType = mService.getOperationTypeFromTransport(mTransportConnection);
+        int backupDestination = mService.getBackupDestinationFromTransport(mTransportConnection);
 
-        assertThat(operationType).isEqualTo(OperationType.MIGRATION);
+        assertThat(backupDestination).isEqualTo(BackupDestination.DEVICE_TRANSFER);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
index 310c8f4..48b0aad 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupEligibilityRulesTest.java
@@ -23,7 +23,7 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.when;
 
-import android.app.backup.BackupManager.OperationType;
+import android.app.backup.BackupAnnotations.BackupDestination;
 import android.compat.testing.PlatformCompatChangeRule;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -78,7 +78,7 @@
         MockitoAnnotations.initMocks(this);
 
         mUserId = UserHandle.USER_SYSTEM;
-        mBackupEligibilityRules = getBackupEligibilityRules(OperationType.BACKUP);
+        mBackupEligibilityRules = getBackupEligibilityRules(BackupDestination.CLOUD);
     }
 
     @Test
@@ -225,7 +225,7 @@
                 /* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
 
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.MIGRATION);
+                BackupDestination.DEVICE_TRANSFER);
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
 
         assertThat(isEligible).isTrue();
@@ -237,7 +237,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.SYSTEM_UID,
                 ApplicationInfo.FLAG_SYSTEM, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.MIGRATION);
+                BackupDestination.DEVICE_TRANSFER);
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
 
         assertThat(isEligible).isFalse();
@@ -250,7 +250,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
                 /* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.ADB_BACKUP);
+                BackupDestination.ADB_BACKUP);
         when(mPackageManager.getPropertyAsUser(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
                 eq(TEST_PACKAGE_NAME), isNull(), eq(mUserId)))
                 .thenReturn(getAdbBackupProperty(/* allowAdbBackup */ false));
@@ -267,7 +267,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
                 /* flags */ ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.ADB_BACKUP);
+                BackupDestination.ADB_BACKUP);
         when(mPackageManager.getPropertyAsUser(eq(PackageManager.PROPERTY_ALLOW_ADB_BACKUP),
                 eq(TEST_PACKAGE_NAME), isNull(), eq(mUserId)))
                 .thenReturn(getAdbBackupProperty(/* allowAdbBackup */ true));
@@ -284,7 +284,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
                 /* flags */ ApplicationInfo.FLAG_DEBUGGABLE, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.ADB_BACKUP);
+                BackupDestination.ADB_BACKUP);
 
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
 
@@ -298,7 +298,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
                 ApplicationInfo.FLAG_ALLOW_BACKUP, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.ADB_BACKUP);
+                BackupDestination.ADB_BACKUP);
 
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
 
@@ -312,7 +312,7 @@
         ApplicationInfo applicationInfo = getApplicationInfo(Process.FIRST_APPLICATION_UID,
                 /* flags */ 0, CUSTOM_BACKUP_AGENT_NAME);
         BackupEligibilityRules eligibilityRules = getBackupEligibilityRules(
-                OperationType.ADB_BACKUP);
+                BackupDestination.ADB_BACKUP);
 
         boolean isEligible = eligibilityRules.appIsEligibleForBackup(applicationInfo);
 
@@ -787,9 +787,10 @@
         assertThat(result).isFalse();
     }
 
-    private BackupEligibilityRules getBackupEligibilityRules(@OperationType int operationType) {
+    private BackupEligibilityRules getBackupEligibilityRules(
+            @BackupDestination int backupDestination) {
         return new BackupEligibilityRules(mPackageManager, mMockPackageManagerInternal, mUserId,
-                operationType);
+                backupDestination);
     }
 
     private static Signature generateSignature(byte i) {
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/OWNERS b/services/tests/servicestests/src/com/android/server/companion/virtual/OWNERS
new file mode 100644
index 0000000..2968104
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/OWNERS
@@ -0,0 +1 @@
+include /services/companion/java/com/android/server/companion/virtual/OWNERS
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
new file mode 100644
index 0000000..ef8a49f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/SensorControllerTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.companion.virtual;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
+
+import android.companion.virtual.sensor.VirtualSensorConfig;
+import android.companion.virtual.sensor.VirtualSensorEvent;
+import android.hardware.Sensor;
+import android.os.Binder;
+import android.os.IBinder;
+import android.platform.test.annotations.Presubmit;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+
+import com.android.server.LocalServices;
+import com.android.server.sensors.SensorManagerInternal;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper(setAsMainLooper = true)
+public class SensorControllerTest {
+
+    private static final int VIRTUAL_DEVICE_ID = 42;
+    private static final String VIRTUAL_SENSOR_NAME = "VirtualAccelerometer";
+    private static final int SENSOR_HANDLE = 7;
+
+    @Mock
+    private SensorManagerInternal mSensorManagerInternalMock;
+    private SensorController mSensorController;
+    private VirtualSensorEvent mSensorEvent;
+    private VirtualSensorConfig mVirtualSensorConfig;
+    private IBinder mSensorToken;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        LocalServices.removeServiceForTest(SensorManagerInternal.class);
+        LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
+
+        mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID);
+        mSensorEvent = new VirtualSensorEvent.Builder(new float[] { 1f, 2f, 3f}).build();
+        mVirtualSensorConfig =
+                new VirtualSensorConfig.Builder(Sensor.TYPE_ACCELEROMETER, VIRTUAL_SENSOR_NAME)
+                        .build();
+        mSensorToken = new Binder("sensorToken");
+    }
+
+    @Test
+    public void createSensor_invalidHandle_throwsException() {
+        doReturn(/* handle= */0).when(mSensorManagerInternalMock).createRuntimeSensor(
+                anyInt(), anyInt(), anyString(), anyString(), any());
+
+        Throwable thrown = assertThrows(
+                RuntimeException.class,
+                () -> mSensorController.createSensor(mSensorToken, mVirtualSensorConfig));
+
+        assertThat(thrown.getCause().getMessage())
+                .contains("Received an invalid virtual sensor handle");
+    }
+
+    @Test
+    public void createSensor_success() {
+        doCreateSensorSuccessfully();
+
+        assertThat(mSensorController.getSensorDescriptors()).isNotEmpty();
+    }
+
+    @Test
+    public void sendSensorEvent_invalidToken_throwsException() {
+        doCreateSensorSuccessfully();
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mSensorController.sendSensorEvent(
+                        new Binder("invalidSensorToken"), mSensorEvent));
+    }
+
+    @Test
+    public void sendSensorEvent_success() {
+        doCreateSensorSuccessfully();
+
+        mSensorController.sendSensorEvent(mSensorToken, mSensorEvent);
+        verify(mSensorManagerInternalMock).sendSensorEvent(
+                SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, mSensorEvent.getTimestampNanos(),
+                mSensorEvent.getValues());
+    }
+
+    @Test
+    public void unregisterSensor_invalidToken_throwsException() {
+        doCreateSensorSuccessfully();
+
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mSensorController.unregisterSensor(new Binder("invalidSensorToken")));
+    }
+
+    @Test
+    public void unregisterSensor_success() {
+        doCreateSensorSuccessfully();
+
+        mSensorController.unregisterSensor(mSensorToken);
+        verify(mSensorManagerInternalMock).removeRuntimeSensor(SENSOR_HANDLE);
+        assertThat(mSensorController.getSensorDescriptors()).isEmpty();
+    }
+
+    private void doCreateSensorSuccessfully() {
+        doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
+                anyInt(), anyInt(), anyString(), anyString(), any());
+        mSensorController.createSensor(mSensorToken, mVirtualSensorConfig);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
index 09dc367..9de6190 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceManagerServiceTest.java
@@ -51,20 +51,25 @@
 import android.companion.virtual.VirtualDeviceParams;
 import android.companion.virtual.audio.IAudioConfigChangedCallback;
 import android.companion.virtual.audio.IAudioRoutingCallback;
+import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.graphics.Point;
+import android.hardware.Sensor;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.input.IInputManager;
+import android.hardware.input.VirtualDpadConfig;
 import android.hardware.input.VirtualKeyEvent;
+import android.hardware.input.VirtualKeyboardConfig;
 import android.hardware.input.VirtualMouseButtonEvent;
+import android.hardware.input.VirtualMouseConfig;
 import android.hardware.input.VirtualMouseRelativeEvent;
 import android.hardware.input.VirtualMouseScrollEvent;
 import android.hardware.input.VirtualTouchEvent;
+import android.hardware.input.VirtualTouchscreenConfig;
 import android.net.MacAddress;
 import android.os.Binder;
 import android.os.Handler;
@@ -88,6 +93,7 @@
 import com.android.internal.app.BlockedAppStreamingActivity;
 import com.android.server.LocalServices;
 import com.android.server.input.InputManagerInternal;
+import com.android.server.sensors.SensorManagerInternal;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -99,6 +105,7 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 import java.util.function.Consumer;
 
 @Presubmit
@@ -125,16 +132,49 @@
     private static final int VENDOR_ID = 5;
     private static final String UNIQUE_ID = "uniqueid";
     private static final String PHYS = "phys";
-    private static final int DEVICE_ID = 42;
+    private static final int DEVICE_ID = 53;
     private static final int HEIGHT = 1800;
     private static final int WIDTH = 900;
+    private static final int SENSOR_HANDLE = 64;
     private static final Binder BINDER = new Binder("binder");
     private static final int FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES = 0x00000;
+    private static final int VIRTUAL_DEVICE_ID = 42;
+    private static final VirtualDpadConfig DPAD_CONFIG =
+            new VirtualDpadConfig.Builder()
+                    .setVendorId(VENDOR_ID)
+                    .setProductId(PRODUCT_ID)
+                    .setInputDeviceName(DEVICE_NAME)
+                    .setAssociatedDisplayId(DISPLAY_ID)
+                    .build();
+    private static final VirtualKeyboardConfig KEYBOARD_CONFIG =
+            new VirtualKeyboardConfig.Builder()
+                    .setVendorId(VENDOR_ID)
+                    .setProductId(PRODUCT_ID)
+                    .setInputDeviceName(DEVICE_NAME)
+                    .setAssociatedDisplayId(DISPLAY_ID)
+                    .build();
+    private static final VirtualMouseConfig MOUSE_CONFIG =
+            new VirtualMouseConfig.Builder()
+                    .setVendorId(VENDOR_ID)
+                    .setProductId(PRODUCT_ID)
+                    .setInputDeviceName(DEVICE_NAME)
+                    .setAssociatedDisplayId(DISPLAY_ID)
+                    .build();
+    private static final VirtualTouchscreenConfig TOUCHSCREEN_CONFIG =
+            new VirtualTouchscreenConfig.Builder()
+                    .setVendorId(VENDOR_ID)
+                    .setProductId(PRODUCT_ID)
+                    .setInputDeviceName(DEVICE_NAME)
+                    .setAssociatedDisplayId(DISPLAY_ID)
+                    .setWidthInPixels(WIDTH)
+                    .setHeightInPixels(HEIGHT)
+                    .build();
 
     private Context mContext;
     private InputManagerMockHelper mInputManagerMockHelper;
     private VirtualDeviceImpl mDeviceImpl;
     private InputController mInputController;
+    private SensorController mSensorController;
     private AssociationInfo mAssociationInfo;
     private VirtualDeviceManagerService mVdms;
     private VirtualDeviceManagerInternal mLocalService;
@@ -149,6 +189,8 @@
     @Mock
     private InputManagerInternal mInputManagerInternalMock;
     @Mock
+    private SensorManagerInternal mSensorManagerInternalMock;
+    @Mock
     private IVirtualDeviceActivityListener mActivityListener;
     @Mock
     private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
@@ -181,14 +223,36 @@
         return blockedActivities;
     }
 
+    private Intent createRestrictedActivityBlockedIntent(List displayCategories,
+            String targetDisplayCategory) {
+        mDeviceImpl.onVirtualDisplayCreatedLocked(
+                mDeviceImpl.createWindowPolicyController(displayCategories), DISPLAY_ID);
+        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
+                DISPLAY_ID);
+        doNothing().when(mContext).startActivityAsUser(any(), any(), any());
+
+        ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
+                NONBLOCKED_APP_PACKAGE_NAME,
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoveDevices= */ true,
+                targetDisplayCategory);
+        Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
+                activityInfos.get(0), mAssociationInfo.getDisplayName());
+        gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
+        return blockedAppIntent;
+    }
+
+
     private ArrayList<ActivityInfo> getActivityInfoList(
-            String packageName, String name, boolean displayOnRemoveDevices) {
+            String packageName, String name, boolean displayOnRemoveDevices,
+            String requiredDisplayCategory) {
         ActivityInfo activityInfo = new ActivityInfo();
         activityInfo.packageName = packageName;
         activityInfo.name = name;
         activityInfo.flags = displayOnRemoveDevices
                 ? FLAG_CAN_DISPLAY_ON_REMOTE_DEVICES : FLAG_CANNOT_DISPLAY_ON_REMOTE_DEVICES;
         activityInfo.applicationInfo = mApplicationInfoMock;
+        activityInfo.requiredDisplayCategory = requiredDisplayCategory;
         return new ArrayList<>(Arrays.asList(activityInfo));
     }
 
@@ -205,6 +269,9 @@
         LocalServices.removeServiceForTest(InputManagerInternal.class);
         LocalServices.addService(InputManagerInternal.class, mInputManagerInternalMock);
 
+        LocalServices.removeServiceForTest(SensorManagerInternal.class);
+        LocalServices.addService(SensorManagerInternal.class, mSensorManagerInternalMock);
+
         final DisplayInfo displayInfo = new DisplayInfo();
         displayInfo.uniqueId = UNIQUE_ID;
         doReturn(displayInfo).when(mDisplayManagerInternalMock).getDisplayInfo(anyInt());
@@ -229,6 +296,7 @@
         mInputController = new InputController(new Object(), mNativeWrapperMock,
                 new Handler(TestableLooper.get(this).getLooper()),
                 mContext.getSystemService(WindowManager.class), threadVerifier);
+        mSensorController = new SensorController(new Object(), VIRTUAL_DEVICE_ID);
 
         mAssociationInfo = new AssociationInfo(1, 0, null,
                 MacAddress.BROADCAST_ADDRESS, "", null, null, true, false, false, 0, 0);
@@ -241,9 +309,9 @@
                 .setBlockedActivities(getBlockedActivities())
                 .build();
         mDeviceImpl = new VirtualDeviceImpl(mContext,
-                mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
-                mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
-                mActivityListener, mRunningAppsChangedCallback, params);
+                mAssociationInfo, new Binder(), /* ownerUid */ 0, VIRTUAL_DEVICE_ID,
+                mInputController, mSensorController, (int associationId) -> {},
+                mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
         mVdms.addVirtualDevice(mDeviceImpl);
     }
 
@@ -282,12 +350,12 @@
         VirtualDeviceParams params = new VirtualDeviceParams
                 .Builder()
                 .setBlockedActivities(getBlockedActivities())
-                .addDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
+                .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
                 .build();
         mDeviceImpl = new VirtualDeviceImpl(mContext,
-                mAssociationInfo, new Binder(), /* ownerUid */ 0, /* uniqueId */ 1,
-                mInputController, (int associationId) -> {}, mPendingTrampolineCallback,
-                mActivityListener, mRunningAppsChangedCallback, params);
+                mAssociationInfo, new Binder(), /* ownerUid */ 0, VIRTUAL_DEVICE_ID,
+                mInputController, mSensorController, (int associationId) -> {},
+                mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback, params);
         mVdms.addVirtualDevice(mDeviceImpl);
 
         assertThat(
@@ -298,7 +366,7 @@
     @Test
     public void onVirtualDisplayRemovedLocked_doesNotThrowException() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         // This call should not throw any exceptions.
         mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
     }
@@ -317,7 +385,7 @@
     public void onVirtualDisplayRemovedLocked_listenersNotified() {
         mLocalService.registerVirtualDisplayListener(mDisplayListener);
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
 
         mLocalService.onVirtualDisplayRemoved(mDeviceImpl, DISPLAY_ID);
         TestableLooper.get(this).processAllMessages();
@@ -379,7 +447,7 @@
                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
                 nullable(String.class), anyInt(), eq(null));
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         verify(mIPowerManagerMock).acquireWakeLock(any(Binder.class), anyInt(),
                 nullable(String.class), nullable(String.class), nullable(WorkSource.class),
                 nullable(String.class), eq(DISPLAY_ID), eq(null));
@@ -388,9 +456,10 @@
     @Test
     public void onVirtualDisplayCreatedLocked_duplicateCalls_onlyOneWakeLockIsAcquired()
             throws RemoteException {
-        GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController();
+        GenericWindowPolicyController gwpc = mDeviceImpl.createWindowPolicyController(
+                new ArrayList<>());
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         assertThrows(IllegalStateException.class,
                 () -> mDeviceImpl.onVirtualDisplayCreatedLocked(gwpc, DISPLAY_ID));
         TestableLooper.get(this).processAllMessages();
@@ -409,7 +478,7 @@
     @Test
     public void onVirtualDisplayRemovedLocked_wakeLockIsReleased() throws RemoteException {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
         TestableLooper.get(this).processAllMessages();
         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -425,7 +494,7 @@
     @Test
     public void addVirtualDisplay_displayNotReleased_wakeLockIsReleased() throws RemoteException {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         ArgumentCaptor<IBinder> wakeLockCaptor = ArgumentCaptor.forClass(IBinder.class);
         TestableLooper.get(this).processAllMessages();
         verify(mIPowerManagerMock).acquireWakeLock(wakeLockCaptor.capture(),
@@ -441,63 +510,77 @@
 
     @Test
     public void createVirtualDpad_noDisplay_failsSecurityException() {
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
     }
 
     @Test
     public void createVirtualKeyboard_noDisplay_failsSecurityException() {
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
     }
 
     @Test
     public void createVirtualMouse_noDisplay_failsSecurityException() {
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
     }
 
     @Test
     public void createVirtualTouchscreen_noDisplay_failsSecurityException() {
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME,
-                        VENDOR_ID, PRODUCT_ID, BINDER, new Point(WIDTH, HEIGHT)));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
     }
 
     @Test
     public void createVirtualTouchscreen_zeroDisplayDimension_failsIllegalArgumentException() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        Point size = new Point(0, 0);
+        final VirtualTouchscreenConfig zeroConfig =
+                new VirtualTouchscreenConfig.Builder()
+                        .setVendorId(VENDOR_ID)
+                        .setProductId(PRODUCT_ID)
+                        .setInputDeviceName(DEVICE_NAME)
+                        .setAssociatedDisplayId(DISPLAY_ID)
+                        .setWidthInPixels(0)
+                        .setHeightInPixels(0)
+                        .build();
         assertThrows(IllegalArgumentException.class,
-                () -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER, size));
+                () -> mDeviceImpl.createVirtualTouchscreen(zeroConfig, BINDER));
     }
 
     @Test
     public void createVirtualTouchscreen_negativeDisplayDimension_failsIllegalArgumentException() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        Point size = new Point(-100, -100);
+        final VirtualTouchscreenConfig negativeConfig =
+                new VirtualTouchscreenConfig.Builder()
+                        .setVendorId(VENDOR_ID)
+                        .setProductId(PRODUCT_ID)
+                        .setInputDeviceName(DEVICE_NAME)
+                        .setAssociatedDisplayId(DISPLAY_ID)
+                        .setWidthInPixels(-100)
+                        .setHeightInPixels(-100)
+                        .build();
         assertThrows(IllegalArgumentException.class,
-                () -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER, size));
+                () -> mDeviceImpl.createVirtualTouchscreen(negativeConfig, BINDER));
+
     }
 
     @Test
     public void createVirtualTouchscreen_positiveDisplayDimension_successful() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        Point size = new Point(600, 800);
-        mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER,
-                size);
+        VirtualTouchscreenConfig positiveConfig =
+                new VirtualTouchscreenConfig.Builder()
+                        .setVendorId(VENDOR_ID)
+                        .setProductId(PRODUCT_ID)
+                        .setInputDeviceName(DEVICE_NAME)
+                        .setAssociatedDisplayId(DISPLAY_ID)
+                        .setWidthInPixels(600)
+                        .setHeightInPixels(800)
+                        .build();
+        mDeviceImpl.createVirtualTouchscreen(positiveConfig, BINDER);
         assertWithMessage(
-                "Virtual touchscreen should create input device descriptor on successful creation.")
-                .that(mInputController.mInputDeviceDescriptors).isNotEmpty();
+                "Virtual touchscreen should create input device descriptor on successful creation"
+                        + ".").that(mInputController.getInputDeviceDescriptors()).isNotEmpty();
     }
 
     @Test
@@ -512,10 +595,8 @@
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
         doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER));
     }
 
     @Test
@@ -523,10 +604,8 @@
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
         doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER));
     }
 
     @Test
@@ -534,10 +613,8 @@
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
         doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
-        assertThrows(
-                SecurityException.class,
-                () -> mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID,
-                        PRODUCT_ID, BINDER));
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER));
     }
 
     @Test
@@ -545,10 +622,20 @@
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
         doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
                 eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
+        assertThrows(SecurityException.class,
+                () -> mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER));
+    }
+
+    @Test
+    public void createVirtualSensor_noPermission_failsSecurityException() {
+        doCallRealMethod().when(mContext).enforceCallingOrSelfPermission(
+                eq(Manifest.permission.CREATE_VIRTUAL_DEVICE), anyString());
         assertThrows(
                 SecurityException.class,
-                () -> mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME,
-                        VENDOR_ID, PRODUCT_ID, BINDER, new Point(WIDTH, HEIGHT)));
+                () -> mDeviceImpl.createVirtualSensor(
+                        BINDER,
+                        new VirtualSensorConfig.Builder(
+                                Sensor.TYPE_ACCELEROMETER, DEVICE_NAME).build()));
     }
 
     @Test
@@ -571,21 +658,19 @@
     @Test
     public void createVirtualDpad_hasDisplay_obtainFileDescriptor() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        mDeviceImpl.createVirtualDpad(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
-                BINDER);
-        assertWithMessage("Virtual dpad should register fd when the display matches")
-          	.that(mInputController.mInputDeviceDescriptors).isNotEmpty();
-        verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME), eq(VENDOR_ID),
-                eq(PRODUCT_ID), anyString());
+        mDeviceImpl.createVirtualDpad(DPAD_CONFIG, BINDER);
+        assertWithMessage("Virtual dpad should register fd when the display matches").that(
+                mInputController.getInputDeviceDescriptors()).isNotEmpty();
+        verify(mNativeWrapperMock).openUinputDpad(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
+                anyString());
     }
 
     @Test
     public void createVirtualKeyboard_hasDisplay_obtainFileDescriptor() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        mDeviceImpl.createVirtualKeyboard(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
-                BINDER);
-        assertWithMessage("Virtual keyboard should register fd when the display matches")
-                .that(mInputController.mInputDeviceDescriptors).isNotEmpty();
+        mDeviceImpl.createVirtualKeyboard(KEYBOARD_CONFIG, BINDER);
+        assertWithMessage("Virtual keyboard should register fd when the display matches").that(
+                mInputController.getInputDeviceDescriptors()).isNotEmpty();
         verify(mNativeWrapperMock).openUinputKeyboard(eq(DEVICE_NAME), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString());
     }
@@ -593,10 +678,9 @@
     @Test
     public void createVirtualMouse_hasDisplay_obtainFileDescriptor() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        mDeviceImpl.createVirtualMouse(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
-                BINDER);
-        assertWithMessage("Virtual mouse should register fd when the display matches")
-                .that(mInputController.mInputDeviceDescriptors).isNotEmpty();
+        mDeviceImpl.createVirtualMouse(MOUSE_CONFIG, BINDER);
+        assertWithMessage("Virtual mouse should register fd when the display matches").that(
+                mInputController.getInputDeviceDescriptors()).isNotEmpty();
         verify(mNativeWrapperMock).openUinputMouse(eq(DEVICE_NAME), eq(VENDOR_ID), eq(PRODUCT_ID),
                 anyString());
     }
@@ -604,10 +688,9 @@
     @Test
     public void createVirtualTouchscreen_hasDisplay_obtainFileDescriptor() {
         mDeviceImpl.mVirtualDisplayIds.add(DISPLAY_ID);
-        mDeviceImpl.createVirtualTouchscreen(DISPLAY_ID, DEVICE_NAME, VENDOR_ID, PRODUCT_ID,
-                BINDER, new Point(WIDTH, HEIGHT));
-        assertWithMessage("Virtual touchscreen should register fd when the display matches")
-                .that(mInputController.mInputDeviceDescriptors).isNotEmpty();
+        mDeviceImpl.createVirtualTouchscreen(TOUCHSCREEN_CONFIG, BINDER);
+        assertWithMessage("Virtual touchscreen should register fd when the display matches").that(
+                mInputController.getInputDeviceDescriptors()).isNotEmpty();
         verify(mNativeWrapperMock).openUinputTouchscreen(eq(DEVICE_NAME), eq(VENDOR_ID),
                 eq(PRODUCT_ID), anyString(), eq(HEIGHT), eq(WIDTH));
     }
@@ -625,7 +708,7 @@
     @Test
     public void onAudioSessionStarting_hasVirtualAudioController() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
 
         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
 
@@ -635,7 +718,7 @@
     @Test
     public void onAudioSessionEnded_noVirtualAudioController() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
 
         mDeviceImpl.onAudioSessionEnded();
@@ -646,7 +729,7 @@
     @Test
     public void close_cleanVirtualAudioController() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         mDeviceImpl.onAudioSessionStarting(DISPLAY_ID, mRoutingCallback, mConfigChangedCallback);
 
         mDeviceImpl.close();
@@ -655,6 +738,17 @@
     }
 
     @Test
+    public void close_cleanSensorController() {
+        mSensorController.addSensorForTesting(
+                BINDER, SENSOR_HANDLE, Sensor.TYPE_ACCELEROMETER, DEVICE_NAME);
+
+        mDeviceImpl.close();
+
+        assertThat(mSensorController.getSensorDescriptors()).isEmpty();
+        verify(mSensorManagerInternalMock).removeRuntimeSensor(SENSOR_HANDLE);
+    }
+
+    @Test
     public void sendKeyEvent_noFd() {
         assertThrows(
                 IllegalArgumentException.class,
@@ -850,9 +944,28 @@
         mDeviceImpl.mVirtualDisplayIds.add(1);
         mDeviceImpl.mVirtualDisplayIds.add(2);
         mDeviceImpl.mVirtualDisplayIds.add(3);
-        mDeviceImpl.createVirtualMouse(1, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
-        mDeviceImpl.createVirtualMouse(2, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
-        mDeviceImpl.createVirtualMouse(3, DEVICE_NAME, VENDOR_ID, PRODUCT_ID, BINDER);
+        VirtualMouseConfig config1 = new VirtualMouseConfig.Builder()
+                .setAssociatedDisplayId(1)
+                .setInputDeviceName(DEVICE_NAME)
+                .setVendorId(VENDOR_ID)
+                .setProductId(PRODUCT_ID)
+                .build();
+        VirtualMouseConfig config2 = new VirtualMouseConfig.Builder()
+                .setAssociatedDisplayId(2)
+                .setInputDeviceName(DEVICE_NAME)
+                .setVendorId(VENDOR_ID)
+                .setProductId(PRODUCT_ID)
+                .build();
+        VirtualMouseConfig config3 = new VirtualMouseConfig.Builder()
+                .setAssociatedDisplayId(3)
+                .setInputDeviceName(DEVICE_NAME)
+                .setVendorId(VENDOR_ID)
+                .setProductId(PRODUCT_ID)
+                .build();
+
+        mDeviceImpl.createVirtualMouse(config1, BINDER);
+        mDeviceImpl.createVirtualMouse(config2, BINDER);
+        mDeviceImpl.createVirtualMouse(config3, BINDER);
         mDeviceImpl.setShowPointerIcon(false);
         verify(mInputManagerInternalMock, times(3)).setPointerIconVisible(eq(false), anyInt());
         verify(mInputManagerInternalMock, never()).setPointerIconVisible(eq(true), anyInt());
@@ -863,14 +976,16 @@
     @Test
     public void openNonBlockedAppOnVirtualDisplay_doesNotStartBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 NONBLOCKED_APP_PACKAGE_NAME,
-                NONBLOCKED_APP_PACKAGE_NAME, /* displayOnRemoveDevices */ true);
+                NONBLOCKED_APP_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -882,14 +997,16 @@
     @Test
     public void openPermissionControllerOnVirtualDisplay_startBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 PERMISSION_CONTROLLER_PACKAGE_NAME,
-                PERMISSION_CONTROLLER_PACKAGE_NAME, /* displayOnRemoveDevices */  false);
+                PERMISSION_CONTROLLER_PACKAGE_NAME,
+                /* displayOnRemoveDevices */  false,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -901,14 +1018,16 @@
     @Test
     public void openSettingsOnVirtualDisplay_startBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 SETTINGS_PACKAGE_NAME,
-                SETTINGS_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
+                SETTINGS_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -920,14 +1039,16 @@
     @Test
     public void openVendingOnVirtualDisplay_startBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 VENDING_PACKAGE_NAME,
-                VENDING_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
+                VENDING_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -939,14 +1060,16 @@
     @Test
     public void openGoogleDialerOnVirtualDisplay_startBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 GOOGLE_DIALER_PACKAGE_NAME,
-                GOOGLE_DIALER_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
+                GOOGLE_DIALER_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -958,14 +1081,16 @@
     @Test
     public void openGoogleMapsOnVirtualDisplay_startBlockedAlertActivity() {
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         doNothing().when(mContext).startActivityAsUser(any(), any(), any());
 
         ArrayList<ActivityInfo> activityInfos = getActivityInfoList(
                 GOOGLE_MAPS_PACKAGE_NAME,
-                GOOGLE_MAPS_PACKAGE_NAME, /* displayOnRemoveDevices */  true);
+                GOOGLE_MAPS_PACKAGE_NAME,
+                /* displayOnRemoveDevices */ true,
+                /* targetDisplayCategory */ null);
         Intent blockedAppIntent = BlockedAppStreamingActivity.createIntent(
                 activityInfos.get(0), mAssociationInfo.getDisplayName());
         gwpc.canContainActivities(activityInfos, WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
@@ -978,7 +1103,7 @@
     public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() {
         ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
 
@@ -993,7 +1118,7 @@
     public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
         ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
         mDeviceImpl.onVirtualDisplayCreatedLocked(
-                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
+                mDeviceImpl.createWindowPolicyController(new ArrayList<>()), DISPLAY_ID);
         GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                 DISPLAY_ID);
         mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);
@@ -1003,4 +1128,37 @@
 
         assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
     }
+
+    @Test
+    public void nonRestrictedActivityOnRestrictedVirtualDisplay_startBlockedAlertActivity() {
+        Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"),
+                /* targetDisplayCategory= */ null);
+        verify(mContext).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+
+    }
+
+    @Test
+    public void restrictedActivityOnRestrictedVirtualDisplay_doesNotStartBlockedAlertActivity() {
+        Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "abc");
+        verify(mContext, never()).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
+    @Test
+    public void restrictedActivityOnNonRestrictedVirtualDisplay_startBlockedAlertActivity() {
+        Intent blockedAppIntent = createRestrictedActivityBlockedIntent(
+                /* displayCategories= */ List.of(), "abc");
+        verify(mContext).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
+    @Test
+    public void
+            restrictedActivityOnNonMatchingRestrictedVirtualDisplay_startBlockedAlertActivity() {
+        Intent blockedAppIntent = createRestrictedActivityBlockedIntent(List.of("abc"), "def");
+        verify(mContext).startActivityAsUser(argThat(intent ->
+                intent.filterEquals(blockedAppIntent)), any(), any());
+    }
+
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
index 036b6df..aefe4b6 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceParamsTest.java
@@ -16,9 +16,14 @@
 
 package com.android.server.companion.virtual;
 
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
+import static android.hardware.Sensor.TYPE_ACCELEROMETER;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import android.companion.virtual.VirtualDeviceParams;
+import android.companion.virtual.sensor.VirtualSensorConfig;
 import android.os.Parcel;
 import android.os.UserHandle;
 
@@ -27,18 +32,25 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
 import java.util.Set;
 
 @RunWith(AndroidJUnit4.class)
 public class VirtualDeviceParamsTest {
 
+    private static final String SENSOR_NAME = "VirtualSensorName";
+    private static final String SENSOR_VENDOR = "VirtualSensorVendor";
+
     @Test
     public void parcelable_shouldRecreateSuccessfully() {
         VirtualDeviceParams originalParams = new VirtualDeviceParams.Builder()
                 .setLockState(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED)
                 .setUsersWithMatchingAccounts(Set.of(UserHandle.of(123), UserHandle.of(456)))
-                .addDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS,
-                        VirtualDeviceParams.DEVICE_POLICY_CUSTOM)
+                .setDevicePolicy(POLICY_TYPE_SENSORS, DEVICE_POLICY_CUSTOM)
+                .addVirtualSensorConfig(
+                        new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
+                                .setVendor(SENSOR_VENDOR)
+                                .build())
                 .build();
         Parcel parcel = Parcel.obtain();
         originalParams.writeToParcel(parcel, 0);
@@ -49,7 +61,14 @@
         assertThat(params.getLockState()).isEqualTo(VirtualDeviceParams.LOCK_STATE_ALWAYS_UNLOCKED);
         assertThat(params.getUsersWithMatchingAccounts())
                 .containsExactly(UserHandle.of(123), UserHandle.of(456));
-        assertThat(params.getDevicePolicy(VirtualDeviceParams.POLICY_TYPE_SENSORS))
-                .isEqualTo(VirtualDeviceParams.DEVICE_POLICY_CUSTOM);
+        assertThat(params.getDevicePolicy(POLICY_TYPE_SENSORS)).isEqualTo(DEVICE_POLICY_CUSTOM);
+
+        List<VirtualSensorConfig> sensorConfigs = params.getVirtualSensorConfigs();
+        assertThat(sensorConfigs).hasSize(1);
+        VirtualSensorConfig sensorConfig = sensorConfigs.get(0);
+        assertThat(sensorConfig.getType()).isEqualTo(TYPE_ACCELEROMETER);
+        assertThat(sensorConfig.getName()).isEqualTo(SENSOR_NAME);
+        assertThat(sensorConfig.getVendor()).isEqualTo(SENSOR_VENDOR);
+        assertThat(sensorConfig.getStateChangeCallback()).isNull();
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 0262f56..3ca648c 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -72,22 +72,25 @@
         MockitoAnnotations.initMocks(this);
         mContext = Mockito.spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
         mVirtualAudioController = new VirtualAudioController(mContext);
-        mGenericWindowPolicyController = new GenericWindowPolicyController(
-                FLAG_SECURE,
-                SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
-                /* allowedUsers= */ new ArraySet<>(),
-                /* allowedCrossTaskNavigations= */ new ArraySet<>(),
-                /* blockedCrossTaskNavigations= */ new ArraySet<>(),
-                /* allowedActivities= */ new ArraySet<>(),
-                /* blockedActivities= */ new ArraySet<>(),
-                VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
-                /* activityListener= */ null,
-                /* pipBlockedCallback= */ null,
-                /* activityBlockedCallback= */ null,
-                /* secureWindowCallback= */ null,
-                /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING);
+        mGenericWindowPolicyController =
+                new GenericWindowPolicyController(
+                        FLAG_SECURE,
+                        SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+                        /* allowedUsers= */ new ArraySet<>(),
+                        /* allowedCrossTaskNavigations= */ new ArraySet<>(),
+                        /* blockedCrossTaskNavigations= */ new ArraySet<>(),
+                        /* allowedActivities= */ new ArraySet<>(),
+                        /* blockedActivities= */ new ArraySet<>(),
+                        VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
+                        /* activityListener= */ null,
+                        /* pipBlockedCallback= */ null,
+                        /* activityBlockedCallback= */ null,
+                        /* secureWindowCallback= */ null,
+                        /* deviceProfile= */ DEVICE_PROFILE_APP_STREAMING,
+                        /* displayCategories= */ new ArrayList<>());
     }
 
+
     @Test
     public void startListening_receivesCallback() throws RemoteException {
         ArraySet<Integer> runningUids = new ArraySet<>();
diff --git a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
index c2a81d9..d4e3d44 100644
--- a/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/content/SyncManagerTest.java
@@ -16,12 +16,40 @@
 
 package com.android.server.content;
 
+import static android.content.pm.UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT;
+import static android.content.pm.UserProperties.SHOW_IN_LAUNCHER_WITH_PARENT;
+import static android.content.pm.UserProperties.SHOW_IN_SETTINGS_WITH_PARENT;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.accounts.AccountManagerInternal;
 import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
 import android.os.Bundle;
+import android.os.UserManager;
+import android.provider.ContactsContract;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import androidx.test.core.app.ApplicationProvider;
+
+import com.android.server.job.JobSchedulerInternal;
+
 import junit.framework.TestCase;
 
+import org.jetbrains.annotations.NotNull;
+import org.junit.Before;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+
 /**
  * Tests for SyncManager.
  *
@@ -33,6 +61,43 @@
     final String KEY_1 = "key_1";
     final String KEY_2 = "key_2";
 
+    private SyncManager mSyncManager;
+    private Context mContext;
+
+    @Mock
+    private UserManager mUserManager;
+    @Mock
+    private AccountManagerInternal mAccountManagerInternal;
+    @Mock
+    private JobSchedulerInternal mJobSchedulerInternal;
+
+    private class SyncManagerWithMockedServices extends SyncManager {
+
+        @Override
+        protected AccountManagerInternal getAccountManagerInternal() {
+            return mAccountManagerInternal;
+        }
+
+        @Override
+        protected JobSchedulerInternal getJobSchedulerInternal() {
+            return mJobSchedulerInternal;
+        }
+
+        private SyncManagerWithMockedServices(Context context, boolean factoryTest) {
+            super(context, factoryTest);
+        }
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = spy(ApplicationProvider.getApplicationContext());
+        when(mContext.getSystemService(Context.USER_SERVICE)).thenReturn(mUserManager);
+        doNothing().when(mAccountManagerInternal).addOnAppPermissionChangeListener(any());
+        when(mJobSchedulerInternal.getSystemScheduledPendingJobs()).thenReturn(new ArrayList<>());
+        mSyncManager = new SyncManagerWithMockedServices(mContext, true);
+    }
+
     public void testSyncExtrasEquals_WithNull() throws Exception {
         Bundle b1 = new Bundle();
         Bundle b2 = new Bundle();
@@ -140,4 +205,45 @@
         final StringBuilder sb = new StringBuilder();
         assertEquals(expected, SyncManager.formatDurationHMS(sb, time * 1000).toString());
     }
+
+    private UserInfo createUserInfo(String name, int id, int groupId, int flags) {
+        final UserInfo ui = new UserInfo(id, name, flags | UserInfo.FLAG_INITIALIZED);
+        ui.profileGroupId = groupId;
+        return ui;
+    }
+
+    @NotNull
+    private UserProperties getCloneUserProperties() {
+        return new UserProperties.Builder()
+                .setStartWithParent(true)
+                .setShowInLauncher(SHOW_IN_LAUNCHER_WITH_PARENT)
+                .setShowInSettings(SHOW_IN_SETTINGS_WITH_PARENT)
+                .setUseParentsContacts(true)
+                .setInheritDevicePolicy(INHERIT_DEVICE_POLICY_FROM_PARENT)
+                .build();
+    }
+
+    private void mockUserProperties(UserInfo primaryUserInfo, UserInfo cloneUserInfo) {
+        UserProperties cloneUserProperties = getCloneUserProperties();
+        when(mUserManager.getUserProperties(cloneUserInfo.getUserHandle()))
+                .thenReturn(cloneUserProperties);
+        // Set default user properties for primary user
+        when(mUserManager.getUserProperties(primaryUserInfo.getUserHandle()))
+                .thenReturn(new UserProperties.Builder().build());
+    }
+
+    public void testShouldDisableSync() {
+        UserInfo primaryUserInfo = createUserInfo("primary", 0 /* id */, 0 /* groupId */,
+                UserInfo.FLAG_PRIMARY | UserInfo.FLAG_ADMIN);
+        UserInfo cloneUserInfo = createUserInfo("clone", 10 /* id */, 0 /* groupId */,
+                UserInfo.FLAG_PROFILE);
+
+        mockUserProperties(primaryUserInfo, cloneUserInfo);
+
+        // Clone user accounts must have contact syncs disabled
+        assertThat(mSyncManager.shouldDisableSyncForUser(cloneUserInfo,
+                ContactsContract.AUTHORITY)).isTrue();
+        assertThat(mSyncManager.shouldDisableSyncForUser(primaryUserInfo,
+                ContactsContract.AUTHORITY)).isFalse();
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
index 0206839..ae36871 100644
--- a/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/AutomaticBrightnessControllerTest.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.display.AutomaticBrightnessController.AUTO_BRIGHTNESS_ENABLED;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
@@ -176,7 +177,7 @@
 
         // Send new sensor value and verify
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1));
-        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), 0.001f);
+        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON);
 
         // Set up system to return 0.0f (minimum possible brightness) as a brightness value
         float lux2 = 10.0f;
@@ -190,7 +191,7 @@
 
         // Send new sensor value and verify
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2));
-        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), 0.001f);
+        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON);
     }
 
     @Test
@@ -219,7 +220,7 @@
 
         // Send new sensor value and verify
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux1));
-        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), 0.001f);
+        assertEquals(normalizedBrightness1, mController.getAutomaticScreenBrightness(), EPSILON);
 
 
         // Set up system to return 1.0f as a brightness value (brightness_max)
@@ -234,7 +235,7 @@
 
         // Send new sensor value and verify
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, (int) lux2));
-        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), 0.001f);
+        assertEquals(normalizedBrightness2, mController.getAutomaticScreenBrightness(), EPSILON);
     }
 
     @Test
@@ -416,6 +417,12 @@
         // ambient lux goes to 0
         listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, 0));
         assertEquals(0.0f, mController.getAmbientLux(), EPSILON);
+
+        // only the values within the horizon should be kept
+        assertArrayEquals(new float[] {10000, 10000, 0, 0, 0}, mController.getLastSensorValues(),
+                EPSILON);
+        assertArrayEquals(new long[] {4000, 4500, 5000, 5500, 6000},
+                mController.getLastSensorTimestamps());
     }
 
     @Test
@@ -487,4 +494,92 @@
                 0 /* adjustment */, false /* userChanged */, DisplayPowerRequest.POLICY_BRIGHT);
         assertEquals(BRIGHTNESS_MAX_FLOAT, mController.getAutomaticScreenBrightness(), 0.0f);
     }
+
+    @Test
+    public void testGetSensorReadings() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+
+        // Choose values such that the ring buffer's capacity is extended and the buffer is pruned
+        int increment = 11;
+        int lux = 5000;
+        for (int i = 0; i < 1000; i++) {
+            lux += increment;
+            mClock.fastForward(increment);
+            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+        }
+
+        int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment + 1);
+        float[] sensorValues = mController.getLastSensorValues();
+        long[] sensorTimestamps = mController.getLastSensorTimestamps();
+
+        // Only the values within the horizon should be kept
+        assertEquals(valuesCount, sensorValues.length);
+        assertEquals(valuesCount, sensorTimestamps.length);
+
+        long sensorTimestamp = mClock.now();
+        for (int i = valuesCount - 1; i >= 1; i--) {
+            assertEquals(lux, sensorValues[i], EPSILON);
+            assertEquals(sensorTimestamp, sensorTimestamps[i]);
+            lux -= increment;
+            sensorTimestamp -= increment;
+        }
+        assertEquals(lux, sensorValues[0], EPSILON);
+        assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+    }
+
+    @Test
+    public void testGetSensorReadingsFullBuffer() throws Exception {
+        ArgumentCaptor<SensorEventListener> listenerCaptor =
+                ArgumentCaptor.forClass(SensorEventListener.class);
+        verify(mSensorManager).registerListener(listenerCaptor.capture(), eq(mLightSensor),
+                eq(INITIAL_LIGHT_SENSOR_RATE * 1000), any(Handler.class));
+        SensorEventListener listener = listenerCaptor.getValue();
+        int initialCapacity = 150;
+
+        // Choose values such that the ring buffer is pruned
+        int increment1 = 200;
+        int lux = 5000;
+        for (int i = 0; i < 20; i++) {
+            lux += increment1;
+            mClock.fastForward(increment1);
+            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+        }
+
+        int valuesCount = (int) Math.ceil((double) AMBIENT_LIGHT_HORIZON_LONG / increment1 + 1);
+
+        // Choose values such that the buffer becomes full
+        int increment2 = 1;
+        for (int i = 0; i < initialCapacity - valuesCount; i++) {
+            lux += increment2;
+            mClock.fastForward(increment2);
+            listener.onSensorChanged(TestUtils.createSensorEvent(mLightSensor, lux));
+        }
+
+        float[] sensorValues = mController.getLastSensorValues();
+        long[] sensorTimestamps = mController.getLastSensorTimestamps();
+
+        // The buffer should be full
+        assertEquals(initialCapacity, sensorValues.length);
+        assertEquals(initialCapacity, sensorTimestamps.length);
+
+        long sensorTimestamp = mClock.now();
+        for (int i = initialCapacity - 1; i >= 1; i--) {
+            assertEquals(lux, sensorValues[i], EPSILON);
+            assertEquals(sensorTimestamp, sensorTimestamps[i]);
+
+            if (i >= valuesCount) {
+                lux -= increment2;
+                sensorTimestamp -= increment2;
+            } else {
+                lux -= increment1;
+                sensorTimestamp -= increment1;
+            }
+        }
+        assertEquals(lux, sensorValues[0], EPSILON);
+        assertEquals(mClock.now() - AMBIENT_LIGHT_HORIZON_LONG, sensorTimestamps[0]);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index c2e8417f..6def7b1 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -136,28 +136,28 @@
         assertNull(mInjector.mSensorListener);
         assertNotNull(mInjector.mBroadcastReceiver);
         assertTrue(mInjector.mIdleScheduled);
-        mInjector.sendScreenChange(/*screen on */ true);
+        mInjector.sendScreenChange(/* screenOn= */ true);
         assertNotNull(mInjector.mSensorListener);
         assertTrue(mInjector.mColorSamplingEnabled);
 
-        mInjector.sendScreenChange(/*screen on */ false);
+        mInjector.sendScreenChange(/* screenOn= */ false);
         assertNull(mInjector.mSensorListener);
         assertFalse(mInjector.mColorSamplingEnabled);
 
         // Turn screen on while brightness mode is manual
-        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic */ false);
-        mInjector.sendScreenChange(/*screen on */ true);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ false);
+        mInjector.sendScreenChange(/* screenOn= */ true);
         assertNull(mInjector.mSensorListener);
         assertFalse(mInjector.mColorSamplingEnabled);
 
         // Set brightness mode to automatic while screen is off.
-        mInjector.sendScreenChange(/*screen on */ false);
-        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic */ true);
+        mInjector.sendScreenChange(/* screenOn= */ false);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true);
         assertNull(mInjector.mSensorListener);
         assertFalse(mInjector.mColorSamplingEnabled);
 
         // Turn on screen while brightness mode is automatic.
-        mInjector.sendScreenChange(/*screen on */ true);
+        mInjector.sendScreenChange(/* screenOn= */ true);
         assertNotNull(mInjector.mSensorListener);
         assertTrue(mInjector.mColorSamplingEnabled);
 
@@ -188,14 +188,14 @@
         assertFalse(mInjector.mColorSamplingEnabled);
 
         // Pretend screen is off, update config to turn on color sampling.
-        mInjector.sendScreenChange(/*screen on */ false);
+        mInjector.sendScreenChange(/* screenOn= */ false);
         mTracker.setBrightnessConfiguration(buildBrightnessConfiguration(
                 /* collectColorSamples= */ true));
         mInjector.waitForHandler();
         assertFalse(mInjector.mColorSamplingEnabled);
 
         // Pretend screen is on.
-        mInjector.sendScreenChange(/*screen on */ true);
+        mInjector.sendScreenChange(/* screenOn= */ true);
         assertTrue(mInjector.mColorSamplingEnabled);
 
         mTracker.stop();
@@ -261,7 +261,7 @@
         assertFalse(mInjector.mColorSamplingEnabled);
         assertNull(mInjector.mDisplayListener);
 
-        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ true);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true);
         assertNotNull(mInjector.mSensorListener);
         assertTrue(mInjector.mColorSamplingEnabled);
         assertNotNull(mInjector.mDisplayListener);
@@ -272,16 +272,15 @@
         mInjector.mColorSamplingEnabled = false;
         mInjector.mDisplayListener = null;
         // Duplicate notification
-        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ true);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ true);
         // Sensor shouldn't have been registered as it was already registered.
         assertNull(mInjector.mSensorListener);
         assertFalse(mInjector.mColorSamplingEnabled);
         assertNull(mInjector.mDisplayListener);
-        mInjector.mSensorListener = listener;
         mInjector.mDisplayListener = displayListener;
         mInjector.mColorSamplingEnabled = true;
 
-        mInjector.setBrightnessMode(/*isBrightnessModeAutomatic*/ false);
+        mInjector.setBrightnessMode(/* isBrightnessModeAutomatic= */ false);
         assertNull(mInjector.mSensorListener);
         assertFalse(mInjector.mColorSamplingEnabled);
         assertNull(mInjector.mDisplayListener);
@@ -301,19 +300,21 @@
         final String displayId = "1234";
 
         startTracker(mTracker);
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
+        final long sensorTime = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos());
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
-        notifyBrightnessChanged(mTracker, brightness, displayId);
+        final long currentTime = mInjector.currentTimeMillis();
+        notifyBrightnessChanged(mTracker, brightness, displayId, new float[] {1.0f},
+                new long[] {sensorTime});
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
         mTracker.stop();
 
         assertEquals(1, events.size());
         BrightnessChangeEvent event = events.get(0);
-        assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
+        assertEquals(currentTime, event.timeStamp);
         assertEquals(displayId, event.uniqueDisplayId);
         assertEquals(1, event.luxValues.length);
         assertEquals(1.0f, event.luxValues[0], FLOAT_DELTA);
-        assertEquals(mInjector.currentTimeMillis() - TimeUnit.SECONDS.toMillis(2),
+        assertEquals(currentTime - TimeUnit.SECONDS.toMillis(2),
                 event.luxTimestamps[0]);
         assertEquals(brightness, event.brightness, FLOAT_DELTA);
         assertEquals(DEFAULT_INITIAL_BRIGHTNESS, event.lastBrightness, FLOAT_DELTA);
@@ -339,9 +340,9 @@
         startTracker(mTracker, initialBrightness, DEFAULT_COLOR_SAMPLING_ENABLED);
         mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
                 batteryChangeEvent(30, 60));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
-        final long sensorTime = mInjector.currentTimeMillis();
-        notifyBrightnessChanged(mTracker, brightness, displayId);
+        final long currentTime = mInjector.currentTimeMillis();
+        notifyBrightnessChanged(mTracker, brightness, displayId, new float[] {1000.0f},
+                new long[] {TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos())});
         List<BrightnessChangeEvent> eventsNoPackage
                 = mTracker.getEvents(0, false).getList();
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
@@ -349,10 +350,10 @@
 
         assertEquals(1, events.size());
         BrightnessChangeEvent event = events.get(0);
-        assertEquals(event.timeStamp, mInjector.currentTimeMillis());
+        assertEquals(event.timeStamp, currentTime);
         assertEquals(displayId, event.uniqueDisplayId);
-        assertArrayEquals(new float[] {1000.0f}, event.luxValues, 0.01f);
-        assertArrayEquals(new long[] {sensorTime}, event.luxTimestamps);
+        assertArrayEquals(new float[] {1000.0f}, event.luxValues, FLOAT_DELTA);
+        assertArrayEquals(new long[] {currentTime}, event.luxTimestamps);
         assertEquals(brightness, event.brightness, FLOAT_DELTA);
         assertEquals(initialBrightness, event.lastBrightness, FLOAT_DELTA);
         assertEquals(0.5, event.batteryLevel, FLOAT_DELTA);
@@ -374,13 +375,12 @@
     public void testIgnoreAutomaticBrightnessChange() {
         final int initialBrightness = 30;
         startTracker(mTracker, initialBrightness, DEFAULT_COLOR_SAMPLING_ENABLED);
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
 
         final int systemUpdatedBrightness = 20;
-        notifyBrightnessChanged(mTracker, systemUpdatedBrightness, false /*userInitiated*/,
-                0.5f /*powerBrightnessFactor(*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/, DEFAULT_DISPLAY_ID);
+        notifyBrightnessChanged(mTracker, systemUpdatedBrightness, /* userInitiated= */ false,
+                /* powerBrightnessFactor= */ 0.5f, /* isUserSetBrightness= */ false,
+                /* isDefaultBrightnessConfig= */ false, DEFAULT_DISPLAY_ID);
         List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
         // No events because we filtered out our change.
         assertEquals(0, events.size());
@@ -408,10 +408,8 @@
     @Test
     public void testLimitedBufferSize() {
         startTracker(mTracker);
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
 
         for (int brightness = 0; brightness <= 255; ++brightness) {
-            mInjector.mSensorListener.onSensorChanged(createSensorEvent(1.0f));
             mInjector.incrementTime(TimeUnit.SECONDS.toNanos(1));
             notifyBrightnessChanged(mTracker, brightness);
         }
@@ -427,33 +425,6 @@
     }
 
     @Test
-    public void testLimitedSensorEvents() {
-        final int brightness = 20;
-
-        startTracker(mTracker);
-        // 20 Sensor events 1 second apart.
-        for (int i = 0; i < 20; ++i) {
-            mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
-            mInjector.mSensorListener.onSensorChanged(createSensorEvent(i + 1.0f));
-        }
-        notifyBrightnessChanged(mTracker, 20);
-        List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
-        mTracker.stop();
-
-        assertEquals(1, events.size());
-        BrightnessChangeEvent event = events.get(0);
-        assertEquals(mInjector.currentTimeMillis(), event.timeStamp);
-
-        // 12 sensor events, 11 for 0->10 seconds + 1 previous event.
-        assertEquals(12, event.luxValues.length);
-        for (int i = 0; i < 12; ++i) {
-            assertEquals(event.luxTimestamps[11 - i],
-                    mInjector.currentTimeMillis() - i * TimeUnit.SECONDS.toMillis(1));
-        }
-        assertEquals(brightness, event.brightness, FLOAT_DELTA);
-    }
-
-    @Test
     public void testReadEvents() throws Exception {
         BrightnessTracker tracker = new BrightnessTracker(InstrumentationRegistry.getContext(),
                 mInjector);
@@ -607,15 +578,16 @@
         startTracker(mTracker);
         mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
                 batteryChangeEvent(30, 100));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(2000.0f));
-        final long firstSensorTime = mInjector.currentTimeMillis();
+        final long elapsedTime1 = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos());
+        final long currentTime1 = mInjector.currentTimeMillis();
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(3000.0f));
-        final long secondSensorTime = mInjector.currentTimeMillis();
+        final long elapsedTime2 = TimeUnit.NANOSECONDS.toMillis(mInjector.elapsedRealtimeNanos());
+        final long currentTime2 = mInjector.currentTimeMillis();
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(3));
-        notifyBrightnessChanged(mTracker, brightness, true /*userInitiated*/,
-                0.5f /*powerBrightnessFactor*/, true /*hasUserBrightnessPoints*/,
-                false /*isDefaultBrightnessConfig*/, displayId);
+        notifyBrightnessChanged(mTracker, brightness, /* userInitiated= */ true,
+                /* powerBrightnessFactor= */ 0.5f, /* isUserSetBrightness= */ true,
+                /* isDefaultBrightnessConfig= */ false, displayId, new float[] {2000.0f, 3000.0f},
+                new long[] {elapsedTime1, elapsedTime2});
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         mTracker.writeEventsLocked(baos);
         mTracker.stop();
@@ -631,7 +603,7 @@
         BrightnessChangeEvent event = events.get(0);
         assertEquals(displayId, event.uniqueDisplayId);
         assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA);
-        assertArrayEquals(new long[] {firstSensorTime, secondSensorTime}, event.luxTimestamps);
+        assertArrayEquals(new long[] {currentTime1, currentTime2}, event.luxTimestamps);
         assertEquals(brightness, event.brightness, FLOAT_DELTA);
         assertEquals(0.3, event.batteryLevel, FLOAT_DELTA);
         assertTrue(event.nightMode);
@@ -647,53 +619,6 @@
     }
 
     @Test
-    public void testWritePrunesOldEvents() throws Exception {
-        final int brightness = 20;
-
-        mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_ACTIVATED, 1);
-        mInjector.mSecureIntSettings.put(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, 3339);
-
-        mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_ACTIVATED, 1);
-        mInjector.mSecureIntSettings.put(Settings.Secure.REDUCE_BRIGHT_COLORS_LEVEL, 40);
-
-        startTracker(mTracker);
-        mInjector.mBroadcastReceiver.onReceive(InstrumentationRegistry.getContext(),
-                batteryChangeEvent(30, 100));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(1000.0f));
-        mInjector.incrementTime(TimeUnit.SECONDS.toMillis(1));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(2000.0f));
-        final long sensorTime = mInjector.currentTimeMillis();
-        notifyBrightnessChanged(mTracker, brightness);
-
-        // 31 days later
-        mInjector.incrementTime(TimeUnit.DAYS.toMillis(31));
-        mInjector.mSensorListener.onSensorChanged(createSensorEvent(3000.0f));
-        notifyBrightnessChanged(mTracker, brightness);
-        final long eventTime = mInjector.currentTimeMillis();
-
-        List<BrightnessChangeEvent> events = mTracker.getEvents(0, true).getList();
-        assertEquals(2, events.size());
-
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        mTracker.writeEventsLocked(baos);
-        events = mTracker.getEvents(0, true).getList();
-        mTracker.stop();
-
-        assertEquals(1, events.size());
-        BrightnessChangeEvent event = events.get(0);
-        assertEquals(eventTime, event.timeStamp);
-
-        // We will keep one of the old sensor events because we keep 1 event outside the window.
-        assertArrayEquals(new float[] {2000.0f, 3000.0f}, event.luxValues, FLOAT_DELTA);
-        assertArrayEquals(new long[] {sensorTime, eventTime}, event.luxTimestamps);
-        assertEquals(brightness, event.brightness, FLOAT_DELTA);
-        assertEquals(0.3, event.batteryLevel, FLOAT_DELTA);
-        assertTrue(event.nightMode);
-        assertTrue(event.reduceBrightColors);
-        assertEquals(3339, event.colorTemperature);
-    }
-
-    @Test
     public void testParcelUnParcel() {
         Parcel parcel = Parcel.obtain();
         BrightnessChangeEvent.Builder builder = new BrightnessChangeEvent.Builder();
@@ -796,9 +721,10 @@
 
         // Send an event.
         long eventTime = mInjector.currentTimeMillis();
-        mTracker.notifyBrightnessChanged(brightness, true /*userInitiated*/,
-                1.0f /*powerBrightnessFactor*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/, DEFAULT_DISPLAY_ID);
+        mTracker.notifyBrightnessChanged(brightness, /* userInitiated= */ true,
+                /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false,
+                /* isDefaultBrightnessConfig= */ false, DEFAULT_DISPLAY_ID, new float[10],
+                new long[10]);
 
         // Time passes before handler can run.
         mInjector.incrementTime(TimeUnit.SECONDS.toMillis(2));
@@ -890,20 +816,33 @@
     public void testOnlyOneReceiverRegistered() {
         assertNull(mInjector.mLightSensor);
         assertNull(mInjector.mSensorListener);
+        assertNull(mInjector.mContentObserver);
+        assertNull(mInjector.mBroadcastReceiver);
+        assertFalse(mInjector.mIdleScheduled);
         startTracker(mTracker, 0.3f, false);
 
         assertNotNull(mInjector.mLightSensor);
         assertNotNull(mInjector.mSensorListener);
+        assertNotNull(mInjector.mContentObserver);
+        assertNotNull(mInjector.mBroadcastReceiver);
+        assertTrue(mInjector.mIdleScheduled);
         Sensor registeredLightSensor = mInjector.mLightSensor;
         SensorEventListener registeredSensorListener = mInjector.mSensorListener;
+        ContentObserver registeredContentObserver = mInjector.mContentObserver;
+        BroadcastReceiver registeredBroadcastReceiver = mInjector.mBroadcastReceiver;
 
         mTracker.start(0.3f);
         assertSame(registeredLightSensor, mInjector.mLightSensor);
         assertSame(registeredSensorListener, mInjector.mSensorListener);
+        assertSame(registeredContentObserver, mInjector.mContentObserver);
+        assertSame(registeredBroadcastReceiver, mInjector.mBroadcastReceiver);
 
         mTracker.stop();
         assertNull(mInjector.mLightSensor);
         assertNull(mInjector.mSensorListener);
+        assertNull(mInjector.mContentObserver);
+        assertNull(mInjector.mBroadcastReceiver);
+        assertFalse(mInjector.mIdleScheduled);
 
         // mInjector asserts that we aren't removing a null receiver
         mTracker.stop();
@@ -954,23 +893,41 @@
 
     private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
             String displayId) {
-        notifyBrightnessChanged(tracker, brightness, true /*userInitiated*/,
-                1.0f /*powerBrightnessFactor*/, false /*isUserSetBrightness*/,
-                false /*isDefaultBrightnessConfig*/, displayId);
+        notifyBrightnessChanged(tracker, brightness, /* userInitiated= */ true,
+                /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false,
+                /* isDefaultBrightnessConfig= */ false, displayId, new float[10], new long[10]);
+    }
+
+    private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
+            String displayId, float[] luxValues, long[] luxTimestamps) {
+        notifyBrightnessChanged(tracker, brightness, /* userInitiated= */ true,
+                /* powerBrightnessFactor= */ 1.0f, /* isUserSetBrightness= */ false,
+                /* isDefaultBrightnessConfig= */ false, displayId, luxValues, luxTimestamps);
     }
 
     private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
             boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness,
             boolean isDefaultBrightnessConfig, String displayId) {
         tracker.notifyBrightnessChanged(brightness, userInitiated, powerBrightnessFactor,
-                isUserSetBrightness, isDefaultBrightnessConfig, displayId);
+                isUserSetBrightness, isDefaultBrightnessConfig, displayId, new float[10],
+                new long[10]);
+        mInjector.waitForHandler();
+    }
+
+    private void notifyBrightnessChanged(BrightnessTracker tracker, float brightness,
+            boolean userInitiated, float powerBrightnessFactor, boolean isUserSetBrightness,
+            boolean isDefaultBrightnessConfig, String displayId, float[] luxValues,
+            long[] luxTimestamps) {
+        tracker.notifyBrightnessChanged(brightness, userInitiated, powerBrightnessFactor,
+                isUserSetBrightness, isDefaultBrightnessConfig, displayId, luxValues,
+                luxTimestamps);
         mInjector.waitForHandler();
     }
 
     private BrightnessConfiguration buildBrightnessConfiguration(boolean collectColorSamples) {
         BrightnessConfiguration.Builder builder = new BrightnessConfiguration.Builder(
-                /* lux = */ new float[] {0f, 10f, 100f},
-                /* nits = */ new float[] {1f, 90f, 100f});
+                /* lux= */ new float[] {0f, 10f, 100f},
+                /* nits= */ new float[] {1f, 90f, 100f});
         builder.setShouldCollectColorSamples(collectColorSamples);
         return builder.build();
     }
diff --git a/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
new file mode 100644
index 0000000..bcae50e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/DeviceStateToLayoutMapTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display;
+
+
+import static org.junit.Assert.assertEquals;
+
+import android.view.DisplayAddress;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.display.layout.DisplayIdProducer;
+import com.android.server.display.layout.Layout;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+
+@SmallTest
+public class DeviceStateToLayoutMapTest {
+    private DeviceStateToLayoutMap mDeviceStateToLayoutMap;
+
+    @Mock DisplayIdProducer mDisplayIdProducerMock;
+
+    @Before
+    public void setUp() throws IOException {
+        MockitoAnnotations.initMocks(this);
+
+        Mockito.when(mDisplayIdProducerMock.getId(false)).thenReturn(1);
+
+        setupDeviceStateToLayoutMap();
+    }
+
+    //////////////////
+    // Test Methods //
+    //////////////////
+
+    @Test
+    public void testInitialState() {
+        Layout configLayout = mDeviceStateToLayoutMap.get(0);
+
+        Layout testLayout = new Layout();
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(123456L), /* isDefault= */ true,
+                /* isEnabled= */ true, mDisplayIdProducerMock);
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(78910L), /* isDefault= */ false,
+                /* isEnabled= */ false, mDisplayIdProducerMock);
+        assertEquals(testLayout, configLayout);
+    }
+
+    @Test
+    public void testSwitchedState() {
+        Layout configLayout = mDeviceStateToLayoutMap.get(1);
+
+        Layout testLayout = new Layout();
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(78910L), /* isDefault= */ true,
+                /* isEnabled= */ true, mDisplayIdProducerMock);
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(123456L), /* isDefault= */ false,
+                /* isEnabled= */ false, mDisplayIdProducerMock);
+
+        assertEquals(testLayout, configLayout);
+    }
+
+    @Test
+    public void testConcurrentState() {
+        Layout configLayout = mDeviceStateToLayoutMap.get(2);
+
+        Layout testLayout = new Layout();
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(345L), /* isDefault= */ true,
+                /* isEnabled= */ true, mDisplayIdProducerMock);
+        testLayout.createDisplayLocked(
+                DisplayAddress.fromPhysicalDisplayId(678L), /* isDefault= */ false,
+                /* isEnabled= */ true, mDisplayIdProducerMock);
+
+        assertEquals(testLayout, configLayout);
+    }
+
+    ////////////////////
+    // Helper Methods //
+    ////////////////////
+
+    private void setupDeviceStateToLayoutMap() throws IOException {
+        Path tempFile = Files.createTempFile("device_state_layout_map", ".tmp");
+        Files.write(tempFile, getContent().getBytes(StandardCharsets.UTF_8));
+        mDeviceStateToLayoutMap = new DeviceStateToLayoutMap(mDisplayIdProducerMock,
+                tempFile.toFile());
+    }
+
+    private String getContent() {
+        return "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                +  "<layouts>\n"
+                +    "<layout>\n"
+                +      "<state>0</state> \n"
+                +      "<display enabled=\"true\" defaultDisplay=\"true\">\n"
+                +        "<address>123456</address>\n"
+                +      "</display>\n"
+                +      "<display enabled=\"false\">\n"
+                +        "<address>78910</address>\n"
+                +      "</display>\n"
+                +    "</layout>\n"
+
+                +    "<layout>\n"
+                +      "<state>1</state> \n"
+                +      "<display enabled=\"true\" defaultDisplay=\"true\">\n"
+                +        "<address>78910</address>\n"
+                +      "</display>\n"
+                +      "<display enabled=\"false\">\n"
+                +        "<address>123456</address>\n"
+                +      "</display>\n"
+                +    "</layout>\n"
+
+                +    "<layout>\n"
+                +      "<state>2</state> \n"
+                +      "<display enabled=\"true\" defaultDisplay=\"true\">\n"
+                +        "<address>345</address>\n"
+                +      "</display>\n"
+                +      "<display enabled=\"true\">\n"
+                +        "<address>678</address>\n"
+                +      "</display>\n"
+                +    "</layout>\n"
+                +  "</layouts>\n";
+    }
+}
+
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 062bde8..303b240 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -16,7 +16,9 @@
 
 package com.android.server.display;
 
+import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY;
 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;
 
@@ -171,22 +173,6 @@
 
     private final DisplayManagerService.Injector mBasicInjector = new BasicInjector();
 
-    private final DisplayManagerService.Injector mAllowNonNativeRefreshRateOverrideInjector =
-            new BasicInjector() {
-                @Override
-                boolean getAllowNonNativeRefreshRateOverride() {
-                    return true;
-                }
-            };
-
-    private final DisplayManagerService.Injector mDenyNonNativeRefreshRateOverrideInjector =
-            new BasicInjector() {
-                @Override
-                boolean getAllowNonNativeRefreshRateOverride() {
-                    return false;
-                }
-            };
-
     @Mock InputManagerInternal mMockInputManagerInternal;
     @Mock VirtualDeviceManagerInternal mMockVirtualDeviceManagerInternal;
     @Mock IVirtualDisplayCallback.Stub mMockAppToken;
@@ -235,6 +221,7 @@
         SurfaceControl.DisplayMode displayMode = new SurfaceControl.DisplayMode();
         displayMode.width = 100;
         displayMode.height = 200;
+        displayMode.supportedHdrTypes = new int[]{1, 2};
         dynamicDisplayMode.supportedDisplayModes = new SurfaceControl.DisplayMode[] {displayMode};
         when(mSurfaceControlProxy.getDynamicDisplayInfo(mMockDisplayToken))
                 .thenReturn(dynamicDisplayMode);
@@ -335,7 +322,7 @@
 
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
 
-        final int displayIds[] = bs.getDisplayIds();
+        final int[] displayIds = bs.getDisplayIds(/* includeDisabled= */ true);
         final int size = displayIds.length;
         assertTrue(size > 0);
 
@@ -408,6 +395,75 @@
         assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0);
     }
 
+    @Test
+    public void testCreateVirtualDisplayOwnFocus() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        // This is effectively the DisplayManager service published to ServiceManager.
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+        String uniqueId = "uniqueId --- Own Focus Test";
+        int width = 600;
+        int height = 800;
+        int dpi = 320;
+        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS
+                | DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
+
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY)).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, width, height, dpi);
+        builder.setFlags(flags);
+        builder.setUniqueId(uniqueId);
+        int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
+                /* projection= */ null, PACKAGE_NAME);
+
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+        // flush the handler
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) != 0);
+    }
+
+    @Test
+    public void testCreateVirtualDisplayOwnFocus_nonTrustedDisplay() {
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        registerDefaultDisplays(displayManager);
+
+        // This is effectively the DisplayManager service published to ServiceManager.
+        DisplayManagerService.BinderService bs = displayManager.new BinderService();
+
+        String uniqueId = "uniqueId --- Own Focus Test -- nonTrustedDisplay";
+        int width = 600;
+        int height = 800;
+        int dpi = 320;
+        int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
+
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+        final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(
+                VIRTUAL_DISPLAY_NAME, width, height, dpi);
+        builder.setFlags(flags);
+        builder.setUniqueId(uniqueId);
+        int displayId = bs.createVirtualDisplay(builder.build(), /* callback= */ mMockAppToken,
+                /* projection= */ null, PACKAGE_NAME);
+
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
+
+        // flush the handler
+        displayManager.getDisplayHandler().runWithScissors(() -> {}, /* now= */ 0);
+
+        DisplayDeviceInfo ddi = displayManager.getDisplayDeviceInfoInternal(displayId);
+        assertNotNull(ddi);
+        assertTrue((ddi.flags & DisplayDeviceInfo.FLAG_OWN_FOCUS) == 0);
+    }
+
     /**
      * Tests that the virtual display is created along-side the default display.
      */
@@ -670,9 +726,6 @@
         registerDefaultDisplays(displayManager);
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
 
-        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
                 .thenReturn(true);
@@ -726,9 +779,6 @@
         registerDefaultDisplays(displayManager);
         when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
 
-        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
-                .thenReturn(PackageManager.PERMISSION_DENIED);
-
         IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
         when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
                 .thenReturn(true);
@@ -738,7 +788,7 @@
         // virtual device.
         final VirtualDisplayConfig.Builder builder1 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
-                        .setUniqueId("uniqueId --- device display group 1");
+                        .setUniqueId("uniqueId --- device display group");
 
         int displayId1 =
                 localService.createVirtualDisplay(
@@ -754,7 +804,7 @@
         final VirtualDisplayConfig.Builder builder2 =
                 new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
                         .setFlags(VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
-                        .setUniqueId("uniqueId --- device display group 1");
+                        .setUniqueId("uniqueId --- own display group");
 
         int displayId2 =
                 localService.createVirtualDisplay(
@@ -773,6 +823,99 @@
     }
 
     @Test
+    public void displaysInDeviceOrOwnDisplayGroupShouldPreserveAlwaysUnlockedFlag()
+            throws Exception {
+        DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerInternal localService = displayManager.new LocalService();
+
+        registerDefaultDisplays(displayManager);
+        when(mMockAppToken.asBinder()).thenReturn(mMockAppToken);
+
+        IVirtualDevice virtualDevice = mock(IVirtualDevice.class);
+        when(mMockVirtualDeviceManagerInternal.isValidVirtualDevice(virtualDevice))
+                .thenReturn(true);
+        when(virtualDevice.getDeviceId()).thenReturn(1);
+
+        // Allow an ALWAYS_UNLOCKED display to be created.
+        when(mContext.checkCallingPermission(ADD_TRUSTED_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        when(mContext.checkCallingPermission(ADD_ALWAYS_UNLOCKED_DISPLAY))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+
+        // Create a virtual display in a device display group.
+        final VirtualDisplayConfig deviceDisplayGroupDisplayConfig =
+                new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
+                        .setUniqueId("uniqueId --- device display group 1")
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED)
+                        .build();
+
+        int deviceDisplayGroupDisplayId =
+                localService.createVirtualDisplay(
+                        deviceDisplayGroupDisplayConfig,
+                        mMockAppToken /* callback */,
+                        virtualDevice /* virtualDeviceToken */,
+                        mock(DisplayWindowPolicyController.class),
+                        PACKAGE_NAME);
+
+        // Check that FLAG_ALWAYS_UNLOCKED is set.
+        assertNotEquals(
+                "FLAG_ALWAYS_UNLOCKED should be set for displays created in a device display"
+                        + " group.",
+                (displayManager.getDisplayDeviceInfoInternal(deviceDisplayGroupDisplayId).flags
+                        & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
+                0);
+
+        // Create a virtual display in its own display group.
+        final VirtualDisplayConfig ownDisplayGroupConfig =
+                new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
+                        .setUniqueId("uniqueId --- own display group 1")
+                        .setFlags(
+                                VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED
+                                        | VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP)
+                        .build();
+
+        int ownDisplayGroupDisplayId =
+                localService.createVirtualDisplay(
+                        ownDisplayGroupConfig,
+                        mMockAppToken /* callback */,
+                        virtualDevice /* virtualDeviceToken */,
+                        mock(DisplayWindowPolicyController.class),
+                        PACKAGE_NAME);
+
+        // Check that FLAG_ALWAYS_UNLOCKED is set.
+        assertNotEquals(
+                "FLAG_ALWAYS_UNLOCKED should be set for displays created in their own display"
+                        + " group.",
+                (displayManager.getDisplayDeviceInfoInternal(ownDisplayGroupDisplayId).flags
+                        & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
+                0);
+
+        // Create a virtual display in a device display group.
+        final VirtualDisplayConfig defaultDisplayGroupConfig =
+                new VirtualDisplayConfig.Builder(VIRTUAL_DISPLAY_NAME, 600, 800, 320)
+                        .setUniqueId("uniqueId --- default display group 1")
+                        .setFlags(VIRTUAL_DISPLAY_FLAG_ALWAYS_UNLOCKED)
+                        .build();
+
+        int defaultDisplayGroupDisplayId =
+                localService.createVirtualDisplay(
+                        defaultDisplayGroupConfig,
+                        mMockAppToken /* callback */,
+                        null /* virtualDeviceToken */,
+                        mock(DisplayWindowPolicyController.class),
+                        PACKAGE_NAME);
+
+        // Check that FLAG_ALWAYS_UNLOCKED is not set.
+        assertEquals(
+                "FLAG_ALWAYS_UNLOCKED should not be set for displays created in the default"
+                        + " display group.",
+                (displayManager.getDisplayDeviceInfoInternal(defaultDisplayGroupDisplayId).flags
+                        & DisplayDeviceInfo.FLAG_ALWAYS_UNLOCKED),
+                0);
+    }
+
+    @Test
     public void testGetDisplayIdToMirror() throws Exception {
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         registerDefaultDisplays(displayManager);
@@ -1044,13 +1187,32 @@
     }
 
     /**
-     * Tests that the frame rate override is updated accordingly to the
-     * allowNonNativeRefreshRateOverride policy.
+     * Tests that the frame rate override is returning the correct value from
+     * DisplayInfo#getRefreshRate
      */
     @Test
     public void testDisplayInfoNonNativeFrameRateOverride() throws Exception {
-        testDisplayInfoNonNativeFrameRateOverride(mDenyNonNativeRefreshRateOverrideInjector);
-        testDisplayInfoNonNativeFrameRateOverride(mAllowNonNativeRefreshRateOverrideInjector);
+        DisplayManagerService displayManager =
+                new DisplayManagerService(mContext, mBasicInjector);
+        DisplayManagerService.BinderService displayManagerBinderService =
+                displayManager.new BinderService();
+        registerDefaultDisplays(displayManager);
+        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
+
+        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
+                new float[]{60f});
+        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
+                displayDevice);
+        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
+
+        updateFrameRateOverride(displayManager, displayDevice,
+                new DisplayEventReceiver.FrameRateOverride[]{
+                        new DisplayEventReceiver.FrameRateOverride(
+                                Process.myUid(), 20f)
+                });
+        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
+        assertEquals(20f, displayInfo.getRefreshRate(), 0.01f);
     }
 
     /**
@@ -1078,10 +1240,7 @@
     @Test
     @DisableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
     public void testDisplayInfoNonNativeFrameRateOverrideModeCompat() throws Exception {
-        testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
-                /*compatChangeEnabled*/ false);
-        testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
-                /*compatChangeEnabled*/  false);
+        testDisplayInfoNonNativeFrameRateOverrideMode(/*compatChangeEnabled*/ false);
     }
 
     /**
@@ -1090,10 +1249,7 @@
     @Test
     @EnableCompatChanges({DisplayManagerService.DISPLAY_MODE_RETURNS_PHYSICAL_REFRESH_RATE})
     public void testDisplayInfoNonNativeFrameRateOverrideMode() throws Exception {
-        testDisplayInfoNonNativeFrameRateOverrideMode(mDenyNonNativeRefreshRateOverrideInjector,
-                /*compatChangeEnabled*/  true);
-        testDisplayInfoNonNativeFrameRateOverrideMode(mAllowNonNativeRefreshRateOverrideInjector,
-                /*compatChangeEnabled*/  true);
+        testDisplayInfoNonNativeFrameRateOverrideMode(/*compatChangeEnabled*/ true);
     }
 
     /**
@@ -1316,10 +1472,9 @@
         assertEquals(expectedMode, displayInfo.getMode());
     }
 
-    private void testDisplayInfoNonNativeFrameRateOverrideMode(
-            DisplayManagerService.Injector injector, boolean compatChangeEnabled) {
+    private void testDisplayInfoNonNativeFrameRateOverrideMode(boolean compatChangeEnabled) {
         DisplayManagerService displayManager =
-                new DisplayManagerService(mContext, injector);
+                new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerService.BinderService displayManagerBinderService =
                 displayManager.new BinderService();
         registerDefaultDisplays(displayManager);
@@ -1341,46 +1496,19 @@
         Display.Mode expectedMode;
         if (compatChangeEnabled) {
             expectedMode = new Display.Mode(1, 100, 200, 60f);
-        } else if (injector.getAllowNonNativeRefreshRateOverride()) {
-            expectedMode = new Display.Mode(255, 100, 200, 20f);
         } else {
-            expectedMode = new Display.Mode(1, 100, 200, 60f);
+            expectedMode = new Display.Mode(255, 100, 200, 20f);
         }
         assertEquals(expectedMode, displayInfo.getMode());
     }
 
-    private void testDisplayInfoNonNativeFrameRateOverride(
-            DisplayManagerService.Injector injector) {
-        DisplayManagerService displayManager =
-                new DisplayManagerService(mContext, injector);
-        DisplayManagerService.BinderService displayManagerBinderService =
-                displayManager.new BinderService();
-        registerDefaultDisplays(displayManager);
-        displayManager.onBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
-
-        FakeDisplayDevice displayDevice = createFakeDisplayDevice(displayManager,
-                new float[]{60f});
-        int displayId = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
-                displayDevice);
-        DisplayInfo displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
-        assertEquals(60f, displayInfo.getRefreshRate(), 0.01f);
-
-        updateFrameRateOverride(displayManager, displayDevice,
-                new DisplayEventReceiver.FrameRateOverride[]{
-                        new DisplayEventReceiver.FrameRateOverride(
-                                Process.myUid(), 20f)
-                });
-        displayInfo = displayManagerBinderService.getDisplayInfo(displayId);
-        float expectedRefreshRate = injector.getAllowNonNativeRefreshRateOverride() ? 20f : 60f;
-        assertEquals(expectedRefreshRate, displayInfo.getRefreshRate(), 0.01f);
-    }
-
     private int getDisplayIdForDisplayDevice(
             DisplayManagerService displayManager,
             DisplayManagerService.BinderService displayManagerBinderService,
             FakeDisplayDevice displayDevice) {
 
-        final int[] displayIds = displayManagerBinderService.getDisplayIds();
+        final int[] displayIds = displayManagerBinderService.getDisplayIds(
+                /* includeDisabled= */ true);
         assertTrue(displayIds.length > 0);
         int displayId = Display.INVALID_DISPLAY;
         for (int i = 0; i < displayIds.length; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 71f3d15..865bc98 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -200,12 +200,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testDisplayModeVoting(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testDisplayModeVoting() {
         // With no votes present, DisplayModeDirector should allow any refresh rate.
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         DesiredDisplayModeSpecs modeSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
@@ -242,12 +237,7 @@
                         .isEqualTo((float) (minFps + i));
                 assertThat(modeSpecs.primary.physical.max)
                         .isEqualTo((float) (maxFps - i));
-                if (frameRateIsRefreshRate) {
-                    assertThat(modeSpecs.primary.render.min)
-                            .isEqualTo((float) (minFps + i));
-                } else {
-                    assertThat(modeSpecs.primary.render.min).isZero();
-                }
+                assertThat(modeSpecs.primary.render.min).isZero();
                 assertThat(modeSpecs.primary.render.max)
                         .isEqualTo((float) (maxFps - i));
                 if (priority >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF) {
@@ -255,12 +245,7 @@
                             .isEqualTo((float) (minFps + i));
                     assertThat(modeSpecs.appRequest.physical.max)
                             .isEqualTo((float) (maxFps - i));
-                    if (frameRateIsRefreshRate) {
-                        assertThat(modeSpecs.appRequest.render.min).isEqualTo(
-                                (float) (minFps + i));
-                    } else {
-                        assertThat(modeSpecs.appRequest.render.min).isZero();
-                    }
+                    assertThat(modeSpecs.appRequest.render.min).isZero();
                     assertThat(modeSpecs.appRequest.render.max).isEqualTo(
                             (float) (maxFps - i));
                 } else {
@@ -292,12 +277,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testVotingWithFloatingPointErrors(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testVotingWithFloatingPointErrors() {
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -318,12 +298,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testFlickerHasLowerPriorityThanUserAndRangeIsSingle(
-            boolean frameRateIsRefreshRate) {
+    public void testFlickerHasLowerPriorityThanUserAndRangeIsSingle() {
         assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
                 < Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
         assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE
@@ -332,7 +307,6 @@
         assertTrue(Vote.PRIORITY_FLICKER_REFRESH_RATE_SWITCH
                 > Vote.PRIORITY_LOW_POWER_MODE);
 
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
         Display.Mode[] modes = new Display.Mode[4];
         modes[0] = new Display.Mode(
                 /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -408,17 +382,12 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testLPMHasHigherPriorityThanUser(boolean frameRateIsRefreshRate) {
+    public void testLPMHasHigherPriorityThanUser() {
         assertTrue(Vote.PRIORITY_LOW_POWER_MODE
                 > Vote.PRIORITY_APP_REQUEST_BASE_MODE_REFRESH_RATE);
         assertTrue(Vote.PRIORITY_LOW_POWER_MODE
                 > Vote.PRIORITY_APP_REQUEST_SIZE);
 
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
         Display.Mode[] modes = new Display.Mode[4];
         modes[0] = new Display.Mode(
                 /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -443,11 +412,7 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.baseModeId).isEqualTo(2);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
 
@@ -462,11 +427,7 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.baseModeId).isEqualTo(4);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(90);
 
@@ -481,11 +442,7 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.baseModeId).isEqualTo(2);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
 
@@ -500,21 +457,13 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.baseModeId).isEqualTo(4);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(90);
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestRefreshRateRange(boolean frameRateIsRefreshRate) {
+    public void testAppRequestRefreshRateRange() {
         // Confirm that the app request range doesn't include flicker or min refresh rate settings,
         // but does include everything else.
         assertTrue(
@@ -525,7 +474,6 @@
         assertTrue(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE
                 >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
 
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
         Display.Mode[] modes = new Display.Mode[3];
         modes[0] = new Display.Mode(
                 /*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
@@ -582,12 +530,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testSpecsFromRefreshRateSettings(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testSpecsFromRefreshRateSettings() {
         // Confirm that, with varying settings for min, peak, and default refresh rate,
         // DesiredDisplayModeSpecs is calculated correctly.
         float[] refreshRates = {30.f, 60.f, 90.f, 120.f, 150.f};
@@ -607,27 +550,12 @@
 
         RefreshRateRanges frameRateAll = new RefreshRateRanges(rangeAll, rangeAll);
         RefreshRateRanges frameRate90toInf = new RefreshRateRanges(range90toInf, range90toInf);
-        RefreshRateRanges frameRate0to60;
-        RefreshRateRanges frameRate0to90;
-        RefreshRateRanges frameRate0to120;
-        RefreshRateRanges frameRate60to90;
-        RefreshRateRanges frameRate90to90;
-        RefreshRateRanges frameRate90to120;
-        if (frameRateIsRefreshRate) {
-            frameRate0to60 = new RefreshRateRanges(range0to60, range0to60);
-            frameRate0to90 = new RefreshRateRanges(range0to90, range0to90);
-            frameRate0to120 = new RefreshRateRanges(range0to120, range0to120);
-            frameRate60to90 = new RefreshRateRanges(range60to90, range60to90);
-            frameRate90to90 = new RefreshRateRanges(range90to90, range90to90);
-            frameRate90to120 = new RefreshRateRanges(range90to120, range90to120);
-        } else {
-            frameRate0to60 = new RefreshRateRanges(rangeAll, range0to60);
-            frameRate0to90 = new RefreshRateRanges(rangeAll, range0to90);
-            frameRate0to120 = new RefreshRateRanges(rangeAll, range0to120);
-            frameRate60to90 = new RefreshRateRanges(range60toInf, range60to90);
-            frameRate90to90 = new RefreshRateRanges(range90toInf, range90to90);
-            frameRate90to120 = new RefreshRateRanges(range90toInf, range90to120);
-        }
+        RefreshRateRanges frameRate0to60 = new RefreshRateRanges(rangeAll, range0to60);
+        RefreshRateRanges frameRate0to90 = new RefreshRateRanges(rangeAll, range0to90);
+        RefreshRateRanges frameRate0to120 = new RefreshRateRanges(rangeAll, range0to120);
+        RefreshRateRanges frameRate60to90 = new RefreshRateRanges(range60toInf, range60to90);
+        RefreshRateRanges frameRate90to90 = new RefreshRateRanges(range90toInf, range90to90);
+        RefreshRateRanges frameRate90to120 = new RefreshRateRanges(range90toInf, range90to120);
 
         verifySpecsWithRefreshRateSettings(director, 0, 0, 0, frameRateAll, frameRateAll);
         verifySpecsWithRefreshRateSettings(director, 0, 0, 90, frameRate0to90, frameRateAll);
@@ -657,12 +585,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testBrightnessObserverCallWithRefreshRateSettings(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testBrightnessObserverCallWithRefreshRateSettings() {
         // Confirm that, with varying settings for min, peak, and default refresh rate, we make the
         // correct call to the brightness observer.
         float[] refreshRates = {60.f, 90.f, 120.f};
@@ -677,12 +600,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testVotingWithAlwaysRespectAppRequest(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testVotingWithAlwaysRespectAppRequest() {
         Display.Mode[] modes = new Display.Mode[3];
         modes[0] = new Display.Mode(
                 /*modeId=*/50, /*width=*/1000, /*height=*/1000, 50);
@@ -711,11 +629,7 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(60);
@@ -734,23 +648,14 @@
 
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(60);
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testVotingWithSwitchingTypeNone(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testVotingWithSwitchingTypeNone() {
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -765,20 +670,11 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
-                    60);
-        } else {
-            assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(30);
@@ -800,12 +696,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testVotingWithSwitchingTypeRenderFrameRateOnly(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testVotingWithSwitchingTypeRenderFrameRateOnly() {
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -816,24 +707,15 @@
 
         director.injectVotesByDisplay(votesByDisplay);
         assertThat(director.getModeSwitchingType())
-                .isNotEqualTo(DisplayManager.SWITCHING_TYPE_NONE);
+                .isNotEqualTo(DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY);
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
 
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
-                    60);
-        } else {
-            assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(30);
@@ -846,25 +728,58 @@
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(30);
-        } else {
-            assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
-        }
+        assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
         assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(30);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(30);
-            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(30);
-        } else {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
-            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
-        }
+        assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
+        assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(30);
 
         assertThat(desiredSpecs.baseModeId).isEqualTo(30);
     }
 
     @Test
+    public void testVotingWithSwitchingTypeRenderFrameRateOnlyRenderRateIsNotPhysicalRefreshRate() {
+        DisplayModeDirector director = createDirectorFromFpsRange(90, 120);
+        SparseArray<Vote> votes = new SparseArray<>();
+        SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+        votesByDisplay.put(DISPLAY_ID, votes);
+        votes.put(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+                Vote.forRenderFrameRates(30, 90));
+        votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRenderFrameRates(0, 60));
+
+        director.injectVotesByDisplay(votesByDisplay);
+        assertThat(director.getModeSwitchingType())
+                .isNotEqualTo(DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+
+        assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(30);
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+        assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(30);
+        assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
+        assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
+        assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
+        assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        assertThat(desiredSpecs.baseModeId).isEqualTo(90);
+
+        director.setModeSwitchingType(DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY);
+        assertThat(director.getModeSwitchingType())
+                .isEqualTo(DisplayManager.SWITCHING_TYPE_RENDER_FRAME_RATE_ONLY);
+
+        desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+        assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
+        assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
+        assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
+        assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
+        assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(90);
+        assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(0);
+        assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+
+        assertThat(desiredSpecs.baseModeId).isEqualTo(90);
+    }
+
+    @Test
     public void testVotingWithSwitchingTypeWithinGroups() {
         DisplayModeDirector director = createDirectorFromFpsRange(0, 90);
 
@@ -887,12 +802,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testDefaultDisplayModeIsSelectedIfAvailable(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testDefaultDisplayModeIsSelectedIfAvailable() {
         final float[] refreshRates = new float[]{24f, 25f, 30f, 60f, 90f};
         final int defaultModeId = 3;
         DisplayModeDirector director = createDirectorFromRefreshRateArray(
@@ -1173,17 +1083,12 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestMinRefreshRate(boolean frameRateIsRefreshRate) {
+    public void testAppRequestMinRefreshRate() {
         // Confirm that the app min request range doesn't include flicker or min refresh rate
         // settings but does include everything else.
         assertTrue(Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE
                 >= Vote.APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF);
 
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
         Display.Mode[] modes = new Display.Mode[3];
         modes[0] = new Display.Mode(
                 /*modeId=*/60, /*width=*/1000, /*height=*/1000, 60);
@@ -1225,11 +1130,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestMaxRefreshRate(boolean frameRateIsRefreshRate) {
+    public void testAppRequestMaxRefreshRate() {
         // Confirm that the app max request range doesn't include flicker or min refresh rate
         // settings but does include everything else.
         assertTrue(Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE
@@ -1243,7 +1144,6 @@
         modes[2] = new Display.Mode(
                 /*modeId=*/90, /*width=*/1000, /*height=*/1000, 90);
 
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
         DisplayModeDirector director = createDirectorFromModeArray(modes, modes[1]);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1254,19 +1154,11 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.render.min).isZero();
-        }
+        assertThat(desiredSpecs.primary.render.min).isZero();
         assertThat(desiredSpecs.primary.render.max).isAtMost(60);
         assertThat(desiredSpecs.appRequest.physical.min).isAtMost(60f);
         assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isAtMost(60f);
-        } else {
-            assertThat(desiredSpecs.appRequest.render.min).isZero();
-        }
+        assertThat(desiredSpecs.appRequest.render.min).isZero();
         assertThat(desiredSpecs.appRequest.render.max).isAtLeast(90f);
 
         votes.put(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
@@ -1288,30 +1180,16 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(75);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(75);
-        } else {
-            assertThat(desiredSpecs.primary.render.min).isZero();
-        }
+        assertThat(desiredSpecs.primary.render.min).isZero();
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(75);
         assertThat(desiredSpecs.appRequest.physical.min).isZero();
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(
-                    75);
-        } else {
-            assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
-        }
+        assertThat(desiredSpecs.appRequest.physical.max).isAtLeast(90f);
         assertThat(desiredSpecs.appRequest.render.min).isZero();
         assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(75);
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestObserver_modeId(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testAppRequestObserver_modeId() {
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 0, 0);
 
@@ -1373,12 +1251,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestObserver_minRefreshRate(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testAppRequestObserver_minRefreshRate() {
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 60, 0);
         Vote appRequestRefreshRate =
@@ -1391,15 +1264,9 @@
         Vote appRequestRefreshRateRange =
                 director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
         assertNotNull(appRequestRefreshRateRange);
-        if (frameRateIsRefreshRate) {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min)
-                    .isWithin(FLOAT_TOLERANCE).of(60);
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max).isAtLeast(90);
-        } else {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isPositiveInfinity();
-        }
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+                .isPositiveInfinity();
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
                 .isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max).isAtLeast(90);
@@ -1417,15 +1284,9 @@
         appRequestRefreshRateRange =
                 director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
         assertNotNull(appRequestRefreshRateRange);
-        if (frameRateIsRefreshRate) {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isWithin(
-                    FLOAT_TOLERANCE).of(90);
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max).isAtLeast(90);
-        } else {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isPositiveInfinity();
-        }
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+                .isPositiveInfinity();
 
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
                 .isWithin(FLOAT_TOLERANCE).of(90);
@@ -1435,12 +1296,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestObserver_maxRefreshRate(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testAppRequestObserver_maxRefreshRate() {
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         director.getAppRequestObserver().setAppRequest(DISPLAY_ID, -1, 0, 90);
         Vote appRequestRefreshRate =
@@ -1454,13 +1310,8 @@
                 director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
         assertNotNull(appRequestRefreshRateRange);
         assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
-        if (frameRateIsRefreshRate) {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isPositiveInfinity();
-        }
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+                .isPositiveInfinity();
 
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1480,13 +1331,8 @@
                 director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
         assertNotNull(appRequestRefreshRateRange);
         assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
-        if (frameRateIsRefreshRate) {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isPositiveInfinity();
-        }
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+                .isPositiveInfinity();
 
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min).isZero();
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1512,12 +1358,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestObserver_modeIdAndRefreshRateRange(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testAppRequestObserver_modeIdAndRefreshRateRange() {
         DisplayModeDirector director = createDirectorFromFpsRange(60, 90);
         director.getAppRequestObserver().setAppRequest(DISPLAY_ID, 60, 90, 90);
 
@@ -1547,16 +1388,9 @@
         Vote appRequestRefreshRateRange =
                 director.getVote(DISPLAY_ID, Vote.PRIORITY_APP_REQUEST_RENDER_FRAME_RATE_RANGE);
         assertNotNull(appRequestRefreshRateRange);
-        if (frameRateIsRefreshRate) {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min)
-                    .isWithin(FLOAT_TOLERANCE).of(90);
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
-            assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
-                    .isPositiveInfinity();
-        }
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.min).isZero();
+        assertThat(appRequestRefreshRateRange.refreshRateRanges.physical.max)
+                .isPositiveInfinity();
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.min)
                 .isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(appRequestRefreshRateRange.refreshRateRanges.render.max)
@@ -1566,12 +1400,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testAppRequestsIsTheDefaultMode(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testAppRequestsIsTheDefaultMode() {
         Display.Mode[] modes = new Display.Mode[2];
         modes[0] = new Display.Mode(
                 /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -1600,12 +1429,7 @@
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testDisableRefreshRateSwitchingVote(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testDisableRefreshRateSwitchingVote() {
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1650,8 +1474,8 @@
             "true",
             "false"
     })
-    public void testBaseModeIdInPrimaryRange(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testBaseModeIdInPrimaryRange(boolean supportsFrameRateOverride) {
+        when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
         DisplayModeDirector director = createDirectorFromFpsRange(50, 90);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1662,12 +1486,12 @@
         director.injectVotesByDisplay(votesByDisplay);
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-            assertThat(desiredSpecs.baseModeId).isEqualTo(50);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+        if (supportsFrameRateOverride) {
             assertThat(desiredSpecs.baseModeId).isEqualTo(70);
+        } else {
+            assertThat(desiredSpecs.baseModeId).isEqualTo(50);
+
         }
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
@@ -1679,11 +1503,7 @@
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         assertThat(desiredSpecs.baseModeId).isEqualTo(55);
@@ -1697,12 +1517,11 @@
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(60);
-            assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
+        if (supportsFrameRateOverride) {
             assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(52);
+        } else {
+            assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(60);
         }
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.baseModeId).isEqualTo(55);
@@ -1716,23 +1535,14 @@
         director.injectVotesByDisplay(votesByDisplay);
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.primary.physical.min).isWithin(FLOAT_TOLERANCE).of(0);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.primary.physical.max).isWithin(FLOAT_TOLERANCE).of(58);
-        } else {
-            assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
-        }
+        assertThat(desiredSpecs.primary.physical.max).isPositiveInfinity();
         assertThat(desiredSpecs.primary.render.min).isWithin(FLOAT_TOLERANCE).of(0);
         assertThat(desiredSpecs.primary.render.max).isWithin(FLOAT_TOLERANCE).of(58);
         assertThat(desiredSpecs.baseModeId).isEqualTo(55);
     }
 
     @Test
-    @Parameters({
-            "true",
-            "false"
-    })
-    public void testStaleAppVote(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testStaleAppVote() {
         Display.Mode[] modes = new Display.Mode[4];
         modes[0] = new Display.Mode(
                 /*modeId=*/1, /*width=*/1000, /*height=*/1000, 60);
@@ -1782,8 +1592,8 @@
             "true",
             "false"
     })
-    public void testRefreshRateIsSubsetOfFrameRate(boolean frameRateIsRefreshRate) {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(frameRateIsRefreshRate);
+    public void testRefreshRateIsSubsetOfFrameRate(boolean supportsFrameRateOverride) {
+        when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
         DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1795,11 +1605,7 @@
         DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(desiredSpecs.appRequest.render.min).isZero();
-        }
+        assertThat(desiredSpecs.appRequest.render.min).isZero();
         assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
 
         votes.clear();
@@ -1810,13 +1616,11 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
-            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(
-                    120);
-        } else {
-            assertThat(desiredSpecs.appRequest.render.min).isZero();
+        assertThat(desiredSpecs.appRequest.render.min).isZero();
+        if (supportsFrameRateOverride) {
             assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        } else {
+            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
         }
 
         votes.clear();
@@ -1827,13 +1631,12 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
-            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(
-                    120);
-        } else {
+        if (supportsFrameRateOverride) {
             assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(60);
             assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        } else {
+            assertThat(desiredSpecs.appRequest.render.min).isZero();
+            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
         }
 
         votes.clear();
@@ -1844,17 +1647,12 @@
         desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
         assertThat(desiredSpecs.appRequest.physical.min).isWithin(FLOAT_TOLERANCE).of(90);
         assertThat(desiredSpecs.appRequest.physical.max).isWithin(FLOAT_TOLERANCE).of(120);
-        if (frameRateIsRefreshRate) {
-            assertThat(desiredSpecs.appRequest.render.min).isWithin(FLOAT_TOLERANCE).of(90);
-        } else {
-            assertThat(desiredSpecs.appRequest.render.min).isZero();
-        }
+        assertThat(desiredSpecs.appRequest.render.min).isZero();
         assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(120);
     }
 
     @Test
     public void testRenderFrameRateIsAchievableByPhysicalRefreshRate() {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(false);
         DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -1872,8 +1670,34 @@
     }
 
     @Test
+    @Parameters({
+            "true",
+            "false"
+    })
+    public void testRenderFrameRateIncludesPhysicalRefreshRate(boolean supportsFrameRateOverride) {
+        when(mInjector.supportsFrameRateOverride()).thenReturn(supportsFrameRateOverride);
+        DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
+        SparseArray<Vote> votes = new SparseArray<>();
+        SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
+        votesByDisplay.put(DISPLAY_ID, votes);
+
+        votes.put(Vote.PRIORITY_LOW_POWER_MODE, Vote.forRenderFrameRates(0, 60));
+        votes.put(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+                Vote.forRenderFrameRates(0, 30));
+        director.injectVotesByDisplay(votesByDisplay);
+        DesiredDisplayModeSpecs desiredSpecs = director.getDesiredDisplayModeSpecs(DISPLAY_ID);
+        assertThat(desiredSpecs.appRequest.physical.min).isZero();
+        assertThat(desiredSpecs.appRequest.physical.max).isPositiveInfinity();
+        assertThat(desiredSpecs.appRequest.render.min).isZero();
+        if (supportsFrameRateOverride) {
+            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(30);
+        } else {
+            assertThat(desiredSpecs.appRequest.render.max).isWithin(FLOAT_TOLERANCE).of(60);
+        }
+    }
+
+    @Test
     public void testRenderFrameRateIsDroppedIfLowerPriorityThenBaseModeRefreshRate() {
-        when(mInjector.renderFrameRateIsPhysicalRefreshRate()).thenReturn(false);
         DisplayModeDirector director = createDirectorFromFpsRange(60, 120);
         SparseArray<Vote> votes = new SparseArray<>();
         SparseArray<SparseArray<Vote>> votesByDisplay = new SparseArray<>();
@@ -2692,7 +2516,7 @@
         }
 
         @Override
-        public boolean renderFrameRateIsPhysicalRefreshRate() {
+        public boolean supportsFrameRateOverride() {
             return true;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 657bda6..c7caa43 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -30,6 +30,8 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.clearInvocations;
@@ -52,6 +54,9 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.display.layout.DisplayIdProducer;
+import com.android.server.display.layout.Layout;
+
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -59,6 +64,7 @@
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
 
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -71,6 +77,7 @@
     private static int sUniqueTestDisplayId = 0;
     private static final int DEVICE_STATE_CLOSED = 0;
     private static final int DEVICE_STATE_OPEN = 2;
+    private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
 
     private DisplayDeviceRepository mDisplayDeviceRepo;
     private LogicalDisplayMapper mLogicalDisplayMapper;
@@ -78,11 +85,16 @@
     private Handler mHandler;
     private PowerManager mPowerManager;
 
+    private final DisplayIdProducer mIdProducer = (isDefault) ->
+            isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++;
+
     @Mock LogicalDisplayMapper.Listener mListenerMock;
     @Mock Context mContextMock;
     @Mock Resources mResourcesMock;
     @Mock IPowerManager mIPowerManagerMock;
     @Mock IThermalService mIThermalServiceMock;
+    @Spy DeviceStateToLayoutMap mDeviceStateToLayoutMapSpy =
+            new DeviceStateToLayoutMap(mIdProducer);
 
     @Captor ArgumentCaptor<LogicalDisplay> mDisplayCaptor;
 
@@ -132,7 +144,8 @@
         mLooper = new TestLooper();
         mHandler = new Handler(mLooper.getLooper());
         mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
-                mListenerMock, new DisplayManagerService.SyncRoot(), mHandler);
+                mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
+                mDeviceStateToLayoutMapSpy);
     }
 
 
@@ -259,7 +272,8 @@
         add(createDisplayDevice(Display.TYPE_EXTERNAL, 600, 800, 0));
         add(createDisplayDevice(Display.TYPE_VIRTUAL, 600, 800, 0));
 
-        int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID);
+        int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID,
+                /* includeDisabled= */ true);
         assertEquals(3, ids.length);
         Arrays.sort(ids);
         assertEquals(DEFAULT_DISPLAY, ids[0]);
@@ -503,10 +517,193 @@
                 /* isBootCompleted= */true));
     }
 
+    @Test
+    public void testDeviceStateLocked() {
+        DisplayDevice device1 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+        DisplayDevice device2 = createDisplayDevice(Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+
+        Layout layout = new Layout();
+        layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address,
+                true, true, mIdProducer);
+        layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
+                false, false, mIdProducer);
+        when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(layout);
+
+        layout = new Layout();
+        layout.createDisplayLocked(device1.getDisplayDeviceInfoLocked().address,
+                false, false, mIdProducer);
+        layout.createDisplayLocked(device2.getDisplayDeviceInfoLocked().address,
+                true, true, mIdProducer);
+        when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(layout);
+        when(mDeviceStateToLayoutMapSpy.get(2)).thenReturn(layout);
+
+        LogicalDisplay display1 = add(device1);
+        assertEquals(info(display1).address, info(device1).address);
+        assertEquals(DEFAULT_DISPLAY, id(display1));
+
+        LogicalDisplay display2 = add(device2);
+        assertEquals(info(display2).address, info(device2).address);
+        // We can only have one default display
+        assertEquals(DEFAULT_DISPLAY, id(display1));
+
+        mLogicalDisplayMapper.setDeviceStateLocked(0, false);
+        advanceTime(1000);
+        assertTrue(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
+
+        mLogicalDisplayMapper.setDeviceStateLocked(1, false);
+        advanceTime(1000);
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
+        assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
+
+        mLogicalDisplayMapper.setDeviceStateLocked(2, false);
+        advanceTime(1000);
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isEnabledLocked());
+        assertTrue(mLogicalDisplayMapper.getDisplayLocked(device2).isEnabledLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device1).isInTransitionLocked());
+        assertFalse(mLogicalDisplayMapper.getDisplayLocked(device2).isInTransitionLocked());
+    }
+
+    @Test
+    public void testEnabledAndDisabledDisplays() {
+        DisplayAddress displayAddressOne = new TestUtils.TestDisplayAddress();
+        DisplayAddress displayAddressTwo = new TestUtils.TestDisplayAddress();
+        DisplayAddress displayAddressThree = new TestUtils.TestDisplayAddress();
+
+        TestDisplayDevice device1 = createDisplayDevice(displayAddressOne, "one",
+                Display.TYPE_INTERNAL, 600, 800,
+                DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
+        TestDisplayDevice device2 = createDisplayDevice(displayAddressTwo, "two",
+                Display.TYPE_INTERNAL, 200, 800,
+                DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+        TestDisplayDevice device3 = createDisplayDevice(displayAddressThree, "three",
+                Display.TYPE_INTERNAL, 600, 900,
+                DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP);
+
+        Layout threeDevicesEnabledLayout = new Layout();
+        threeDevicesEnabledLayout.createDisplayLocked(
+                displayAddressOne,
+                /* isDefault= */ true,
+                /* isEnabled= */ true,
+                mIdProducer);
+        threeDevicesEnabledLayout.createDisplayLocked(
+                displayAddressTwo,
+                /* isDefault= */ false,
+                /* isEnabled= */ true,
+                mIdProducer);
+        threeDevicesEnabledLayout.createDisplayLocked(
+                displayAddressThree,
+                /* isDefault= */ false,
+                /* isEnabled= */ true,
+                mIdProducer);
+
+        when(mDeviceStateToLayoutMapSpy.get(DeviceStateToLayoutMap.STATE_DEFAULT))
+                .thenReturn(threeDevicesEnabledLayout);
+
+        LogicalDisplay display1 = add(device1);
+        LogicalDisplay display2 = add(device2);
+        LogicalDisplay display3 = add(device3);
+
+        // ensure 3 displays are returned
+        int [] ids = mLogicalDisplayMapper.getDisplayIdsLocked(Process.SYSTEM_UID, false);
+        assertEquals(3, ids.length);
+        Arrays.sort(ids);
+        assertEquals(DEFAULT_DISPLAY, ids[0]);
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device1,
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device2,
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device3,
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
+                threeDevicesEnabledLayout.getByAddress(displayAddressOne).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
+                threeDevicesEnabledLayout.getByAddress(displayAddressTwo).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
+                threeDevicesEnabledLayout.getByAddress(displayAddressThree).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+
+        Layout oneDeviceEnabledLayout = new Layout();
+        oneDeviceEnabledLayout.createDisplayLocked(
+                displayAddressOne,
+                /* isDefault= */ true,
+                /* isEnabled= */ true,
+                mIdProducer);
+        oneDeviceEnabledLayout.createDisplayLocked(
+                displayAddressTwo,
+                /* isDefault= */ false,
+                /* isEnabled= */ false,
+                mIdProducer);
+        oneDeviceEnabledLayout.createDisplayLocked(
+                displayAddressThree,
+                /* isDefault= */ false,
+                /* isEnabled= */ false,
+                mIdProducer);
+
+        when(mDeviceStateToLayoutMapSpy.get(0)).thenReturn(oneDeviceEnabledLayout);
+        when(mDeviceStateToLayoutMapSpy.get(1)).thenReturn(threeDevicesEnabledLayout);
+
+        // 1) Set the new state
+        // 2) Mark the displays as STATE_OFF so that it can continue with transition
+        // 3) Send DISPLAY_DEVICE_EVENT_CHANGE to inform the mapper of the new display state
+        // 4) Dispatch handler events.
+        mLogicalDisplayMapper.setDeviceStateLocked(0, false);
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
+        advanceTime(1000);
+        final int[] allDisplayIds = mLogicalDisplayMapper.getDisplayIdsLocked(
+                Process.SYSTEM_UID, false);
+        if (allDisplayIds.length != 1) {
+            throw new RuntimeException("Displays: \n"
+                    + mLogicalDisplayMapper.getDisplayLocked(device1).toString()
+                    + "\n" + mLogicalDisplayMapper.getDisplayLocked(device2).toString()
+                    + "\n" + mLogicalDisplayMapper.getDisplayLocked(device3).toString());
+        }
+        // ensure only one display is returned
+        assertEquals(1, allDisplayIds.length);
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(device1,
+                /* includeDisabled= */ false));
+        assertNull(mLogicalDisplayMapper.getDisplayLocked(device2,
+                /* includeDisabled= */ false));
+        assertNull(mLogicalDisplayMapper.getDisplayLocked(device3,
+                /* includeDisabled= */ false));
+        assertNotNull(mLogicalDisplayMapper.getDisplayLocked(
+                oneDeviceEnabledLayout.getByAddress(displayAddressOne).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+        assertNull(mLogicalDisplayMapper.getDisplayLocked(
+                oneDeviceEnabledLayout.getByAddress(displayAddressTwo).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+        assertNull(mLogicalDisplayMapper.getDisplayLocked(
+                oneDeviceEnabledLayout.getByAddress(displayAddressThree).getLogicalDisplayId(),
+                /* includeDisabled= */ false));
+
+        // Now do it again to go back to state 1
+        mLogicalDisplayMapper.setDeviceStateLocked(1, false);
+        mDisplayDeviceRepo.onDisplayDeviceEvent(device3, DISPLAY_DEVICE_EVENT_CHANGED);
+        advanceTime(1000);
+        final int[] threeDisplaysEnabled = mLogicalDisplayMapper.getDisplayIdsLocked(
+                Process.SYSTEM_UID, false);
+
+        // ensure all three displays are returned
+        assertEquals(3, threeDisplaysEnabled.length);
+    }
+
     /////////////////
     // Helper Methods
     /////////////////
 
+    private void advanceTime(long timeMs) {
+        mLooper.moveTimeForward(1000);
+        mLooper.dispatchAll();
+    }
+
     private TestDisplayDevice createDisplayDevice(int type, int width, int height, int flags) {
         return createDisplayDevice(
                 new TestUtils.TestDisplayAddress(), /*  uniqueId */ "", type, width, height, flags);
@@ -575,6 +772,7 @@
     class TestDisplayDevice extends DisplayDevice {
         private DisplayDeviceInfo mInfo;
         private DisplayDeviceInfo mSentInfo;
+        private int mState;
 
         TestDisplayDevice() {
             super(null, null, "test_display_" + sUniqueTestDisplayId++, mContextMock);
diff --git a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
index 5a43530..1d70fc6 100644
--- a/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/LogicalDisplayTest.java
@@ -126,12 +126,12 @@
         verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));
         reset(t);
 
-        mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_DISABLED);
+        mLogicalDisplay.setEnabledLocked(false);
         mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
         verify(t).setDisplayFlags(any(), eq(0));
         reset(t);
 
-        mLogicalDisplay.setPhase(LogicalDisplay.DISPLAY_PHASE_ENABLED);
+        mLogicalDisplay.setEnabledLocked(true);
         mDisplayDeviceInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
         mLogicalDisplay.configureDisplayLocked(t, mDisplayDevice, false);
         verify(t).setDisplayFlags(any(), eq(SurfaceControl.DISPLAY_RECEIVES_INPUT));
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
index 59c69d1..dcf217c 100644
--- a/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/DisplayBrightnessStrategySelectorTest.java
@@ -29,10 +29,12 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
+import com.android.server.display.brightness.strategy.BoostBrightnessStrategy;
 import com.android.server.display.brightness.strategy.DozeBrightnessStrategy;
 import com.android.server.display.brightness.strategy.InvalidBrightnessStrategy;
 import com.android.server.display.brightness.strategy.OverrideBrightnessStrategy;
 import com.android.server.display.brightness.strategy.ScreenOffBrightnessStrategy;
+import com.android.server.display.brightness.strategy.TemporaryBrightnessStrategy;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -53,6 +55,10 @@
     @Mock
     private OverrideBrightnessStrategy mOverrideBrightnessStrategy;
     @Mock
+    private TemporaryBrightnessStrategy mTemporaryBrightnessStrategy;
+    @Mock
+    private BoostBrightnessStrategy mBoostBrightnessStrategy;
+    @Mock
     private InvalidBrightnessStrategy mInvalidBrightnessStrategy;
     @Mock
     private Context mContext;
@@ -65,6 +71,7 @@
     public void before() {
         MockitoAnnotations.initMocks(this);
         when(mContext.getResources()).thenReturn(mResources);
+        when(mInvalidBrightnessStrategy.getName()).thenReturn("InvalidBrightnessStrategy");
         DisplayBrightnessStrategySelector.Injector injector =
                 new DisplayBrightnessStrategySelector.Injector() {
                     @Override
@@ -83,6 +90,16 @@
                     }
 
                     @Override
+                    TemporaryBrightnessStrategy getTemporaryBrightnessStrategy() {
+                        return mTemporaryBrightnessStrategy;
+                    }
+
+                    @Override
+                    BoostBrightnessStrategy getBoostBrightnessStrategy() {
+                        return mBoostBrightnessStrategy;
+                    }
+
+                    @Override
                     InvalidBrightnessStrategy getInvalidBrightnessStrategy() {
                         return mInvalidBrightnessStrategy;
                     }
@@ -121,10 +138,32 @@
     }
 
     @Test
+    public void selectStrategySelectsTemporaryStrategyWhenValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(0.3f);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_ON), mTemporaryBrightnessStrategy);
+    }
+
+    @Test
+    public void selectStrategySelectsBoostStrategyWhenValid() {
+        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
+                DisplayManagerInternal.DisplayPowerRequest.class);
+        displayPowerRequest.boostScreenBrightness = true;
+        displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
+        assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
+                Display.STATE_ON), mBoostBrightnessStrategy);
+    }
+
+    @Test
     public void selectStrategySelectsInvalidStrategyWhenNoStrategyIsValid() {
         DisplayManagerInternal.DisplayPowerRequest displayPowerRequest = mock(
                 DisplayManagerInternal.DisplayPowerRequest.class);
         displayPowerRequest.screenBrightnessOverride = Float.NaN;
+        when(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness()).thenReturn(Float.NaN);
         assertEquals(mDisplayBrightnessStrategySelector.selectStrategy(displayPowerRequest,
                 Display.STATE_ON), mInvalidBrightnessStrategy);
     }
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
new file mode 100644
index 0000000..431a239
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/BoostBrightnessStrategyTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display.brightness.strategy;
+
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal;
+import android.os.PowerManager;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+
+public class BoostBrightnessStrategyTest {
+    private BoostBrightnessStrategy mBoostBrightnessStrategy;
+
+    @Before
+    public void before() {
+        mBoostBrightnessStrategy = new BoostBrightnessStrategy();
+    }
+
+    @Test
+    public void updateBrightnessWorksAsExpectedWhenBoostBrightnessIsRequested() {
+        DisplayManagerInternal.DisplayPowerRequest
+                displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+        displayPowerRequest.boostScreenBrightness = true;
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_BOOST);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(PowerManager.BRIGHTNESS_MAX)
+                        .setBrightnessReason(brightnessReason)
+                        .setSdrBrightness(PowerManager.BRIGHTNESS_MAX)
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mBoostBrightnessStrategy.updateBrightness(displayPowerRequest);
+        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
new file mode 100644
index 0000000..4a32796
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/brightness/strategy/TemporaryBrightnessStrategyTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.display.brightness.strategy;
+
+
+import static org.junit.Assert.assertEquals;
+
+import android.hardware.display.DisplayManagerInternal;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.display.DisplayBrightnessState;
+import com.android.server.display.brightness.BrightnessReason;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+
+public class TemporaryBrightnessStrategyTest {
+    private TemporaryBrightnessStrategy mTemporaryBrightnessStrategy;
+
+    @Before
+    public void before() {
+        mTemporaryBrightnessStrategy = new TemporaryBrightnessStrategy();
+    }
+
+    @Test
+    public void updateBrightnessWorksAsExpectedWhenTemporaryBrightnessIsSet() {
+        DisplayManagerInternal.DisplayPowerRequest
+                displayPowerRequest = new DisplayManagerInternal.DisplayPowerRequest();
+        float temporaryBrightness = 0.2f;
+        mTemporaryBrightnessStrategy.setTemporaryScreenBrightness(temporaryBrightness);
+        BrightnessReason brightnessReason = new BrightnessReason();
+        brightnessReason.setReason(BrightnessReason.REASON_TEMPORARY);
+        DisplayBrightnessState expectedDisplayBrightnessState =
+                new DisplayBrightnessState.Builder()
+                        .setBrightness(temporaryBrightness)
+                        .setBrightnessReason(brightnessReason)
+                        .setSdrBrightness(temporaryBrightness)
+                        .build();
+        DisplayBrightnessState updatedDisplayBrightnessState =
+                mTemporaryBrightnessStrategy.updateBrightness(displayPowerRequest);
+        assertEquals(updatedDisplayBrightnessState, expectedDisplayBrightnessState);
+        assertEquals(mTemporaryBrightnessStrategy.getTemporaryScreenBrightness(),
+                Float.NaN, 0.0f);
+    }
+
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
index 5b11466..09cd47a 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/ArcTerminationActionFromAvrTest.java
@@ -143,8 +143,12 @@
                 Constants.ADDR_AUDIO_SYSTEM, Constants.ADDR_TV);
 
         assertThat(mNativeWrapper.getResultMessages()).contains(terminateArc);
+        mTestLooper.dispatchAll();
 
-        assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isTrue();
+        mTestLooper.moveTimeForward(ArcTerminationActionFromAvr.TIMEOUT_MS);
+        mTestLooper.dispatchAll();
+
+        assertThat(mHdmiCecLocalDeviceAudioSystem.isArcEnabled()).isFalse();
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
index 7df0078..6a899e8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromPlaybackTest.java
@@ -102,7 +102,7 @@
                         Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK),
                         new FakeAudioDeviceVolumeManagerWrapper()) {
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
index ac57834..0419768 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/DeviceSelectActionFromTvTest.java
@@ -111,7 +111,7 @@
                         Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
                         new FakeAudioDeviceVolumeManagerWrapper()) {
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
index 0028969..167e0f8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/FakeHdmiCecConfig.java
@@ -80,6 +80,17 @@
                 R.bool.config_cecRoutingControlDisabled_default);
 
         doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSoundbarMode_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSoundbarModeEnabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_cecSoundbarModeEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSoundbarModeDisabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_cecSoundbarModeDisabled_default);
+
+        doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecPowerControlMode_userConfigurable);
         doReturn(true).when(resources).getBoolean(
                 R.bool.config_cecPowerControlModeTv_allowed);
@@ -348,6 +359,17 @@
         doReturn(true).when(resources).getBoolean(R.bool.config_cecQuerySadMaxDisabled_allowed);
         doReturn(false).when(resources).getBoolean(R.bool.config_cecQuerySadMaxDisabled_default);
 
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_earcEnabled_userConfigurable);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_earcFeatureEnabled_allowed);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_earcFeatureEnabled_default);
+        doReturn(true).when(resources).getBoolean(
+                R.bool.config_earcFeatureDisabled_allowed);
+        doReturn(false).when(resources).getBoolean(
+                R.bool.config_earcFeatureDisabled_default);
+
         return resources;
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
index 8e756ae..870b681 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecConfigTest.java
@@ -76,6 +76,7 @@
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                     HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
+                    HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
@@ -105,7 +106,8 @@
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
-                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX);
+                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX,
+                    HdmiControlManager.SETTING_NAME_EARC_ENABLED);
     }
 
     @Test
@@ -115,6 +117,7 @@
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_ENABLED,
                     HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                     HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
+                    HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
@@ -144,7 +147,8 @@
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
-                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX);
+                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX,
+                    HdmiControlManager.SETTING_NAME_EARC_ENABLED);
     }
 
     @Test
@@ -155,6 +159,7 @@
                 .containsExactly(HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_CONTROL_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_ROUTING_CONTROL,
+                    HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
                     HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_CONTROL,
                     HdmiControlManager.CEC_SETTING_NAME_SYSTEM_AUDIO_MODE_MUTING,
@@ -183,7 +188,8 @@
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_TRUEHD,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_DST,
                     HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_WMAPRO,
-                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX);
+                    HdmiControlManager.CEC_SETTING_NAME_QUERY_SAD_MAX,
+                    HdmiControlManager.SETTING_NAME_EARC_ENABLED);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
index 08d0e90..7c6c990 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystemTest.java
@@ -354,7 +354,7 @@
         HdmiCecMessage expectedMessage =
                 HdmiCecMessageBuilder.buildSetSystemAudioMode(
                         ADDR_AUDIO_SYSTEM, ADDR_BROADCAST, false);
-        assertThat(mNativeWrapper.getOnlyResultMessage()).isEqualTo(expectedMessage);
+        assertThat(mNativeWrapper.getResultMessages()).contains(expectedMessage);
         assertThat(mMusicMute).isTrue();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
index 75c4d92..3ed8983 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java
@@ -31,6 +31,7 @@
 import android.hardware.hdmi.HdmiPortInfo;
 import android.hardware.hdmi.IHdmiControlCallback;
 import android.hardware.tv.cec.V1_0.SendMessageResult;
+import android.media.AudioManager;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.test.TestLooper;
@@ -45,6 +46,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -85,9 +88,13 @@
     private boolean mActiveMediaSessionsPaused;
     private FakePowerManagerInternalWrapper mPowerManagerInternal =
             new FakePowerManagerInternalWrapper();
+    @Mock
+    protected AudioManager mAudioManager;
 
     @Before
     public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
         Context context = InstrumentationRegistry.getTargetContext();
         mMyLooper = mTestLooper.getLooper();
 
@@ -103,12 +110,17 @@
                     }
 
                     @Override
+                    AudioManager getAudioManager() {
+                        return mAudioManager;
+                    }
+
+                    @Override
                     void pauseActiveMediaSessions() {
                         mActiveMediaSessionsPaused = true;
                     }
 
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
@@ -1424,6 +1436,32 @@
     }
 
     @Test
+    public void sendVolumeKeyEvent_toLocalDevice_discardMessage() {
+        HdmiCecLocalDeviceAudioSystem audioSystem =
+                new HdmiCecLocalDeviceAudioSystem(mHdmiControlService);
+        audioSystem.init();
+        mLocalDevices.add(audioSystem);
+        mHdmiControlService.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+
+        mHdmiControlService.setHdmiCecVolumeControlEnabledInternal(
+                HdmiControlManager.VOLUME_CONTROL_ENABLED);
+        mHdmiControlService.setSystemAudioActivated(true);
+
+        mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, true);
+        mHdmiCecLocalDevicePlayback.sendVolumeKeyEvent(KeyEvent.KEYCODE_VOLUME_UP, false);
+
+        HdmiCecMessage keyPressed = HdmiCecMessageBuilder.buildUserControlPressed(
+                mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM, HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP);
+        HdmiCecMessage keyReleased = HdmiCecMessageBuilder.buildUserControlReleased(
+                mPlaybackLogicalAddress, ADDR_AUDIO_SYSTEM);
+        mTestLooper.dispatchAll();
+
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyPressed);
+        assertThat(mNativeWrapper.getResultMessages()).doesNotContain(keyReleased);
+    }
+
+    @Test
     public void handleSetStreamPath_broadcastsActiveSource() {
         HdmiCecMessage setStreamPath = HdmiCecMessageBuilder.buildSetStreamPath(ADDR_TV,
                 mPlaybackPhysicalAddress);
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
index 48e70fe..b30118c 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -141,7 +141,7 @@
                 new HdmiControlService(context, Collections.emptyList(),
                         new FakeAudioDeviceVolumeManagerWrapper()) {
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return isControlEnabled;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
index 82c3401..5246107 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTvTest.java
@@ -136,7 +136,7 @@
                         super.wakeUp();
                     }
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
index a08e398..4e5336e 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecPowerStatusControllerTest.java
@@ -68,7 +68,7 @@
                 Collections.singletonList(HdmiDeviceInfo.DEVICE_PLAYBACK),
                 new FakeAudioDeviceVolumeManagerWrapper()) {
             @Override
-            boolean isControlEnabled() {
+            boolean isCecControlEnabled() {
                 return true;
             }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
index 8f6bee1..ef2b212 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTest.java
@@ -44,6 +44,7 @@
 import android.hardware.hdmi.IHdmiCecVolumeControlFeatureListener;
 import android.hardware.hdmi.IHdmiControlStatusChangeListener;
 import android.hardware.hdmi.IHdmiVendorCommandListener;
+import android.media.AudioManager;
 import android.os.Binder;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -58,7 +59,9 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -86,8 +89,12 @@
     private HdmiPortInfo[] mHdmiPortInfo;
     private ArrayList<Integer> mLocalDeviceTypes = new ArrayList<>();
 
+    @Mock protected AudioManager mAudioManager;
+
     @Before
     public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
         mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
 
         HdmiCecConfig hdmiCecConfig = new FakeHdmiCecConfig(mContextSpy);
@@ -132,6 +139,7 @@
         mPowerManager = new FakePowerManagerWrapper(mContextSpy);
         mHdmiControlServiceSpy.setPowerManager(mPowerManager);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mHdmiControlServiceSpy.setAudioManager(mAudioManager);
 
         mTestLooper.dispatchAll();
     }
@@ -195,7 +203,7 @@
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mNativeWrapper.clearResultMessages();
 
         assertThat(mHdmiControlServiceSpy.getInitialPowerStatus()).isEqualTo(
@@ -228,7 +236,7 @@
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
         mTestLooper.dispatchAll();
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mNativeWrapper.clearResultMessages();
         mTestLooper.dispatchAll();
 
@@ -285,11 +293,11 @@
         int volumeControlEnabled = HdmiControlManager.VOLUME_CONTROL_ENABLED;
         mHdmiControlServiceSpy.setHdmiCecVolumeControlEnabledInternal(volumeControlEnabled);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         assertThat(mHdmiControlServiceSpy.getHdmiCecVolumeControl()).isEqualTo(
                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getHdmiCecVolumeControl())
                 .isEqualTo(volumeControlEnabled);
     }
@@ -300,12 +308,12 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE, volumeControlEnabled);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
                 volumeControlEnabled);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getHdmiCecConfig().getIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_VOLUME_CONTROL_MODE)).isEqualTo(
                 volumeControlEnabled);
@@ -320,13 +328,13 @@
         VolumeControlFeatureCallback callback = new VolumeControlFeatureCallback();
         mHdmiControlServiceSpy.addHdmiCecVolumeControlFeatureListener(callback);
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         assertThat(callback.mCallbackReceived).isTrue();
         assertThat(callback.mVolumeControlEnabled).isEqualTo(
                 HdmiControlManager.VOLUME_CONTROL_DISABLED);
 
 
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(callback.mVolumeControlEnabled).isEqualTo(
                 HdmiControlManager.VOLUME_CONTROL_ENABLED);
     }
@@ -423,7 +431,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
     }
@@ -433,7 +441,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
@@ -443,14 +451,14 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
 
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         assertThat(mHdmiControlServiceSpy.getCecVersion()).isEqualTo(
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
     }
@@ -460,7 +468,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mTestLooper.dispatchAll();
 
         mNativeWrapper.onCecMessage(HdmiCecMessageBuilder.buildGiveFeatures(Constants.ADDR_TV,
@@ -478,7 +486,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -500,7 +508,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_1_4_B);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -517,7 +525,7 @@
         mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
                 HdmiControlManager.CEC_SETTING_NAME_HDMI_CEC_VERSION,
                 HdmiControlManager.HDMI_CEC_VERSION_2_0);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -624,11 +632,11 @@
     @Test
     public void initCec_statusListener_CecEnabled_CecAvailable_TvOn() {
         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         mTestLooper.dispatchAll();
 
         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -647,11 +655,11 @@
     @Test
     public void initCec_statusListener_CecEnabled_CecAvailable_TvStandby() {
         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         mTestLooper.dispatchAll();
 
         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -670,11 +678,11 @@
     @Test
     public void initCec_statusListener_CecEnabled_CecAvailable_TvTransientToOn() {
         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         mTestLooper.dispatchAll();
 
         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -693,11 +701,11 @@
     @Test
     public void initCec_statusListener_CecEnabled_CecAvailable_TvTransientToStandby() {
         HdmiControlStatusCallback hdmiControlStatusCallback = new HdmiControlStatusCallback();
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_DISABLED);
         mTestLooper.dispatchAll();
 
         mHdmiControlServiceSpy.addHdmiControlStatusChangeListener(hdmiControlStatusCallback);
-        mHdmiControlServiceSpy.setControlEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
+        mHdmiControlServiceSpy.setCecEnabled(HdmiControlManager.HDMI_CEC_CONTROL_ENABLED);
         mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
         mTestLooper.dispatchAll();
 
@@ -1026,6 +1034,48 @@
                 .containsExactly(DEVICE_PLAYBACK, DEVICE_AUDIO_SYSTEM);
     }
 
+    @Test
+    public void setSoundbarMode_enabled_addAudioSystemLocalDevice() {
+        // Initialize the local devices excluding the audio system.
+        mHdmiControlServiceSpy.clearCecLocalDevices();
+        mLocalDevices.remove(mAudioSystemDeviceSpy);
+        mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+
+        // Enable the setting and check if the audio system local device is found in the network.
+        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+                HdmiControlManager.SOUNDBAR_MODE_ENABLED);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
+    }
+
+    @Test
+    public void setSoundbarMode_disabled_removeAudioSystemLocalDevice() {
+        // Initialize the local devices excluding the audio system.
+        mHdmiControlServiceSpy.clearCecLocalDevices();
+        mLocalDevices.remove(mAudioSystemDeviceSpy);
+        mHdmiControlServiceSpy.allocateLogicalAddress(mLocalDevices, INITIATED_BY_ENABLE_CEC);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+
+        // Enable the setting and check if the audio system local device is found in the network.
+        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+                HdmiControlManager.SOUNDBAR_MODE_ENABLED);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiControlServiceSpy.audioSystem()).isNotNull();
+
+        // Disable the setting and check if the audio system local device is removed from the
+        // network.
+        mHdmiControlServiceSpy.getHdmiCecConfig().setIntValue(
+                HdmiControlManager.CEC_SETTING_NAME_SOUNDBAR_MODE,
+                HdmiControlManager.SOUNDBAR_MODE_DISABLED);
+        mTestLooper.dispatchAll();
+        assertThat(mHdmiControlServiceSpy.audioSystem()).isNull();
+    }
+
     protected static class MockPlaybackDevice extends HdmiCecLocalDevicePlayback {
 
         private boolean mCanGoToStandby;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
index c07d4be..f719ca1 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RequestSadActionTest.java
@@ -99,7 +99,7 @@
                 new HdmiControlService(context, Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
                         new FakeAudioDeviceVolumeManagerWrapper()) {
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
index f5bf30b..be62df8 100644
--- a/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
+++ b/services/tests/servicestests/src/com/android/server/hdmi/RoutingControlActionTest.java
@@ -151,7 +151,7 @@
                         Collections.singletonList(HdmiDeviceInfo.DEVICE_TV),
                         new FakeAudioDeviceVolumeManagerWrapper()) {
                     @Override
-                    boolean isControlEnabled() {
+                    boolean isCecControlEnabled() {
                         return true;
                     }
 
diff --git a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
index 6590a2b..ecd9d89 100644
--- a/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
+++ b/services/tests/servicestests/src/com/android/server/input/BatteryControllerTests.kt
@@ -16,6 +16,7 @@
 
 package com.android.server.input
 
+import android.bluetooth.BluetoothDevice
 import android.content.Context
 import android.content.ContextWrapper
 import android.hardware.BatteryState.STATUS_CHARGING
@@ -33,6 +34,8 @@
 import android.platform.test.annotations.Presubmit
 import android.view.InputDevice
 import androidx.test.InstrumentationRegistry
+import com.android.server.input.BatteryController.BluetoothBatteryManager
+import com.android.server.input.BatteryController.BluetoothBatteryManager.BluetoothBatteryListener
 import com.android.server.input.BatteryController.POLLING_PERIOD_MILLIS
 import com.android.server.input.BatteryController.UEventManager
 import com.android.server.input.BatteryController.UEventManager.UEventBatteryListener
@@ -52,6 +55,7 @@
 import org.junit.Rule
 import org.junit.Test
 import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.any
 import org.mockito.ArgumentMatchers.notNull
 import org.mockito.Mock
 import org.mockito.Mockito.anyInt
@@ -172,6 +176,8 @@
         const val SECOND_DEVICE_ID = 11
         const val USI_DEVICE_ID = 101
         const val SECOND_USI_DEVICE_ID = 102
+        const val BT_DEVICE_ID = 100001
+        const val SECOND_BT_DEVICE_ID = 100002
         const val TIMESTAMP = 123456789L
     }
 
@@ -184,6 +190,8 @@
     private lateinit var iInputManager: IInputManager
     @Mock
     private lateinit var uEventManager: UEventManager
+    @Mock
+    private lateinit var bluetoothBatteryManager: BluetoothBatteryManager
 
     private lateinit var batteryController: BatteryController
     private lateinit var context: Context
@@ -203,11 +211,13 @@
         addInputDevice(DEVICE_ID)
         addInputDevice(SECOND_DEVICE_ID)
 
-        batteryController = BatteryController(context, native, testLooper.looper, uEventManager)
+        batteryController = BatteryController(context, native, testLooper.looper, uEventManager,
+            bluetoothBatteryManager)
         batteryController.systemRunning()
         val listenerCaptor = ArgumentCaptor.forClass(IInputDevicesChangedListener::class.java)
         verify(iInputManager).registerInputDevicesChangedListener(listenerCaptor.capture())
         devicesChangedListener = listenerCaptor.value
+        testLooper.dispatchAll()
     }
 
     private fun notifyDeviceChanged(
@@ -230,7 +240,7 @@
     private fun addInputDevice(
             deviceId: Int,
         hasBattery: Boolean = true,
-        supportsUsi: Boolean = false
+        supportsUsi: Boolean = false,
     ) {
         deviceGenerationMap[deviceId] = 0
         notifyDeviceChanged(deviceId, hasBattery, supportsUsi)
@@ -634,4 +644,125 @@
         assertThat("battery state matches", batteryController.getBatteryState(USI_DEVICE_ID),
             matchesState(USI_DEVICE_ID, status = STATUS_UNKNOWN, capacity = 0f))
     }
+
+    @Test
+    fun testRegisterBluetoothListenerForMonitoredBluetoothDevices() {
+        `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+            .thenReturn("AA:BB:CC:DD:EE:FF")
+        `when`(iInputManager.getInputDeviceBluetoothAddress(SECOND_BT_DEVICE_ID))
+            .thenReturn("11:22:33:44:55:66")
+        addInputDevice(BT_DEVICE_ID)
+        testLooper.dispatchNext()
+        addInputDevice(SECOND_BT_DEVICE_ID)
+        testLooper.dispatchNext()
+
+        // Ensure that a BT battery listener is not added when there are no monitored BT devices.
+        verify(bluetoothBatteryManager, never()).addListener(any())
+
+        val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
+        val listener = createMockListener()
+
+        // The BT battery listener is added when the first BT input device is monitored.
+        batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+
+        // The BT listener is only added once for all BT devices.
+        batteryController.registerBatteryListener(SECOND_BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager, times(1)).addListener(any())
+
+        // The BT listener is only removed when there are no monitored BT devices.
+        batteryController.unregisterBatteryListener(BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager, never()).removeListener(any())
+
+        `when`(iInputManager.getInputDeviceBluetoothAddress(SECOND_BT_DEVICE_ID))
+            .thenReturn(null)
+        notifyDeviceChanged(SECOND_BT_DEVICE_ID)
+        testLooper.dispatchNext()
+        verify(bluetoothBatteryManager).removeListener(bluetoothListener.value)
+    }
+
+    @Test
+    fun testNotifiesBluetoothBatteryChanges() {
+        `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+            .thenReturn("AA:BB:CC:DD:EE:FF")
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(21)
+        addInputDevice(BT_DEVICE_ID)
+        val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
+        val listener = createMockListener()
+        batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
+
+        // When the state has not changed, the listener is not notified again.
+        bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+        listener.verifyNotified(BT_DEVICE_ID, mode = times(1), capacity = 0.21f)
+
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(25)
+        bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.25f)
+    }
+
+    @Test
+    fun testBluetoothBatteryIsPrioritized() {
+        `when`(native.getBatteryDevicePath(BT_DEVICE_ID)).thenReturn("/sys/dev/bt_device")
+        `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+            .thenReturn("AA:BB:CC:DD:EE:FF")
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(21)
+        `when`(native.getBatteryCapacity(BT_DEVICE_ID)).thenReturn(98)
+        addInputDevice(BT_DEVICE_ID)
+        val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
+        val listener = createMockListener()
+        val uEventListener = ArgumentCaptor.forClass(UEventBatteryListener::class.java)
+
+        // When the device is first monitored and both native and BT battery is available,
+        // the latter is used.
+        batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+        verify(uEventManager).addListener(uEventListener.capture(), any())
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
+        assertThat("battery state matches", batteryController.getBatteryState(BT_DEVICE_ID),
+            matchesState(BT_DEVICE_ID, capacity = 0.21f))
+
+        // If only the native battery state changes the listener is not notified.
+        `when`(native.getBatteryCapacity(BT_DEVICE_ID)).thenReturn(97)
+        uEventListener.value!!.onBatteryUEvent(TIMESTAMP)
+        listener.verifyNotified(BT_DEVICE_ID, mode = times(1), capacity = 0.21f)
+        assertThat("battery state matches", batteryController.getBatteryState(BT_DEVICE_ID),
+            matchesState(BT_DEVICE_ID, capacity = 0.21f))
+    }
+
+    @Test
+    fun testFallBackToNativeBatteryStateWhenBluetoothStateInvalid() {
+        `when`(native.getBatteryDevicePath(BT_DEVICE_ID)).thenReturn("/sys/dev/bt_device")
+        `when`(iInputManager.getInputDeviceBluetoothAddress(BT_DEVICE_ID))
+            .thenReturn("AA:BB:CC:DD:EE:FF")
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(21)
+        `when`(native.getBatteryCapacity(BT_DEVICE_ID)).thenReturn(98)
+        addInputDevice(BT_DEVICE_ID)
+        val bluetoothListener = ArgumentCaptor.forClass(BluetoothBatteryListener::class.java)
+        val listener = createMockListener()
+        val uEventListener = ArgumentCaptor.forClass(UEventBatteryListener::class.java)
+
+        batteryController.registerBatteryListener(BT_DEVICE_ID, listener, PID)
+        verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+        verify(uEventManager).addListener(uEventListener.capture(), any())
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.21f)
+
+        // Fall back to the native state when BT is off.
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF")))
+            .thenReturn(BluetoothDevice.BATTERY_LEVEL_BLUETOOTH_OFF)
+        bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.98f)
+
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF"))).thenReturn(22)
+        bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+        verify(bluetoothBatteryManager).addListener(bluetoothListener.capture())
+        listener.verifyNotified(BT_DEVICE_ID, capacity = 0.22f)
+
+        // Fall back to the native state when BT battery is unknown.
+        `when`(bluetoothBatteryManager.getBatteryLevel(eq("AA:BB:CC:DD:EE:FF")))
+            .thenReturn(BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
+        bluetoothListener.value!!.onBluetoothBatteryChanged(TIMESTAMP, "AA:BB:CC:DD:EE:FF")
+        listener.verifyNotified(BT_DEVICE_ID, mode = times(2), capacity = 0.98f)
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index c934e65..55ab4a0 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -33,6 +33,7 @@
 import android.app.admin.DeviceStateCache;
 import android.app.trust.TrustManager;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.hardware.authsecret.V1_0.IAuthSecret;
@@ -41,14 +42,18 @@
 import android.os.FileUtils;
 import android.os.IProgressListener;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
+import android.provider.Settings;
 import android.security.KeyStore;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.LockSettingsInternal;
 import com.android.internal.widget.LockscreenCredential;
@@ -59,6 +64,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.runner.RunWith;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -106,7 +112,8 @@
     FingerprintManager mFingerprintManager;
     FaceManager mFaceManager;
     PackageManager mPackageManager;
-    FakeSettings mSettings;
+    @Rule
+    public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
 
     @Before
     public void setUp_baseServices() throws Exception {
@@ -126,7 +133,6 @@
         mFingerprintManager = mock(FingerprintManager.class);
         mFaceManager = mock(FaceManager.class);
         mPackageManager = mock(PackageManager.class);
-        mSettings = new FakeSettings();
 
         LocalServices.removeServiceForTest(LockSettingsInternal.class);
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
@@ -134,12 +140,13 @@
         LocalServices.addService(DevicePolicyManagerInternal.class, mDevicePolicyManagerInternal);
         LocalServices.addService(WindowManagerInternal.class, mMockWindowManager);
 
-        mContext = new MockLockSettingsContext(InstrumentationRegistry.getContext(), mUserManager,
-                mNotificationManager, mDevicePolicyManager, mock(StorageManager.class),
-                mock(TrustManager.class), mock(KeyguardManager.class), mFingerprintManager,
-                mFaceManager, mPackageManager);
+        final Context origContext = InstrumentationRegistry.getContext();
+        mContext = new MockLockSettingsContext(origContext,
+                mSettingsRule.mockContentResolver(origContext), mUserManager, mNotificationManager,
+                mDevicePolicyManager, mock(StorageManager.class), mock(TrustManager.class),
+                mock(KeyguardManager.class), mFingerprintManager, mFaceManager, mPackageManager);
         mStorage = new LockSettingsStorageTestable(mContext,
-                new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings"));
+                new File(origContext.getFilesDir(), "locksettings"));
         File storageDir = mStorage.mStorageDir;
         if (storageDir.exists()) {
             FileUtils.deleteContents(storageDir);
@@ -153,7 +160,7 @@
         mService = new LockSettingsServiceTestable(mContext, mStorage,
                 mGateKeeperService, mKeyStore, setUpStorageManagerMock(), mActivityManager,
                 mSpManager, mAuthSecretService, mGsiService, mRecoverableKeyStoreManager,
-                mUserManagerInternal, mDeviceStateCache, mSettings);
+                mUserManagerInternal, mDeviceStateCache);
         mService.mHasSecureLockScreen = true;
         when(mUserManager.getUserInfo(eq(PRIMARY_USER_ID))).thenReturn(PRIMARY_USER_INFO);
         mPrimaryUserProfiles.add(PRIMARY_USER_INFO);
@@ -186,10 +193,25 @@
         mockBiometricsHardwareFingerprintsAndTemplates(PRIMARY_USER_ID);
         mockBiometricsHardwareFingerprintsAndTemplates(MANAGED_PROFILE_USER_ID);
 
-        mSettings.setDeviceProvisioned(true);
+        setDeviceProvisioned(true);
         mLocalService = LocalServices.getService(LockSettingsInternal.class);
     }
 
+    protected void setDeviceProvisioned(boolean provisioned) {
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.DEVICE_PROVISIONED, provisioned ? 1 : 0);
+    }
+
+    protected void setUserSetupComplete(boolean complete) {
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.USER_SETUP_COMPLETE, complete ? 1 : 0, UserHandle.USER_SYSTEM);
+    }
+
+    protected void setSecureFrpMode(boolean secure) {
+        Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                Settings.Secure.SECURE_FRP_MODE, secure ? 1 : 0, UserHandle.USER_SYSTEM);
+    }
+
     private UserInfo installChildProfile(int profileId) {
         final UserInfo userInfo = new UserInfo(
             profileId, null, null, UserInfo.FLAG_INITIALIZED | UserInfo.FLAG_MANAGED_PROFILE);
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java b/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java
deleted file mode 100644
index 2bcd653..0000000
--- a/services/tests/servicestests/src/com/android/server/locksettings/FakeSettings.java
+++ /dev/null
@@ -1,60 +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.locksettings;
-
-import android.content.ContentResolver;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-public class FakeSettings {
-
-    private int mDeviceProvisioned;
-    private int mSecureFrpMode;
-    private int mUserSetupComplete;
-
-    public void setDeviceProvisioned(boolean provisioned) {
-        mDeviceProvisioned = provisioned ? 1 : 0;
-    }
-
-    public void setSecureFrpMode(boolean secure) {
-        mSecureFrpMode = secure ? 1 : 0;
-    }
-
-    public void setUserSetupComplete(boolean complete) {
-        mUserSetupComplete = complete ? 1 : 0;
-    }
-
-    public int globalGetInt(String keyName) {
-        switch (keyName) {
-            case Settings.Global.DEVICE_PROVISIONED:
-                return mDeviceProvisioned;
-            default:
-                throw new IllegalArgumentException("Unhandled global settings: " + keyName);
-        }
-    }
-
-    public int secureGetInt(ContentResolver contentResolver, String keyName, int defaultValue,
-            int userId) {
-        if (Settings.Secure.SECURE_FRP_MODE.equals(keyName) && userId == UserHandle.USER_SYSTEM) {
-            return mSecureFrpMode;
-        }
-        if (Settings.Secure.USER_SETUP_COMPLETE.equals(keyName)
-                && userId == UserHandle.USER_SYSTEM) {
-            return mUserSetupComplete;
-        }
-        return defaultValue;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 85db23c..eccfa06 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -20,7 +20,6 @@
 
 import android.app.IActivityManager;
 import android.app.admin.DeviceStateCache;
-import android.content.ContentResolver;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.hardware.authsecret.V1_0.IAuthSecret;
@@ -52,14 +51,12 @@
         private RecoverableKeyStoreManager mRecoverableKeyStoreManager;
         private UserManagerInternal mUserManagerInternal;
         private DeviceStateCache mDeviceStateCache;
-        private FakeSettings mSettings;
 
         public MockInjector(Context context, LockSettingsStorage storage, KeyStore keyStore,
                 IActivityManager activityManager,
                 IStorageManager storageManager, SyntheticPasswordManager spManager,
                 FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
-                UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
-                FakeSettings settings) {
+                UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
             super(context);
             mLockSettingsStorage = storage;
             mKeyStore = keyStore;
@@ -70,7 +67,6 @@
             mRecoverableKeyStoreManager = recoverableKeyStoreManager;
             mUserManagerInternal = userManagerInternal;
             mDeviceStateCache = deviceStateCache;
-            mSettings = settings;
         }
 
         @Override
@@ -119,18 +115,6 @@
         }
 
         @Override
-        public int settingsGlobalGetInt(ContentResolver contentResolver, String keyName,
-                int defaultValue) {
-            return mSettings.globalGetInt(keyName);
-        }
-
-        @Override
-        public int settingsSecureGetInt(ContentResolver contentResolver, String keyName,
-                int defaultValue, int userId) {
-            return mSettings.secureGetInt(contentResolver, keyName, defaultValue, userId);
-        }
-
-        @Override
         public UserManagerInternal getUserManagerInternal() {
             return mUserManagerInternal;
         }
@@ -165,11 +149,10 @@
             IStorageManager storageManager, IActivityManager mActivityManager,
             SyntheticPasswordManager spManager, IAuthSecret authSecretService,
             FakeGsiService gsiService, RecoverableKeyStoreManager recoverableKeyStoreManager,
-            UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache,
-            FakeSettings settings) {
+            UserManagerInternal userManagerInternal, DeviceStateCache deviceStateCache) {
         super(new MockInjector(context, storage, keystore, mActivityManager,
-                storageManager, spManager, gsiService,
-                recoverableKeyStoreManager, userManagerInternal, deviceStateCache, settings));
+                storageManager, spManager, gsiService, recoverableKeyStoreManager,
+                userManagerInternal, deviceStateCache));
         mGateKeeperService = gatekeeper;
         mAuthSecretService = authSecretService;
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 3f259e3..196226a 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -424,8 +424,8 @@
 
     @Test
     public void testCredentialChangeNotPossibleInSecureFrpModeDuringSuw() {
-        mSettings.setUserSetupComplete(false);
-        mSettings.setSecureFrpMode(true);
+        setUserSetupComplete(false);
+        setSecureFrpMode(true);
         try {
             mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
             fail("Password shouldn't be changeable before FRP unlock");
@@ -434,8 +434,8 @@
 
     @Test
     public void testCredentialChangePossibleInSecureFrpModeAfterSuw() {
-        mSettings.setUserSetupComplete(true);
-        mSettings.setSecureFrpMode(true);
+        setUserSetupComplete(true);
+        setSecureFrpMode(true);
         assertTrue(mService.setLockCredential(newPassword("1234"), nonePassword(),
                 PRIMARY_USER_ID));
     }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index a663858..95d0e15 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -31,6 +31,7 @@
 import android.app.NotificationManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.database.sqlite.SQLiteDatabase;
@@ -49,11 +50,14 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.internal.util.test.FakeSettingsProviderRule;
 import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.locksettings.LockSettingsStorage.PersistentData;
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -78,14 +82,17 @@
 
     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 33};
 
-    LockSettingsStorageTestable mStorage;
-    File mStorageDir;
-
+    private LockSettingsStorageTestable mStorage;
+    private File mStorageDir;
     private File mDb;
+    @Rule
+    public FakeSettingsProviderRule mSettingsRule = FakeSettingsProvider.rule();
 
     @Before
     public void setUp() throws Exception {
-        mStorageDir = new File(InstrumentationRegistry.getContext().getFilesDir(), "locksettings");
+        final Context origContext = InstrumentationRegistry.getContext();
+
+        mStorageDir = new File(origContext.getFilesDir(), "locksettings");
         mDb = InstrumentationRegistry.getContext().getDatabasePath("locksettings.db");
 
         assertTrue(mStorageDir.exists() || mStorageDir.mkdirs());
@@ -98,8 +105,8 @@
         // User 3 is a profile of user 0.
         when(mockUserManager.getProfileParent(eq(3))).thenReturn(new UserInfo(0, "name", 0));
 
-        MockLockSettingsContext context = new MockLockSettingsContext(
-                InstrumentationRegistry.getContext(), mockUserManager,
+        MockLockSettingsContext context = new MockLockSettingsContext(origContext,
+                mSettingsRule.mockContentResolver(origContext), mockUserManager,
                 mock(NotificationManager.class), mock(DevicePolicyManager.class),
                 mock(StorageManager.class), mock(TrustManager.class), mock(KeyguardManager.class),
                 mock(FingerprintManager.class), mock(FaceManager.class),
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
index c2f94e2..fc0ca7e 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockscreenFrpTest.java
@@ -44,7 +44,7 @@
     @Before
     public void setDeviceNotProvisioned() throws Exception {
         // FRP credential can only be verified prior to provisioning
-        mSettings.setDeviceProvisioned(false);
+        setDeviceProvisioned(false);
     }
 
     @Before
@@ -98,6 +98,7 @@
         mService.setLockCredential(newPassword("1234"), nonePassword(), PRIMARY_USER_ID);
         assertEquals(CREDENTIAL_TYPE_PASSWORD, mService.getCredentialType(USER_FRP));
 
+        setDeviceProvisioned(true);
         mService.setLockCredential(nonePassword(), newPassword("1234"), PRIMARY_USER_ID);
         assertEquals(CREDENTIAL_TYPE_NONE, mService.getCredentialType(USER_FRP));
     }
@@ -106,7 +107,7 @@
     public void testFrpCredential_cannotVerifyAfterProvsioning() {
         mService.setLockCredential(newPin("1234"), nonePassword(), PRIMARY_USER_ID);
 
-        mSettings.setDeviceProvisioned(true);
+        setDeviceProvisioned(true);
         assertEquals(VerifyCredentialResponse.RESPONSE_ERROR,
                 mService.verifyCredential(newPin("1234"), USER_FRP, 0 /* flags */)
                         .getResponseCode());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
index efa1b04..21c367b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/MockLockSettingsContext.java
@@ -21,6 +21,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.Intent;
@@ -35,22 +36,25 @@
 
 public class MockLockSettingsContext extends ContextWrapper {
 
-    private UserManager mUserManager;
-    private NotificationManager mNotificationManager;
-    private DevicePolicyManager mDevicePolicyManager;
-    private StorageManager mStorageManager;
-    private TrustManager mTrustManager;
-    private KeyguardManager mKeyguardManager;
-    private FingerprintManager mFingerprintManager;
-    private FaceManager mFaceManager;
-    private PackageManager mPackageManager;
+    private final ContentResolver mContentResolver;
+    private final UserManager mUserManager;
+    private final NotificationManager mNotificationManager;
+    private final DevicePolicyManager mDevicePolicyManager;
+    private final StorageManager mStorageManager;
+    private final TrustManager mTrustManager;
+    private final KeyguardManager mKeyguardManager;
+    private final FingerprintManager mFingerprintManager;
+    private final FaceManager mFaceManager;
+    private final PackageManager mPackageManager;
 
-    public MockLockSettingsContext(Context base, UserManager userManager,
-            NotificationManager notificationManager, DevicePolicyManager devicePolicyManager,
-            StorageManager storageManager, TrustManager trustManager,
-            KeyguardManager keyguardManager, FingerprintManager fingerprintManager,
-            FaceManager faceManager, PackageManager packageManager) {
+    public MockLockSettingsContext(Context base, ContentResolver contentResolver,
+            UserManager userManager, NotificationManager notificationManager,
+            DevicePolicyManager devicePolicyManager, StorageManager storageManager,
+            TrustManager trustManager, KeyguardManager keyguardManager,
+            FingerprintManager fingerprintManager, FaceManager faceManager,
+            PackageManager packageManager) {
         super(base);
+        mContentResolver = contentResolver;
         mUserManager = userManager;
         mNotificationManager = notificationManager;
         mDevicePolicyManager = devicePolicyManager;
@@ -63,6 +67,11 @@
     }
 
     @Override
+    public ContentResolver getContentResolver() {
+        return mContentResolver;
+    }
+
+    @Override
     public Object getSystemService(String name) {
         if (USER_SERVICE.equals(name)) {
             return mUserManager;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 3f4bec6..b9cafa4 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -136,6 +136,43 @@
         assertTrue(mService.isSyntheticPasswordBasedCredential(userId));
     }
 
+    protected void initializeSyntheticPassword(int userId) {
+        synchronized (mService.mSpManager) {
+            mService.initializeSyntheticPasswordLocked(userId);
+        }
+    }
+
+    // Tests that the FRP credential is updated when an LSKF-based protector is created for the user
+    // that owns the FRP credential, if the device is already provisioned.
+    @Test
+    public void testFrpCredentialSyncedIfDeviceProvisioned() throws RemoteException {
+        setDeviceProvisioned(true);
+        initializeSyntheticPassword(PRIMARY_USER_ID);
+        verify(mStorage.mPersistentDataBlockManager).setFrpCredentialHandle(any());
+    }
+
+    // Tests that the FRP credential is not updated when an LSKF-based protector is created for the
+    // user that owns the FRP credential, if the new credential is empty and the device is not yet
+    // provisioned.
+    @Test
+    public void testEmptyFrpCredentialNotSyncedIfDeviceNotProvisioned() throws RemoteException {
+        setDeviceProvisioned(false);
+        initializeSyntheticPassword(PRIMARY_USER_ID);
+        verify(mStorage.mPersistentDataBlockManager, never()).setFrpCredentialHandle(any());
+    }
+
+    // Tests that the FRP credential is updated when an LSKF-based protector is created for the user
+    // that owns the FRP credential, if the new credential is nonempty and the device is not yet
+    // provisioned.
+    @Test
+    public void testNonEmptyFrpCredentialSyncedIfDeviceNotProvisioned() throws RemoteException {
+        setDeviceProvisioned(false);
+        initializeSyntheticPassword(PRIMARY_USER_ID);
+        verify(mStorage.mPersistentDataBlockManager, never()).setFrpCredentialHandle(any());
+        mService.setLockCredential(newPassword("password"), nonePassword(), PRIMARY_USER_ID);
+        verify(mStorage.mPersistentDataBlockManager).setFrpCredentialHandle(any());
+    }
+
     @Test
     public void testChangeCredential() throws RemoteException {
         final LockscreenCredential password = newPassword("password");
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
index a3ac515..6c13a6f 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
@@ -1,11 +1,17 @@
 package com.android.server.locksettings;
 
+import static org.junit.Assert.assertEquals;
+
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.server.locksettings.LockSettingsStorage.PersistentData;
+import com.google.android.collect.Sets;
+
 import org.junit.Before;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
 @SmallTest
@@ -17,4 +23,36 @@
     public void enableWeaver() throws Exception {
         mSpManager.enableWeaver();
     }
+
+    // Tests that if the device is not yet provisioned and the FRP credential uses Weaver, then the
+    // Weaver slot of the FRP credential is not reused.  Assumes that Weaver slots are allocated
+    // sequentially, starting at slot 0.
+    @Test
+    public void testFrpWeaverSlotNotReused() {
+        final int userId = 10;
+        final int frpWeaverSlot = 0;
+
+        setDeviceProvisioned(false);
+        assertEquals(Sets.newHashSet(), mPasswordSlotManager.getUsedSlots());
+        mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, frpWeaverSlot, 0,
+                new byte[1]);
+        initializeSyntheticPassword(userId); // This should allocate a Weaver slot.
+        assertEquals(Sets.newHashSet(1), mPasswordSlotManager.getUsedSlots());
+    }
+
+    // Tests that if the device is already provisioned and the FRP credential uses Weaver, then the
+    // Weaver slot of the FRP credential is reused.  This is not a very interesting test by itself;
+    // it's here as a control for testFrpWeaverSlotNotReused().
+    @Test
+    public void testFrpWeaverSlotReused() {
+        final int userId = 10;
+        final int frpWeaverSlot = 0;
+
+        setDeviceProvisioned(true);
+        assertEquals(Sets.newHashSet(), mPasswordSlotManager.getUsedSlots());
+        mStorage.writePersistentDataBlock(PersistentData.TYPE_SP_WEAVER, frpWeaverSlot, 0,
+                new byte[1]);
+        initializeSyntheticPassword(userId); // This should allocate a Weaver slot.
+        assertEquals(Sets.newHashSet(0), mPasswordSlotManager.getUsedSlots());
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/media/MediaButtonReceiverHolderTest.java b/services/tests/servicestests/src/com/android/server/media/MediaButtonReceiverHolderTest.java
new file mode 100644
index 0000000..1c4ee69
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/MediaButtonReceiverHolderTest.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.common.truth.Truth;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaButtonReceiverHolderTest {
+
+    @Test
+    public void createMediaButtonReceiverHolder_resolvesNullComponentName() {
+        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON);
+        PendingIntent pi = PendingIntent.getBroadcast(context, /* requestCode= */ 0, intent,
+                PendingIntent.FLAG_IMMUTABLE);
+        MediaButtonReceiverHolder a = MediaButtonReceiverHolder.create(/* userId= */ 0, pi,
+                context.getPackageName());
+        Truth.assertWithMessage("Component name must match PendingIntent creator package.").that(
+                a.getComponentName()).isNull();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/media/OWNERS b/services/tests/servicestests/src/com/android/server/media/OWNERS
new file mode 100644
index 0000000..55ffde2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/media/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137631
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
index ab52928..578b888 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -323,4 +323,19 @@
         FakeIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath);
         assertEquals(0, CONFIG_SIGNATURE & idmap.policies);
     }
+
+    @Test
+    public void testOnTargetSystemPackageUninstall() throws Exception {
+        installAndAssert(target(TARGET), USER,
+                Set.of(UserPackage.of(USER, TARGET)));
+        installAndAssert(overlay(OVERLAY, TARGET), USER,
+                Set.of(UserPackage.of(USER, OVERLAY), UserPackage.of(USER, TARGET)));
+        upgradeAndAssert(target(TARGET), USER,
+                Set.of(UserPackage.of(USER, TARGET)),
+                Set.of(UserPackage.of(USER, TARGET)));
+
+        downgradeAndAssert(target(TARGET), USER,
+                Set.of(UserPackage.of(USER, TARGET)),
+                Set.of(UserPackage.of(USER, TARGET)));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
index bba7669..dab4335 100644
--- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
+import android.content.Intent;
 import android.content.om.OverlayIdentifier;
 import android.content.om.OverlayInfo;
 import android.content.om.OverlayInfo.State;
@@ -160,7 +161,7 @@
      * Adds the package to the device.
      *
      * This corresponds to when the OMS receives the
-     * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast.
+     * {@link Intent#ACTION_PACKAGE_ADDED} broadcast.
      *
      * @throws IllegalStateException if the package is currently installed
      */
@@ -178,10 +179,10 @@
      * Begins upgrading the package.
      *
      * This corresponds to when the OMS receives the
-     * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the
-     * {@link android.content.Intent#EXTRA_REPLACING} extra and then receives the
-     * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the
-     * {@link android.content.Intent#EXTRA_REPLACING} extra.
+     * {@link Intent#ACTION_PACKAGE_REMOVED} broadcast with the
+     * {@link Intent#EXTRA_REPLACING} extra and then receives the
+     * {@link Intent#ACTION_PACKAGE_ADDED} broadcast with the
+     * {@link Intent#EXTRA_REPLACING} extra.
      *
      * @throws IllegalStateException if the package is not currently installed
      */
@@ -194,7 +195,35 @@
             throw new IllegalStateException("package " + pkg.packageName + " not installed");
         }
 
-        assertEquals(onReplacingUpdatedPackages, mImpl.onPackageReplacing(pkg.packageName, userId));
+        assertEquals(onReplacingUpdatedPackages, mImpl.onPackageReplacing(pkg.packageName,
+                /* systemUpdateUninstall */ false, userId));
+        mState.add(pkg, userId);
+        assertEquals(onReplacedUpdatedPackages, mImpl.onPackageReplaced(pkg.packageName, userId));
+    }
+
+    /**
+     * Begins downgrading the package. Usually used simulating a system uninstall of its /data
+     * variant.
+     *
+     * This corresponds to when the OMS receives the
+     * {@link Intent#ACTION_PACKAGE_REMOVED} broadcast with the
+     * {@link Intent#EXTRA_REPLACING} and {@link Intent#EXTRA_SYSTEM_UPDATE_UNINSTALL} extras
+     * and then receives the {@link Intent#ACTION_PACKAGE_ADDED} broadcast with the
+     * {@link Intent#EXTRA_REPLACING} extra.
+     *
+     * @throws IllegalStateException if the package is not currently installed
+     */
+    void downgradeAndAssert(FakeDeviceState.PackageBuilder pkg, int userId,
+            @NonNull Set<UserPackage> onReplacingUpdatedPackages,
+            @NonNull Set<UserPackage> onReplacedUpdatedPackages)
+            throws OperationFailedException {
+        final FakeDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId);
+        if (replacedPackage == null) {
+            throw new IllegalStateException("package " + pkg.packageName + " not installed");
+        }
+
+        assertEquals(onReplacingUpdatedPackages, mImpl.onPackageReplacing(pkg.packageName,
+                /* systemUpdateUninstall */ true, userId));
         mState.add(pkg, userId);
         assertEquals(onReplacedUpdatedPackages, mImpl.onPackageReplaced(pkg.packageName, userId));
     }
@@ -203,7 +232,7 @@
      * Removes the package from the device.
      *
      * This corresponds to when the OMS receives the
-     * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast.
+     * {@link Intent#ACTION_PACKAGE_REMOVED} broadcast.
      *
      * @throws IllegalStateException if the package is not currently installed
      */
diff --git a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
index 136e79e..261156611 100644
--- a/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/policy/DeviceStateProviderImplTest.java
@@ -456,9 +456,8 @@
                         new DeviceState(1, "CLOSED", 0 /* flags */),
                         new DeviceState(2, "HALF_OPENED", 0 /* flags */)
                 }, mDeviceStateArrayCaptor.getValue());
-        // onStateChanged() should be called because the provider could not find the sensor.
-        verify(listener).onStateChanged(mIntegerCaptor.capture());
-        assertEquals(1, mIntegerCaptor.getValue().intValue());
+        // onStateChanged() should not be called because the provider could not find the sensor.
+        verify(listener, never()).onStateChanged(mIntegerCaptor.capture());
     }
 
     private static Sensor newSensor(String name, String type) throws Exception {
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java
index e3ca170..b034b0d 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerGroupTest.java
@@ -21,7 +21,6 @@
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DIM;
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_DOZE;
 import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_OFF;
-import static android.hardware.display.DisplayManagerInternal.DisplayPowerRequest.POLICY_VR;
 import static android.os.PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
 import static android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN;
 import static android.os.PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD;
@@ -267,7 +266,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -308,7 +306,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -348,7 +345,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ true,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -387,7 +383,6 @@
                 powerSaveState,
                 /* quiescent= */ true,
                 /* dozeAfterScreenOff= */ true,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -407,83 +402,6 @@
     }
 
     @Test
-    public void testUpdateWhileAsleep_VrModeEnabled() {
-        final boolean batterySaverEnabled = false;
-        float brightnessFactor = 0.3f;
-        PowerSaveState powerSaveState = new PowerSaveState.Builder()
-                .setBatterySaverEnabled(batterySaverEnabled)
-                .setBrightnessFactor(brightnessFactor)
-                .build();
-        mPowerGroup.sleepLocked(TIMESTAMP1, UID, GO_TO_SLEEP_REASON_TIMEOUT);
-        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
-        mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
-                /* autoBrightness = */ true,
-                /* useProximitySensor= */ true,
-                /* boostScreenBrightness= */ true,
-                /* dozeScreenStateOverride= */ Display.STATE_ON,
-                /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
-                /* overrideDrawWakeLock= */ false,
-                powerSaveState,
-                /* quiescent= */ false,
-                /* dozeAfterScreenOff= */ true,
-                /* vrModeEnabled= */ true,
-                /* bootCompleted= */ true,
-                /* screenBrightnessBoostInProgress= */ false,
-                /* waitForNegativeProximity= */ false);
-        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
-                mPowerGroup.mDisplayPowerRequest;
-        assertThat(displayPowerRequest.policy).isEqualTo(POLICY_OFF);
-        assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
-        assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true);
-        assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
-        assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
-        assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
-        assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
-                PowerManager.BRIGHTNESS_INVALID_FLOAT);
-        assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
-        assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
-                brightnessFactor);
-    }
-
-    @Test
-    public void testUpdateWhileAwake_VrModeEnabled() {
-        final boolean batterySaverEnabled = false;
-        float brightnessFactor = 0.3f;
-        PowerSaveState powerSaveState = new PowerSaveState.Builder()
-                .setBatterySaverEnabled(batterySaverEnabled)
-                .setBrightnessFactor(brightnessFactor)
-                .build();
-        assertThat(mPowerGroup.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
-        mPowerGroup.updateLocked(/* screenBrightnessOverride= */ BRIGHTNESS,
-                /* autoBrightness = */ true,
-                /* useProximitySensor= */ true,
-                /* boostScreenBrightness= */ true,
-                /* dozeScreenStateOverride= */ Display.STATE_ON,
-                /* dozeScreenBrightness= */ BRIGHTNESS_DOZE,
-                /* overrideDrawWakeLock= */ false,
-                powerSaveState,
-                /* quiescent= */ false,
-                /* dozeAfterScreenOff= */ true,
-                /* vrModeEnabled= */ true,
-                /* bootCompleted= */ true,
-                /* screenBrightnessBoostInProgress= */ false,
-                /* waitForNegativeProximity= */ false);
-        DisplayManagerInternal.DisplayPowerRequest displayPowerRequest =
-                mPowerGroup.mDisplayPowerRequest;
-        assertThat(displayPowerRequest.policy).isEqualTo(POLICY_VR);
-        assertThat(displayPowerRequest.screenBrightnessOverride).isWithin(PRECISION).of(BRIGHTNESS);
-        assertThat(displayPowerRequest.useAutoBrightness).isEqualTo(true);
-        assertThat(displayPowerRequest.useProximitySensor).isEqualTo(true);
-        assertThat(displayPowerRequest.boostScreenBrightness).isEqualTo(true);
-        assertThat(displayPowerRequest.dozeScreenState).isEqualTo(Display.STATE_UNKNOWN);
-        assertThat(displayPowerRequest.dozeScreenBrightness).isEqualTo(
-                PowerManager.BRIGHTNESS_INVALID_FLOAT);
-        assertThat(displayPowerRequest.lowPowerMode).isEqualTo(batterySaverEnabled);
-        assertThat(displayPowerRequest.screenLowPowerBrightnessFactor).isWithin(PRECISION).of(
-                brightnessFactor);
-    }
-
-    @Test
     public void testUpdateWhileAsleep_UpdatesDisplayPowerRequest() {
         final boolean batterySaverEnabled = false;
         float brightnessFactor = 0.3f;
@@ -503,7 +421,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -543,7 +460,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -581,7 +497,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ false,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -620,7 +535,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ false,
                 /* waitForNegativeProximity= */ false);
@@ -658,7 +572,6 @@
                 powerSaveState,
                 /* quiescent= */ false,
                 /* dozeAfterScreenOff= */ false,
-                /* vrModeEnabled= */ false,
                 /* bootCompleted= */ true,
                 /* screenBrightnessBoostInProgress= */ true,
                 /* waitForNegativeProximity= */ false);
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index c81db92..d7ff553 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -454,39 +454,6 @@
     }
 
     @Test
-    public void testGetDesiredScreenPolicy_WithVR() {
-        createService();
-        startSystem();
-        // Brighten up the screen
-        mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
-                null, null);
-        assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
-                DisplayPowerRequest.POLICY_BRIGHT);
-
-        // Move to VR
-        mService.setVrModeEnabled(true);
-        assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
-                DisplayPowerRequest.POLICY_VR);
-
-        // Then take a nap
-        mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_ASLEEP, 0, 0, 0, 0,
-                null, null);
-        assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
-                DisplayPowerRequest.POLICY_OFF);
-
-        // Wake up to VR
-        mService.setWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP, WAKEFULNESS_AWAKE, 0, 0, 0, 0,
-                null, null);
-        assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
-                DisplayPowerRequest.POLICY_VR);
-
-        // And back to normal
-        mService.setVrModeEnabled(false);
-        assertThat(mService.getDesiredScreenPolicyLocked(Display.DEFAULT_DISPLAY)).isEqualTo(
-                DisplayPowerRequest.POLICY_BRIGHT);
-    }
-
-    @Test
     public void testWakefulnessAwake_InitialValue() {
         createService();
         assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
@@ -1787,10 +1754,8 @@
         when(mNativeWrapperMock.nativeSetPowerMode(anyInt(), anyBoolean())).thenReturn(true);
 
         mService.getBinderServiceInstance().setPowerMode(Mode.LAUNCH, true);
-        mService.getBinderServiceInstance().setPowerMode(Mode.VR, false);
 
         verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.LAUNCH), eq(true));
-        verify(mNativeWrapperMock).nativeSetPowerMode(eq(Mode.VR), eq(false));
     }
 
     @Test
@@ -2014,6 +1979,50 @@
     }
 
     @Test
+    public void testMultiDisplay_defaultDozing_addNewDisplayDefaultGoesBackToDoze() {
+        final int nonDefaultDisplayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1;
+        final int nonDefaultDisplay = Display.DEFAULT_DISPLAY + 1;
+        final AtomicReference<DisplayManagerInternal.DisplayGroupListener> listener =
+                new AtomicReference<>();
+        doAnswer((Answer<Void>) invocation -> {
+            listener.set(invocation.getArgument(0));
+            return null;
+        }).when(mDisplayManagerInternalMock).registerDisplayGroupListener(any());
+        final DisplayInfo info = new DisplayInfo();
+        info.displayGroupId = nonDefaultDisplayGroupId;
+        when(mDisplayManagerInternalMock.getDisplayInfo(nonDefaultDisplay)).thenReturn(info);
+
+        doAnswer(inv -> {
+            when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
+            return null;
+        }).when(mDreamManagerInternalMock).startDream(anyBoolean(), anyString());
+
+        createService();
+        startSystem();
+
+        assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+                WAKEFULNESS_AWAKE);
+
+        forceDozing();
+        advanceTime(500);
+
+        assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+                WAKEFULNESS_DOZING);
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
+        verify(mDreamManagerInternalMock).startDream(eq(true), anyString());
+
+        listener.get().onDisplayGroupAdded(nonDefaultDisplayGroupId);
+        advanceTime(500);
+
+        assertThat(mService.getGlobalWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
+        assertThat(mService.getWakefulnessLocked(nonDefaultDisplayGroupId)).isEqualTo(
+                WAKEFULNESS_AWAKE);
+        assertThat(mService.getWakefulnessLocked(Display.DEFAULT_DISPLAY_GROUP)).isEqualTo(
+                WAKEFULNESS_DOZING);
+        verify(mDreamManagerInternalMock, times(2)).startDream(eq(true), anyString());
+    }
+
+    @Test
     public void testLastSleepTime_notUpdatedWhenDreaming() {
         createService();
         startSystem();
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
index 153d746..0d6bb8a 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/ConfigurationInternalTest.java
@@ -24,6 +24,7 @@
 import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_GEO;
 import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_MANUAL;
 import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_TELEPHONY;
+import static com.android.server.timezonedetector.ConfigurationInternal.DETECTION_MODE_UNKNOWN;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -51,11 +52,11 @@
 
     /**
      * Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
-     * is supported (and geo detection is supported)
+     * is supported (both telephony and geo detection are supported)
      */
     @Test
     @Parameters({ "true,true", "true,false", "false,true", "false,false" })
-    public void test_autoDetectionSupported_capabilitiesAndConfiguration(
+    public void test_telephonyAndGeoSupported_capabilitiesAndConfiguration(
             boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder()
                 .setUserId(ARBITRARY_USER_ID)
@@ -72,18 +73,20 @@
 
         boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
 
-        // Auto-detection enabled.
+        // Auto-detection enabled, location enabled.
         {
-            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
                     .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
                     .build();
-            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
-            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
-            assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
-            assertTrue(autoOnConfig.isGeoDetectionExecutionEnabled());
-            assertEquals(DETECTION_MODE_GEO, autoOnConfig.getDetectionMode());
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getLocationEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertTrue(config.getAutoDetectionEnabledBehavior());
+            assertTrue(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_GEO, config.getDetectionMode());
 
-            TimeZoneCapabilities capabilities = autoOnConfig.asCapabilities(bypassUserPolicyChecks);
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
             if (userRestrictionsExpected) {
                 assertEquals(CAPABILITY_NOT_ALLOWED,
                         capabilities.getConfigureAutoDetectionEnabledCapability());
@@ -99,24 +102,58 @@
             assertEquals(CAPABILITY_POSSESSED,
                     capabilities.getConfigureGeoDetectionEnabledCapability());
 
-            TimeZoneConfiguration configuration = autoOnConfig.asConfiguration();
+            TimeZoneConfiguration configuration = config.asConfiguration();
+            assertTrue(configuration.isAutoDetectionEnabled());
+            assertTrue(configuration.isGeoDetectionEnabled());
+        }
+
+        // Auto-detection enabled, location disabled.
+        {
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(false)
+                    .build();
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertFalse(config.getLocationEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertTrue(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_TELEPHONY, config.getDetectionMode());
+
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
+            if (userRestrictionsExpected) {
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getSetManualTimeZoneCapability());
+            } else {
+                assertEquals(CAPABILITY_POSSESSED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_APPLICABLE,
+                        capabilities.getSetManualTimeZoneCapability());
+            }
+            // This has user privacy implications so it is not restricted in the same way as others.
+            assertEquals(CAPABILITY_NOT_APPLICABLE,
+                    capabilities.getConfigureGeoDetectionEnabledCapability());
+
+            TimeZoneConfiguration configuration = config.asConfiguration();
             assertTrue(configuration.isAutoDetectionEnabled());
             assertTrue(configuration.isGeoDetectionEnabled());
         }
 
         // Auto-detection disabled.
         {
-            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
                     .setAutoDetectionEnabledSetting(false)
                     .build();
-            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
-            assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
-            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
-            assertFalse(autoOffConfig.isGeoDetectionExecutionEnabled());
-            assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
+            assertFalse(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getLocationEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertFalse(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
 
-            TimeZoneCapabilities capabilities =
-                    autoOffConfig.asCapabilities(bypassUserPolicyChecks);
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
             if (userRestrictionsExpected) {
                 assertEquals(CAPABILITY_NOT_ALLOWED,
                         capabilities.getConfigureAutoDetectionEnabledCapability());
@@ -132,7 +169,7 @@
             assertEquals(CAPABILITY_NOT_APPLICABLE,
                     capabilities.getConfigureGeoDetectionEnabledCapability());
 
-            TimeZoneConfiguration configuration = autoOffConfig.asConfiguration();
+            TimeZoneConfiguration configuration = config.asConfiguration();
             assertFalse(configuration.isAutoDetectionEnabled());
             assertTrue(configuration.isGeoDetectionEnabled());
         }
@@ -161,18 +198,20 @@
 
         boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
 
-        // Auto-detection enabled.
+        // Auto-detection enabled, location enabled.
         {
-            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
                     .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
                     .build();
-            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
-            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
-            assertFalse(autoOnConfig.getAutoDetectionEnabledBehavior());
-            assertFalse(autoOnConfig.isGeoDetectionExecutionEnabled());
-            assertEquals(DETECTION_MODE_MANUAL, autoOnConfig.getDetectionMode());
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getLocationEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertFalse(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
 
-            TimeZoneCapabilities capabilities = autoOnConfig.asCapabilities(bypassUserPolicyChecks);
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
             assertEquals(CAPABILITY_NOT_SUPPORTED,
                     capabilities.getConfigureAutoDetectionEnabledCapability());
             if (userRestrictionsExpected) {
@@ -183,7 +222,36 @@
             assertEquals(CAPABILITY_NOT_SUPPORTED,
                     capabilities.getConfigureGeoDetectionEnabledCapability());
 
-            TimeZoneConfiguration configuration = autoOnConfig.asConfiguration();
+            TimeZoneConfiguration configuration = config.asConfiguration();
+            assertTrue(configuration.isAutoDetectionEnabled());
+            assertTrue(configuration.isGeoDetectionEnabled());
+        }
+
+        // Auto-detection enabled, location disabled.
+        {
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(false)
+                    .build();
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertFalse(config.getLocationEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertFalse(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
+
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
+            assertEquals(CAPABILITY_NOT_SUPPORTED,
+                    capabilities.getConfigureAutoDetectionEnabledCapability());
+            if (userRestrictionsExpected) {
+                assertEquals(CAPABILITY_NOT_ALLOWED, capabilities.getSetManualTimeZoneCapability());
+            } else {
+                assertEquals(CAPABILITY_POSSESSED, capabilities.getSetManualTimeZoneCapability());
+            }
+            assertEquals(CAPABILITY_NOT_SUPPORTED,
+                    capabilities.getConfigureGeoDetectionEnabledCapability());
+
+            TimeZoneConfiguration configuration = config.asConfiguration();
             assertTrue(configuration.isAutoDetectionEnabled());
             assertTrue(configuration.isGeoDetectionEnabled());
         }
@@ -219,11 +287,11 @@
 
     /**
      * Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
-     * is supported (and geo detection is not supported).
+     * is supported (telephony only).
      */
     @Test
     @Parameters({ "true,true", "true,false", "false,true", "false,false" })
-    public void test_geoDetectNotSupported_capabilitiesAndConfiguration(
+    public void test_onlyTelephonySupported_capabilitiesAndConfiguration(
             boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder()
                 .setUserId(ARBITRARY_USER_ID)
@@ -242,16 +310,16 @@
 
         // Auto-detection enabled.
         {
-            ConfigurationInternal autoOnConfig = new ConfigurationInternal.Builder(baseConfig)
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
                     .setAutoDetectionEnabledSetting(true)
                     .build();
-            assertTrue(autoOnConfig.getAutoDetectionEnabledSetting());
-            assertTrue(autoOnConfig.getGeoDetectionEnabledSetting());
-            assertTrue(autoOnConfig.getAutoDetectionEnabledBehavior());
-            assertFalse(autoOnConfig.isGeoDetectionExecutionEnabled());
-            assertEquals(DETECTION_MODE_TELEPHONY, autoOnConfig.getDetectionMode());
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertTrue(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_TELEPHONY, config.getDetectionMode());
 
-            TimeZoneCapabilities capabilities = autoOnConfig.asCapabilities(bypassUserPolicyChecks);
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
             if (userRestrictionsExpected) {
                 assertEquals(CAPABILITY_NOT_ALLOWED,
                         capabilities.getConfigureAutoDetectionEnabledCapability());
@@ -266,24 +334,23 @@
             assertEquals(CAPABILITY_NOT_SUPPORTED,
                     capabilities.getConfigureGeoDetectionEnabledCapability());
 
-            TimeZoneConfiguration configuration = autoOnConfig.asConfiguration();
+            TimeZoneConfiguration configuration = config.asConfiguration();
             assertTrue(configuration.isAutoDetectionEnabled());
             assertTrue(configuration.isGeoDetectionEnabled());
         }
 
         // Auto-detection disabled.
         {
-            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
                     .setAutoDetectionEnabledSetting(false)
                     .build();
-            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
-            assertTrue(autoOffConfig.getGeoDetectionEnabledSetting());
-            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
-            assertFalse(autoOffConfig.isGeoDetectionExecutionEnabled());
-            assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
+            assertFalse(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getGeoDetectionEnabledSetting());
+            assertFalse(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_MANUAL, config.getDetectionMode());
 
-            TimeZoneCapabilities capabilities =
-                    autoOffConfig.asCapabilities(bypassUserPolicyChecks);
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
             if (userRestrictionsExpected) {
                 assertEquals(CAPABILITY_NOT_ALLOWED,
                         capabilities.getConfigureAutoDetectionEnabledCapability());
@@ -296,12 +363,137 @@
             assertEquals(CAPABILITY_NOT_SUPPORTED,
                     capabilities.getConfigureGeoDetectionEnabledCapability());
 
-            TimeZoneConfiguration configuration = autoOffConfig.asConfiguration();
+            TimeZoneConfiguration configuration = config.asConfiguration();
             assertFalse(configuration.isAutoDetectionEnabled());
             assertTrue(configuration.isGeoDetectionEnabled());
         }
     }
 
+    /**
+     * Tests {@link TimeCapabilitiesAndConfig} behavior in different scenarios when auto detection
+     * is supported (only geo detection)
+     */
+    @Test
+    @Parameters({ "true,true", "true,false", "false,true", "false,false" })
+    public void test_onlyGeoSupported_capabilitiesAndConfiguration(
+            boolean userConfigAllowed, boolean bypassUserPolicyChecks) {
+        ConfigurationInternal baseConfig = new ConfigurationInternal.Builder()
+                .setUserId(ARBITRARY_USER_ID)
+                .setUserConfigAllowed(userConfigAllowed)
+                .setTelephonyDetectionFeatureSupported(false)
+                .setGeoDetectionFeatureSupported(true)
+                .setGeoDetectionRunInBackgroundEnabled(false)
+                .setTelephonyFallbackSupported(false)
+                .setEnhancedMetricsCollectionEnabled(false)
+                .setAutoDetectionEnabledSetting(true)
+                .setLocationEnabledSetting(true)
+                .setGeoDetectionEnabledSetting(false)
+                .build();
+
+        boolean userRestrictionsExpected = !(userConfigAllowed || bypassUserPolicyChecks);
+
+        // Auto-detection enabled, location enabled.
+        {
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(true)
+                    .build();
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertTrue(config.getLocationEnabledSetting());
+            assertFalse(config.getGeoDetectionEnabledSetting());
+            assertTrue(config.getAutoDetectionEnabledBehavior());
+            assertTrue(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_GEO, config.getDetectionMode());
+
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
+            if (userRestrictionsExpected) {
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getSetManualTimeZoneCapability());
+            } else {
+                assertEquals(CAPABILITY_POSSESSED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_APPLICABLE,
+                        capabilities.getSetManualTimeZoneCapability());
+            }
+            // This capability is always "not supported" if geo detection is the only mechanism.
+            assertEquals(CAPABILITY_NOT_SUPPORTED,
+                    capabilities.getConfigureGeoDetectionEnabledCapability());
+
+            TimeZoneConfiguration configuration = config.asConfiguration();
+            assertTrue(configuration.isAutoDetectionEnabled());
+            assertFalse(configuration.isGeoDetectionEnabled());
+        }
+
+        // Auto-detection enabled, location disabled.
+        {
+            ConfigurationInternal config = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabledSetting(true)
+                    .setLocationEnabledSetting(false)
+                    .build();
+            assertTrue(config.getAutoDetectionEnabledSetting());
+            assertFalse(config.getLocationEnabledSetting());
+            assertFalse(config.getGeoDetectionEnabledSetting());
+            assertTrue(config.getAutoDetectionEnabledBehavior());
+            assertFalse(config.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_UNKNOWN, config.getDetectionMode());
+
+            TimeZoneCapabilities capabilities = config.asCapabilities(bypassUserPolicyChecks);
+            if (userRestrictionsExpected) {
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getSetManualTimeZoneCapability());
+            } else {
+                assertEquals(CAPABILITY_POSSESSED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_APPLICABLE,
+                        capabilities.getSetManualTimeZoneCapability());
+            }
+            // This capability is always "not supported" if geo detection is the only mechanism.
+            assertEquals(CAPABILITY_NOT_SUPPORTED,
+                    capabilities.getConfigureGeoDetectionEnabledCapability());
+
+            TimeZoneConfiguration configuration = config.asConfiguration();
+            assertTrue(configuration.isAutoDetectionEnabled());
+            assertFalse(configuration.isGeoDetectionEnabled());
+        }
+
+        // Auto-detection disabled.
+        {
+            ConfigurationInternal autoOffConfig = new ConfigurationInternal.Builder(baseConfig)
+                    .setAutoDetectionEnabledSetting(false)
+                    .build();
+            assertFalse(autoOffConfig.getAutoDetectionEnabledSetting());
+            assertFalse(autoOffConfig.getGeoDetectionEnabledSetting());
+            assertFalse(autoOffConfig.getAutoDetectionEnabledBehavior());
+            assertFalse(autoOffConfig.isGeoDetectionExecutionEnabled());
+            assertEquals(DETECTION_MODE_MANUAL, autoOffConfig.getDetectionMode());
+
+            TimeZoneCapabilities capabilities =
+                    autoOffConfig.asCapabilities(bypassUserPolicyChecks);
+            if (userRestrictionsExpected) {
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_NOT_ALLOWED,
+                        capabilities.getSetManualTimeZoneCapability());
+            } else {
+                assertEquals(CAPABILITY_POSSESSED,
+                        capabilities.getConfigureAutoDetectionEnabledCapability());
+                assertEquals(CAPABILITY_POSSESSED,
+                        capabilities.getSetManualTimeZoneCapability());
+            }
+            // This capability is always "not supported" if geo detection is the only mechanism.
+            assertEquals(CAPABILITY_NOT_SUPPORTED,
+                    capabilities.getConfigureGeoDetectionEnabledCapability());
+
+            TimeZoneConfiguration configuration = autoOffConfig.asConfiguration();
+            assertFalse(configuration.isAutoDetectionEnabled());
+            assertFalse(configuration.isGeoDetectionEnabled());
+        }
+    }
+
     @Test
     public void test_telephonyFallbackSupported() {
         ConfigurationInternal config = new ConfigurationInternal.Builder()
@@ -317,7 +509,10 @@
         assertTrue(config.isTelephonyFallbackSupported());
     }
 
-    /** Tests when {@link ConfigurationInternal#getGeoDetectionRunInBackgroundEnabled()} is true. */
+    /**
+     * Tests when {@link ConfigurationInternal#getGeoDetectionRunInBackgroundEnabledSetting()}
+     * is true.
+     */
     @Test
     public void test_geoDetectionRunInBackgroundEnabled() {
         ConfigurationInternal baseConfig = new ConfigurationInternal.Builder()
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
index bcdc65c..1e72369 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/FakeTimeZoneDetectorStrategy.java
@@ -111,7 +111,7 @@
     }
 
     @Override
-    public void enableTelephonyTimeZoneFallback() {
+    public void enableTelephonyTimeZoneFallback(String reason) {
         throw new UnsupportedOperationException();
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
index ea801e8..8207c19 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/MetricsTimeZoneDetectorStateTest.java
@@ -158,7 +158,7 @@
                 metricsTimeZoneDetectorState.isGeoDetectionSupported());
         assertEquals(configurationInternal.isTelephonyFallbackSupported(),
                 metricsTimeZoneDetectorState.isTelephonyTimeZoneFallbackSupported());
-        assertEquals(configurationInternal.getGeoDetectionRunInBackgroundEnabled(),
+        assertEquals(configurationInternal.getGeoDetectionRunInBackgroundEnabledSetting(),
                 metricsTimeZoneDetectorState.getGeoDetectionRunInBackgroundEnabled());
         assertEquals(configurationInternal.isEnhancedMetricsCollectionEnabled(),
                 metricsTimeZoneDetectorState.isEnhancedMetricsCollectionEnabled());
diff --git a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
index b991c5a..1c014d1 100644
--- a/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezonedetector/TimeZoneDetectorStrategyImplTest.java
@@ -29,6 +29,9 @@
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET;
 import static android.app.timezonedetector.TelephonyTimeZoneSuggestion.QUALITY_SINGLE_ZONE;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS;
+import static android.service.timezone.TimeZoneProviderStatus.DEPENDENCY_STATUS_UNKNOWN;
+import static android.service.timezone.TimeZoneProviderStatus.OPERATION_STATUS_UNKNOWN;
 
 import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_HIGH;
 import static com.android.server.SystemTimeZone.TIME_ZONE_CONFIDENCE_LOW;
@@ -65,6 +68,7 @@
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion.MatchType;
 import android.app.timezonedetector.TelephonyTimeZoneSuggestion.Quality;
 import android.os.HandlerThread;
+import android.service.timezone.TimeZoneProviderStatus;
 
 import com.android.server.SystemTimeZone.TimeZoneConfidence;
 import com.android.server.timezonedetector.TimeZoneDetectorStrategyImpl.QualifiedTelephonyTimeZoneSuggestion;
@@ -880,7 +884,7 @@
         TimeZoneDetectorStatus expectedInitialDetectorStatus = new TimeZoneDetectorStatus(
                 DETECTOR_STATUS_RUNNING,
                 TELEPHONY_ALGORITHM_RUNNING_STATUS,
-                LocationTimeZoneAlgorithmStatus.UNKNOWN);
+                LocationTimeZoneAlgorithmStatus.RUNNING_NOT_REPORTED);
         script.verifyCachedDetectorStatus(expectedInitialDetectorStatus);
 
         LocationTimeZoneAlgorithmStatus algorithmStatus1 = new LocationTimeZoneAlgorithmStatus(
@@ -1148,7 +1152,7 @@
     }
 
     @Test
-    public void testTelephonyFallback() {
+    public void testTelephonyFallback_enableTelephonyTimeZoneFallbackCalled() {
         ConfigurationInternal config = new ConfigurationInternal.Builder(
                 CONFIG_AUTO_ENABLED_GEO_ENABLED)
                 .setTelephonyFallbackSupported(true)
@@ -1178,19 +1182,21 @@
 
         // Receiving an "uncertain" geolocation suggestion should have no effect.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(true);
         }
 
         // Receiving a "certain" geolocation suggestion should disable telephony fallback mode.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent =
                     createCertainLocationAlgorithmEvent("Europe/London");
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
                     .verifyTelephonyFallbackIsEnabled(false);
         }
@@ -1214,17 +1220,19 @@
         // Geolocation suggestions should continue to be used as normal (previous telephony
         // suggestions are not used, even when the geolocation suggestion is uncertain).
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent certainLocationAlgorithmEvent =
                     createCertainLocationAlgorithmEvent("Europe/Rome");
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent)
                     .verifyTimeZoneChangedAndReset(certainLocationAlgorithmEvent)
                     .verifyTelephonyFallbackIsEnabled(false);
 
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent uncertainLocationAlgorithmEvent =
                     createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(uncertainLocationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(uncertainLocationAlgorithmEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(false);
 
@@ -1246,19 +1254,21 @@
 
         // Make the geolocation algorithm uncertain.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneChangedAndReset(lastTelephonySuggestion)
                     .verifyTelephonyFallbackIsEnabled(true);
         }
 
         // Make the geolocation algorithm certain, disabling telephony fallback.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent =
                     createCertainLocationAlgorithmEvent("Europe/Lisbon");
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
                     .verifyTelephonyFallbackIsEnabled(false);
 
@@ -1267,9 +1277,10 @@
         // Demonstrate what happens when geolocation is uncertain when telephony fallback is
         // enabled.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(false)
                     .simulateEnableTelephonyFallback()
@@ -1279,6 +1290,132 @@
     }
 
     @Test
+    public void testTelephonyFallback_locationAlgorithmEventSuggestsFallback() {
+        ConfigurationInternal config = new ConfigurationInternal.Builder(
+                CONFIG_AUTO_ENABLED_GEO_ENABLED)
+                .setTelephonyFallbackSupported(true)
+                .build();
+
+        Script script = new Script()
+                .initializeClock(ARBITRARY_ELAPSED_REALTIME_MILLIS)
+                .initializeTimeZoneSetting(ARBITRARY_TIME_ZONE_ID, TIME_ZONE_CONFIDENCE_LOW)
+                .simulateConfigurationInternalChange(config)
+                .resetConfigurationTracking();
+
+        // Confirm initial state is as expected.
+        script.verifyTelephonyFallbackIsEnabled(true)
+                .verifyTimeZoneNotChanged();
+
+        // Although geolocation detection is enabled, telephony fallback should be used initially
+        // and until a suitable "certain" geolocation suggestion is received.
+        {
+            TelephonyTimeZoneSuggestion telephonySuggestion = createTelephonySuggestion(
+                    SLOT_INDEX1, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
+                    "Europe/Paris");
+            script.simulateIncrementClock()
+                    .simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
+                    .verifyTimeZoneChangedAndReset(telephonySuggestion)
+                    .verifyTelephonyFallbackIsEnabled(true);
+        }
+
+        // Receiving an "uncertain" geolocation suggestion without a status should have no effect.
+        {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+                    .verifyTimeZoneNotChanged()
+                    .verifyTelephonyFallbackIsEnabled(true);
+        }
+
+        // Receiving a "certain" geolocation suggestion should disable telephony fallback mode.
+        {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent locationAlgorithmEvent =
+                    createCertainLocationAlgorithmEvent("Europe/London");
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+                    .verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
+                    .verifyTelephonyFallbackIsEnabled(false);
+        }
+
+        // Used to record the last telephony suggestion received, which will be used when fallback
+        // takes place.
+        TelephonyTimeZoneSuggestion lastTelephonySuggestion;
+
+        // Telephony suggestions should now be ignored and geolocation detection is "in control".
+        {
+            TelephonyTimeZoneSuggestion telephonySuggestion = createTelephonySuggestion(
+                    SLOT_INDEX1, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, QUALITY_SINGLE_ZONE,
+                    "Europe/Berlin");
+            script.simulateIncrementClock()
+                    .simulateTelephonyTimeZoneSuggestion(telephonySuggestion)
+                    .verifyTimeZoneNotChanged()
+                    .verifyTelephonyFallbackIsEnabled(false);
+            lastTelephonySuggestion = telephonySuggestion;
+        }
+
+        // Geolocation suggestions should continue to be used as normal (previous telephony
+        // suggestions are not used, even when the geolocation suggestion is uncertain).
+        {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent certainLocationAlgorithmEvent =
+                    createCertainLocationAlgorithmEvent("Europe/Rome");
+            script.simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent)
+                    .verifyTimeZoneChangedAndReset(certainLocationAlgorithmEvent)
+                    .verifyTelephonyFallbackIsEnabled(false);
+
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent uncertainLocationAlgorithmEvent =
+                    createUncertainLocationAlgorithmEvent();
+            script.simulateLocationAlgorithmEvent(uncertainLocationAlgorithmEvent)
+                    .verifyTimeZoneNotChanged()
+                    .verifyTelephonyFallbackIsEnabled(false);
+
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent certainLocationAlgorithmEvent2 =
+                    createCertainLocationAlgorithmEvent("Europe/Rome");
+            script.simulateLocationAlgorithmEvent(certainLocationAlgorithmEvent2)
+                    // No change needed, device will already be set to Europe/Rome.
+                    .verifyTimeZoneNotChanged()
+                    .verifyTelephonyFallbackIsEnabled(false);
+        }
+
+        // Enable telephony fallback via a LocationAlgorithmEvent containing an "uncertain"
+        // suggestion.
+        {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            TimeZoneProviderStatus primaryProviderReportedStatus =
+                    new TimeZoneProviderStatus.Builder()
+                            .setLocationDetectionDependencyStatus(
+                                    DEPENDENCY_STATUS_BLOCKED_BY_SETTINGS)
+                            .setConnectivityDependencyStatus(DEPENDENCY_STATUS_UNKNOWN)
+                            .setTimeZoneResolutionOperationStatus(OPERATION_STATUS_UNKNOWN)
+                            .build();
+            LocationAlgorithmEvent uncertainEventBlockedBySettings =
+                    createUncertainLocationAlgorithmEvent(primaryProviderReportedStatus);
+            script.simulateLocationAlgorithmEvent(uncertainEventBlockedBySettings)
+                    .verifyTimeZoneChangedAndReset(lastTelephonySuggestion)
+                    .verifyTelephonyFallbackIsEnabled(true);
+        }
+
+        // Make the geolocation algorithm certain, disabling telephony fallback.
+        {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
+            LocationAlgorithmEvent locationAlgorithmEvent =
+                    createCertainLocationAlgorithmEvent("Europe/Lisbon");
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+                    .verifyTimeZoneChangedAndReset(locationAlgorithmEvent)
+                    .verifyTelephonyFallbackIsEnabled(false);
+        }
+    }
+
+    @Test
     public void testTelephonyFallback_noTelephonySuggestionToFallBackTo() {
         ConfigurationInternal config = new ConfigurationInternal.Builder(
                 CONFIG_AUTO_ENABLED_GEO_ENABLED)
@@ -1297,9 +1434,10 @@
 
         // Receiving an "uncertain" geolocation suggestion should have no effect.
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(true);
         }
@@ -1307,9 +1445,10 @@
         // Make an uncertain geolocation suggestion, there is no telephony suggestion to fall back
         // to
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent locationAlgorithmEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(locationAlgorithmEvent)
+            script.simulateLocationAlgorithmEvent(locationAlgorithmEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(true);
         }
@@ -1319,16 +1458,18 @@
         // Geolocation suggestions should continue to be used as normal (previous telephony
         // suggestions are not used, even when the geolocation suggestion is uncertain).
         {
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent certainEvent =
                     createCertainLocationAlgorithmEvent("Europe/Rome");
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(certainEvent)
+            script.simulateLocationAlgorithmEvent(certainEvent)
                     .verifyTimeZoneChangedAndReset(certainEvent)
                     .verifyTelephonyFallbackIsEnabled(false);
 
+            // Increment the clock before creating the event: the clock's value is used by the event
+            script.simulateIncrementClock();
             LocationAlgorithmEvent uncertainEvent = createUncertainLocationAlgorithmEvent();
-            script.simulateIncrementClock()
-                    .simulateLocationAlgorithmEvent(uncertainEvent)
+            script.simulateLocationAlgorithmEvent(uncertainEvent)
                     .verifyTimeZoneNotChanged()
                     .verifyTelephonyFallbackIsEnabled(false);
 
@@ -1549,9 +1690,16 @@
     }
 
     private LocationAlgorithmEvent createUncertainLocationAlgorithmEvent() {
+        TimeZoneProviderStatus primaryProviderReportedStatus = null;
+        return createUncertainLocationAlgorithmEvent(primaryProviderReportedStatus);
+    }
+
+    private LocationAlgorithmEvent createUncertainLocationAlgorithmEvent(
+            TimeZoneProviderStatus primaryProviderReportedStatus) {
         GeolocationTimeZoneSuggestion suggestion = createUncertainGeolocationSuggestion();
         LocationTimeZoneAlgorithmStatus algorithmStatus = new LocationTimeZoneAlgorithmStatus(
-                DETECTION_ALGORITHM_STATUS_RUNNING, PROVIDER_STATUS_IS_UNCERTAIN, null,
+                DETECTION_ALGORITHM_STATUS_RUNNING,
+                PROVIDER_STATUS_IS_UNCERTAIN, primaryProviderReportedStatus,
                 PROVIDER_STATUS_NOT_PRESENT, null);
         LocationAlgorithmEvent event = new LocationAlgorithmEvent(algorithmStatus, suggestion);
         event.addDebugInfo("Test uncertain event");
@@ -1744,11 +1892,12 @@
         }
 
         /**
-         * Simulates the time zone detection strategty receiving a signal that allows it to do
+         * Simulates the time zone detection strategy receiving a signal that allows it to do
          * telephony fallback.
          */
         Script simulateEnableTelephonyFallback() {
-            mTimeZoneDetectorStrategy.enableTelephonyTimeZoneFallback();
+            mTimeZoneDetectorStrategy.enableTelephonyTimeZoneFallback(
+                    "simulateEnableTelephonyFallback()");
             return this;
         }
 
diff --git a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
index aafc16d..febbffe 100644
--- a/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/EventLoggerTest.java
@@ -71,9 +71,10 @@
         }
 
         @Test
-        public void testThatPrintWriterProducesEmptyListFromEmptyLog() {
+        public void testThatPrintWriterProducesOnlyTitleFromEmptyLog() {
             mEventLogger.dump(mTestPrintWriter);
-            assertThat(mTestStringWriter.toString()).isEmpty();
+            assertThat(mTestStringWriter.toString())
+                    .isEqualTo(mEventLogger.getDumpTitle() + "\n");
         }
     }
 
@@ -87,27 +88,27 @@
                         // insertion order, max size is 3
                         new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_2 },
                         // expected events
-                        new EventLogger.Event[] { TEST_EVENT_2, TEST_EVENT_1 }
+                        new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_2 }
                     },
                     {
                         // insertion order, max size is 3
                         new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_3, TEST_EVENT_2 },
                         // expected events
-                        new EventLogger.Event[] { TEST_EVENT_2, TEST_EVENT_3, TEST_EVENT_1 }
+                        new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_3, TEST_EVENT_2 }
                     },
                     {
                         // insertion order, max size is 3
                         new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_2, TEST_EVENT_3,
                             TEST_EVENT_4 },
                         // expected events
-                        new EventLogger.Event[] { TEST_EVENT_4, TEST_EVENT_3, TEST_EVENT_2 }
+                        new EventLogger.Event[] { TEST_EVENT_2, TEST_EVENT_3, TEST_EVENT_4 }
                     },
                     {
                         // insertion order, max size is 3
                         new EventLogger.Event[] { TEST_EVENT_1, TEST_EVENT_2, TEST_EVENT_3,
                             TEST_EVENT_4, TEST_EVENT_5 },
                         // expected events
-                        new EventLogger.Event[] { TEST_EVENT_5, TEST_EVENT_4, TEST_EVENT_3 }
+                        new EventLogger.Event[] { TEST_EVENT_3, TEST_EVENT_4, TEST_EVENT_5 }
                     }
             });
         }
diff --git a/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/Android.bp b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/Android.bp
new file mode 100644
index 0000000..f376b6f
--- /dev/null
+++ b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/Android.bp
@@ -0,0 +1,37 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+android_test_helper_app {
+    name: "MediaButtonReceiverHolderTestHelperApp",
+
+    sdk_version: "current",
+
+    srcs: ["**/*.java"],
+
+    dex_preopt: {
+        enabled: false,
+    },
+    optimize: {
+        enabled: false,
+    },
+}
diff --git a/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/AndroidManifest.xml b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/AndroidManifest.xml
new file mode 100644
index 0000000..3ba3dc2
--- /dev/null
+++ b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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.servicestests.apps.mediabuttonreceiverholdertesthelperapp">
+
+    <application>
+        <receiver
+            android:name=".FakeMediaButtonBroadcastReceiver"
+            android:enabled="true"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MEDIA_BUTTON" />
+            </intent-filter>
+        </receiver>
+    </application>
+
+</manifest>
diff --git a/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/OWNERS b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/OWNERS
new file mode 100644
index 0000000..55ffde2
--- /dev/null
+++ b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 137631
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
\ No newline at end of file
diff --git a/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/src/FakeMediaButtonBroadcastReceiver.java b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/src/FakeMediaButtonBroadcastReceiver.java
new file mode 100644
index 0000000..6fdd8be
--- /dev/null
+++ b/services/tests/servicestests/test-apps/MediaButtonReceiverHolderTestHelperApp/src/FakeMediaButtonBroadcastReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.servicestests.apps.mediabuttonreceiverholdertesthelperapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+public class FakeMediaButtonBroadcastReceiver extends BroadcastReceiver {
+
+    private static final String TAG = "FakeMediaButtonBroadcastReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Log.v(TAG, "onReceive not expected");
+    }
+}
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp4.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp4.xml
index 4dcb442..5451735 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp4.xml
+++ b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp4.xml
@@ -32,7 +32,7 @@
 
 	    <activity android:name="com.android.servicestests.apps.packageparserapp.MyActivity"
 	              android:exported="true"
-	              android:targetDisplayCategory="automotive">
+	              android:requiredDisplayCategory="automotive">
 	        <property android:name="android.cts.PROPERTY_ACTIVITY" android:value="@integer/integer_property" />
 	        <property android:name="android.cts.PROPERTY_COMPONENT" android:value="@integer/integer_property" />
 	        <property android:name="android.cts.PROPERTY_STRING" android:value="koala activity" />
diff --git a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp6.xml b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp6.xml
index 8e694e1..601479d 100644
--- a/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp6.xml
+++ b/services/tests/servicestests/test-apps/PackageParserApp/AndroidManifestApp6.xml
@@ -21,7 +21,7 @@
     <application>
         <activity android:name="com.android.servicestests.apps.packageparserapp.MyActivity"
                   android:exported="true"
-                  android:targetDisplayCategory="$automotive">
+                  android:requiredDisplayCategory="$automotive">
         </activity>
     </application>
 </manifest>
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
index af10b9d..d758e71 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryJobServiceTest.java
@@ -52,9 +52,9 @@
 @RunWith(AndroidTestingRunner.class)
 public class NotificationHistoryJobServiceTest extends UiServiceTestCase {
     private NotificationHistoryJobService mJobService;
-    private JobParameters mJobParams = new JobParameters(null,
-            NotificationHistoryJobService.BASE_JOB_ID, null, null, null,
-            0, false, false, null, null, null);
+
+    @Mock
+    private JobParameters mJobParams;
 
     @Captor
     ArgumentCaptor<JobInfo> mJobInfoCaptor;
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index afec085..d54d1fe 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -1101,10 +1101,6 @@
                 new NotificationChannel("id", "name", IMPORTANCE_HIGH);
         mBinderService.updateNotificationChannelForPackage(PKG, mUid, updatedChannel);
 
-        // pretend only this following part is called by the app (system permissions are required to
-        // update the notification channel on behalf of the user above)
-        mService.isSystemUid = false;
-
         // Recreating with a lower importance leaves channel unchanged.
         final NotificationChannel dupeChannel =
                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW);
@@ -1130,46 +1126,6 @@
     }
 
     @Test
-    public void testCreateNotificationChannels_fromAppCannotSetFields() throws Exception {
-        // Confirm that when createNotificationChannels is called from the relevant app and not
-        // system, then it cannot set fields that can't be set by apps
-        mService.isSystemUid = false;
-
-        final NotificationChannel channel =
-                new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
-        channel.setBypassDnd(true);
-        channel.setAllowBubbles(true);
-
-        mBinderService.createNotificationChannels(PKG,
-                new ParceledListSlice(Arrays.asList(channel)));
-
-        final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
-        assertFalse(createdChannel.canBypassDnd());
-        assertFalse(createdChannel.canBubble());
-    }
-
-    @Test
-    public void testCreateNotificationChannels_fromSystemCanSetFields() throws Exception {
-        // Confirm that when createNotificationChannels is called from system,
-        // then it can set fields that can't be set by apps
-        mService.isSystemUid = true;
-
-        final NotificationChannel channel =
-                new NotificationChannel("id", "name", IMPORTANCE_DEFAULT);
-        channel.setBypassDnd(true);
-        channel.setAllowBubbles(true);
-
-        mBinderService.createNotificationChannels(PKG,
-                new ParceledListSlice(Arrays.asList(channel)));
-
-        final NotificationChannel createdChannel =
-                mBinderService.getNotificationChannel(PKG, mContext.getUserId(), PKG, "id");
-        assertTrue(createdChannel.canBypassDnd());
-        assertTrue(createdChannel.canBubble());
-    }
-
-    @Test
     public void testBlockedNotifications_suspended() throws Exception {
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
 
@@ -3132,8 +3088,6 @@
 
     @Test
     public void testDeleteChannelGroupChecksForFgses() throws Exception {
-        // the setup for this test requires it to seem like it's coming from the app
-        mService.isSystemUid = false;
         when(mCompanionMgr.getAssociations(PKG, UserHandle.getUserId(mUid)))
                 .thenReturn(singletonList(mock(AssociationInfo.class)));
         CountDownLatch latch = new CountDownLatch(2);
@@ -3146,7 +3100,7 @@
             ParceledListSlice<NotificationChannel> pls =
                     new ParceledListSlice(ImmutableList.of(notificationChannel));
             try {
-                mBinderService.createNotificationChannels(PKG, pls);
+                mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls);
             } catch (RemoteException e) {
                 throw new RuntimeException(e);
             }
@@ -3165,10 +3119,8 @@
                 ParceledListSlice<NotificationChannel> pls =
                         new ParceledListSlice(ImmutableList.of(notificationChannel));
                 try {
-                    // Because existing channels won't have their groups overwritten when the call
-                    // is from the app, this call won't take the channel out of the group
-                    mBinderService.createNotificationChannels(PKG, pls);
-                    mBinderService.deleteNotificationChannelGroup(PKG, "group");
+                mBinderService.createNotificationChannelsForPackage(PKG, mUid, pls);
+                mBinderService.deleteNotificationChannelGroup(PKG, "group");
                 } catch (RemoteException e) {
                     throw new RuntimeException(e);
                 }
@@ -8729,7 +8681,7 @@
         assertEquals("friend", friendChannel.getConversationId());
         assertEquals(null, original.getConversationId());
         assertEquals(original.canShowBadge(), friendChannel.canShowBadge());
-        assertEquals(original.canBubble(), friendChannel.canBubble()); // called by system
+        assertFalse(friendChannel.canBubble()); // can't be modified by app
         assertFalse(original.getId().equals(friendChannel.getId()));
         assertNotNull(friendChannel.getId());
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ReviewNotificationPermissionsJobServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ReviewNotificationPermissionsJobServiceTest.java
index 3a6c0eb..a83eb00 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ReviewNotificationPermissionsJobServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ReviewNotificationPermissionsJobServiceTest.java
@@ -44,9 +44,9 @@
 @RunWith(AndroidTestingRunner.class)
 public class ReviewNotificationPermissionsJobServiceTest extends UiServiceTestCase {
     private ReviewNotificationPermissionsJobService mJobService;
-    private JobParameters mJobParams = new JobParameters(null,
-            ReviewNotificationPermissionsJobService.JOB_ID, null, null, null,
-            0, false, false, null, null, null);
+
+    @Mock
+    private JobParameters mJobParams;
 
     @Captor
     ArgumentCaptor<JobInfo> mJobInfoCaptor;
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 1ab7d7e..a410eed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1206,6 +1206,25 @@
         }
     }
 
+    @Test
+    public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
+        final Task task = new TaskBuilder(mSupervisor).build();
+        final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
+        final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
+        final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
+        final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
+        resultToActivity.setState(RESUMED, "test");
+        targetActivity.setState(RESUMED, "test");
+        targetActivity.resultTo = resultToActivity;
+
+        clearInvocations(mAtm.getLifecycleManager());
+        targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
+        waitUntilHandlersIdle();
+
+        verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
+                anyBoolean());
+    }
+
     /**
      * Verify that complete finish request for non-finishing activity is invalid.
      */
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
index 1575336..8a15c30 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartInterceptorTest.java
@@ -28,6 +28,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
@@ -275,11 +276,60 @@
         // THEN calling intercept returns true
         mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
 
-        // THEN the returned intent is the quiet mode intent
+        // THEN the returned intent is the confirm credentials intent
         assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
     }
 
     @Test
+    public void testLockedManagedProfileShowWhenLocked() {
+        Intent originalIntent = new Intent();
+        // GIVEN that the user is locked but its storage is unlocked and the activity has
+        // showWhenLocked flag
+        when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
+        when(mUserManager.isUserUnlocked(eq(TEST_USER_ID))).thenReturn(true);
+        mAInfo.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+
+        // THEN calling intercept returns true
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+
+        // THEN the returned intent is original intent
+        assertSame(originalIntent, mInterceptor.mIntent);
+    }
+
+    @Test
+    public void testLockedManagedProfileShowWhenLockedEncryptedStorage() {
+        // GIVEN that the user storage is locked, activity has showWhenLocked flag but no
+        // directBootAware flag
+        when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
+        when(mUserManager.isUserUnlocked(eq(TEST_USER_ID))).thenReturn(false);
+        mAInfo.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+        mAInfo.directBootAware = false;
+
+        // THEN calling intercept returns true
+        mInterceptor.intercept(null, null, mAInfo, null, null, null, 0, 0, null);
+
+        // THEN the returned intent is the confirm credentials intent
+        assertTrue(CONFIRM_CREDENTIALS_INTENT.filterEquals(mInterceptor.mIntent));
+    }
+
+    @Test
+    public void testLockedManagedProfileShowWhenLockedEncryptedStorageDirectBootAware() {
+        Intent originalIntent = new Intent();
+        // GIVEN that the user storage is locked, activity has showWhenLocked flag and
+        // directBootAware flag
+        when(mAmInternal.shouldConfirmCredentials(TEST_USER_ID)).thenReturn(true);
+        when(mUserManager.isUserUnlocked(eq(TEST_USER_ID))).thenReturn(false);
+        mAInfo.flags |= ActivityInfo.FLAG_SHOW_WHEN_LOCKED;
+        mAInfo.directBootAware = true;
+
+        // THEN calling intercept returns true
+        mInterceptor.intercept(originalIntent, null, mAInfo, null, null, null, 0, 0, null);
+
+        // THEN the returned intent is original intent
+        assertSame(originalIntent, mInterceptor.mIntent);
+    }
+
+    @Test
     public void testHarmfulAppWarning() throws RemoteException {
         // GIVEN the package we're about to launch has a harmful app warning set
         when(mPackageManager.getHarmfulAppWarning(TEST_PACKAGE_NAME, TEST_USER_ID))
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index f3f56e0..3bce860 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -42,7 +42,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.WindowManager;
 import android.window.BackAnimationAdapter;
-import android.window.BackEvent;
+import android.window.BackMotionEvent;
 import android.window.BackNavigationInfo;
 import android.window.IOnBackInvokedCallback;
 import android.window.OnBackInvokedCallback;
@@ -114,6 +114,20 @@
     }
 
     @Test
+    public void backTypeBackToHomeDifferentUser() {
+        Task taskA = createTask(mDefaultDisplay);
+        ActivityRecord recordA = createActivityRecord(taskA);
+        Mockito.doNothing().when(recordA).reparentSurfaceControl(any(), any());
+        doReturn(false).when(taskA).showToCurrentUser();
+
+        withSystemCallback(createTopTaskWithActivity());
+        BackNavigationInfo backNavigationInfo = startBackNavigation();
+        assertWithMessage("BackNavigationInfo").that(backNavigationInfo).isNotNull();
+        assertThat(typeToString(backNavigationInfo.getType()))
+                .isEqualTo(typeToString(BackNavigationInfo.TYPE_RETURN_TO_HOME));
+    }
+
+    @Test
     public void backTypeCrossActivityWhenBackToPreviousActivity() {
         CrossActivityTestCase testCase = createTopTaskWithTwoActivities();
         IOnBackInvokedCallback callback = withSystemCallback(testCase.task);
@@ -136,6 +150,7 @@
         WindowState window = createWindow(null, WindowManager.LayoutParams.TYPE_WALLPAPER,
                 "Wallpaper");
         addToWindowMap(window, true);
+        makeWindowVisibleAndDrawn(window);
 
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         window.setOnBackInvokedCallbackInfo(
@@ -222,6 +237,20 @@
                 1, appLatch.getCount());
     }
 
+    @Test
+    public void backInfoWindowWithoutDrawn() {
+        WindowState window = createWindow(null, WindowManager.LayoutParams.TYPE_APPLICATION,
+                "TestWindow");
+        addToWindowMap(window, true);
+
+        IOnBackInvokedCallback callback = createOnBackInvokedCallback();
+        window.setOnBackInvokedCallbackInfo(
+                new OnBackInvokedCallbackInfo(callback, OnBackInvokedDispatcher.PRIORITY_DEFAULT));
+
+        BackNavigationInfo backNavigationInfo = startBackNavigation();
+        assertThat(backNavigationInfo).isNull();
+    }
+
     private IOnBackInvokedCallback withSystemCallback(Task task) {
         IOnBackInvokedCallback callback = createOnBackInvokedCallback();
         task.getTopMostActivity().getTopChild().setOnBackInvokedCallbackInfo(
@@ -245,11 +274,11 @@
     private IOnBackInvokedCallback createOnBackInvokedCallback() {
         return new IOnBackInvokedCallback.Stub() {
             @Override
-            public void onBackStarted(BackEvent backEvent) {
+            public void onBackStarted(BackMotionEvent backMotionEvent) {
             }
 
             @Override
-            public void onBackProgressed(BackEvent backEvent) {
+            public void onBackProgressed(BackMotionEvent backMotionEvent) {
             }
 
             @Override
@@ -295,6 +324,7 @@
         Mockito.doNothing().when(task).reparentSurfaceControl(any(), any());
         mAtm.setFocusedTask(task.mTaskId, record);
         addToWindowMap(window, true);
+        makeWindowVisibleAndDrawn(window);
         return task;
     }
 
@@ -319,6 +349,8 @@
         addToWindowMap(window1, true);
         addToWindowMap(window2, true);
 
+        makeWindowVisibleAndDrawn(window2);
+
         CrossActivityTestCase testCase = new CrossActivityTestCase();
         testCase.task = task;
         testCase.recordBack = record1;
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 70b68c7..6733470 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -133,8 +133,8 @@
         final RoundedCorners roundedCorners = mHasRoundedCorners
                 ? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
                 : RoundedCorners.NO_ROUNDED_CORNERS;
-        return new DisplayFrames(insetsState, info,
-                info.displayCutout, roundedCorners, new PrivacyIndicatorBounds());
+        return new DisplayFrames(insetsState, info, info.displayCutout, roundedCorners,
+                new PrivacyIndicatorBounds(), info.displayShape);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index d99946f..10f2270 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -58,6 +58,7 @@
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.InsetsSource;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
@@ -321,7 +322,8 @@
         final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
         mImeWindow.mAboveInsetsState.set(state);
         mDisplayContent.mDisplayFrames = new DisplayFrames(
-                state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+                state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+                DisplayShape.NONE);
 
         mDisplayContent.setInputMethodWindowLocked(mImeWindow);
         mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
index c898119..cdb2642 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsStateControllerTest.java
@@ -443,6 +443,44 @@
     }
 
     @Test
+    public void testUpdateAboveInsetsState_imeTargetOnScreenBehavior() {
+        final WindowToken imeToken = createTestWindowToken(TYPE_INPUT_METHOD, mDisplayContent);
+        final WindowState ime = createWindow(null,  TYPE_INPUT_METHOD, imeToken, "ime");
+        final WindowState app = createTestWindow("app");
+
+        getController().getSourceProvider(ITYPE_IME).setWindowContainer(ime, null, null);
+        ime.getControllableInsetProvider().setServerVisible(true);
+
+        app.mActivityRecord.setVisibility(true);
+        mDisplayContent.setImeLayeringTarget(app);
+        mDisplayContent.updateImeInputAndControlTarget(app);
+
+        app.setRequestedVisibleTypes(ime(), ime());
+        getController().onInsetsModified(app);
+        assertTrue(ime.getControllableInsetProvider().getSource().isVisible());
+
+        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+        verify(app, atLeastOnce()).notifyInsetsChanged();
+
+        // Expect the app will still get IME insets even when the app was invisible.
+        // (i.e. app invisible after locking the device)
+        app.mActivityRecord.setVisible(false);
+        app.setHasSurface(false);
+        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+        verify(app, atLeastOnce()).notifyInsetsChanged();
+
+        // Expect the app will get IME insets when the app is requesting visible.
+        // (i.e. app is going to visible when unlocking the device)
+        app.mActivityRecord.setVisibility(true);
+        assertTrue(app.isVisibleRequested());
+        getController().updateAboveInsetsState(true /* notifyInsetsChange */);
+        assertNotNull(app.getInsetsState().peekSource(ITYPE_IME));
+        verify(app, atLeastOnce()).notifyInsetsChanged();
+    }
+
+    @Test
     public void testDispatchGlobalInsets() {
         final WindowState navBar = createWindow(null, TYPE_APPLICATION, "navBar");
         getController().getSourceProvider(ITYPE_NAVIGATION_BAR).setWindowContainer(navBar, null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index c548dc3..eb26415 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -772,6 +772,7 @@
             // Simulating now win1 is being covered by the lockscreen which has no surface,
             // and then launching an activity win2 with the remote animation
             win1.mHasSurface = false;
+            win1.mActivityRecord.setVisibility(false);
             mDisplayContent.mOpeningApps.add(win2.mActivityRecord);
             final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
                     win2.mActivityRecord, new Point(50, 100), null,
diff --git a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
index d3aa073..df7b3cd 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SyncEngineTests.java
@@ -74,15 +74,15 @@
 
         int id = startSyncSet(bse, listener);
         bse.addToSyncSet(id, mockWC);
-        // Make sure a traversal is requested
-        verify(mWm.mWindowPlacerLocked, times(1)).requestTraversal();
+        // The traversal is not requested because ready is not set.
+        verify(mWm.mWindowPlacerLocked, times(0)).requestTraversal();
 
         bse.onSurfacePlacement();
         verify(listener, times(0)).onTransactionReady(anyInt(), any());
 
         bse.setReady(id);
         // Make sure a traversal is requested
-        verify(mWm.mWindowPlacerLocked, times(2)).requestTraversal();
+        verify(mWm.mWindowPlacerLocked).requestTraversal();
         bse.onSurfacePlacement();
         verify(listener, times(1)).onTransactionReady(eq(id), notNull());
 
@@ -103,14 +103,14 @@
         int id = startSyncSet(bse, listener);
         bse.addToSyncSet(id, mockWC);
         bse.setReady(id);
-        // Make sure traversals requested (one for add and another for setReady)
-        verify(mWm.mWindowPlacerLocked, times(2)).requestTraversal();
+        // Make sure traversals requested.
+        verify(mWm.mWindowPlacerLocked).requestTraversal();
         bse.onSurfacePlacement();
         verify(listener, times(0)).onTransactionReady(anyInt(), any());
 
         mockWC.onSyncFinishedDrawing();
-        // Make sure a (third) traversal is requested.
-        verify(mWm.mWindowPlacerLocked, times(3)).requestTraversal();
+        // Make sure the second traversal is requested.
+        verify(mWm.mWindowPlacerLocked, times(2)).requestTraversal();
         bse.onSurfacePlacement();
         verify(listener, times(1)).onTransactionReady(eq(id), notNull());
     }
@@ -127,8 +127,8 @@
         int id = startSyncSet(bse, listener);
         bse.addToSyncSet(id, mockWC);
         bse.setReady(id);
-        // Make sure traversals requested (one for add and another for setReady)
-        verify(mWm.mWindowPlacerLocked, times(2)).requestTraversal();
+        // Make sure traversals requested.
+        verify(mWm.mWindowPlacerLocked).requestTraversal();
         bse.onSurfacePlacement();
         verify(listener, times(0)).onTransactionReady(anyInt(), any());
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 4e796c5..8fda191 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -24,7 +24,6 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.os.Process.FIRST_APPLICATION_UID;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -33,9 +32,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
 import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
@@ -475,23 +472,6 @@
         doReturn(true).when(taskFragment).smallerThanMinDimension(any());
         assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
                 taskFragment.isAllowedToEmbedActivity(activity));
-
-        // Not allow to start activity across TaskFragments for result.
-        final TaskFragment newTaskFragment = new TaskFragmentBuilder(mAtm)
-                .setParentTask(taskFragment.getTask())
-                .build();
-        final ActivityRecord newActivity = new ActivityBuilder(mAtm)
-                .setUid(FIRST_APPLICATION_UID)
-                .build();
-        doReturn(true).when(newTaskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
-        doReturn(false).when(newTaskFragment).smallerThanMinDimension(any());
-        newActivity.resultTo = activity;
-        assertEquals(EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
-                newTaskFragment.isAllowedToEmbedActivity(newActivity));
-
-        // Allow embedding if the resultTo activity is finishing.
-        activity.finishing = true;
-        assertEquals(EMBEDDING_ALLOWED, newTaskFragment.isAllowedToEmbedActivity(newActivity));
     }
 
     @Test
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 a4cc09a..e7813ff 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -893,11 +893,10 @@
     }
 
     @Test
-    public void testLaunchesPortraitUnresizableOnFreeformLandscapeDisplay() {
+    public void testLaunchesPortraitUnresizableOnFreeformDisplayWithFreeformSizeCompat() {
         mAtm.mDevEnableNonResizableMultiWindow = true;
         final TestDisplayContent freeformDisplay = createNewDisplayContent(
                 WINDOWING_MODE_FREEFORM);
-        assertTrue(freeformDisplay.getBounds().width() > freeformDisplay.getBounds().height());
         final ActivityOptions options = ActivityOptions.makeBasic();
         mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
         mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
@@ -905,42 +904,12 @@
         assertEquals(RESULT_CONTINUE,
                 new CalculateRequestBuilder().setOptions(options).calculate());
 
-        assertEquals(WINDOWING_MODE_UNDEFINED, mResult.mWindowingMode);
-    }
-
-    @Test
-    public void testLaunchesLandscapeUnresizableOnFreeformLandscapeDisplay() {
-        mAtm.mDevEnableNonResizableMultiWindow = true;
-        final TestDisplayContent freeformDisplay = createNewDisplayContent(
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
                 WINDOWING_MODE_FREEFORM);
-        assertTrue(freeformDisplay.getBounds().width() > freeformDisplay.getBounds().height());
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
-        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
-        mActivity.info.screenOrientation = SCREEN_ORIENTATION_LANDSCAPE;
-        assertEquals(RESULT_CONTINUE,
-                new CalculateRequestBuilder().setOptions(options).calculate());
-
-        assertEquals(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode);
     }
 
     @Test
-    public void testLaunchesUndefinedUnresizableOnFreeformLandscapeDisplay() {
-        mAtm.mDevEnableNonResizableMultiWindow = true;
-        final TestDisplayContent freeformDisplay = createNewDisplayContent(
-                WINDOWING_MODE_FREEFORM);
-        assertTrue(freeformDisplay.getBounds().width() > freeformDisplay.getBounds().height());
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        mCurrent.mPreferredTaskDisplayArea = freeformDisplay.getDefaultTaskDisplayArea();
-        mActivity.info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
-        assertEquals(RESULT_CONTINUE,
-                new CalculateRequestBuilder().setOptions(options).calculate());
-
-        assertEquals(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode);
-    }
-
-    @Test
-    public void testForceMaximizingAppsOnNonFreeformDisplay() {
+    public void testSkipsForceMaximizingAppsOnNonFreeformDisplay() {
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WINDOWING_MODE_FREEFORM);
         options.setLaunchBounds(new Rect(0, 0, 200, 100));
@@ -954,9 +923,8 @@
         assertEquals(RESULT_CONTINUE,
                 new CalculateRequestBuilder().setOptions(options).calculate());
 
-        // Non-resizable apps must be launched in fullscreen in a fullscreen display regardless of
-        // other properties.
-        assertEquals(WINDOWING_MODE_FULLSCREEN, mResult.mWindowingMode);
+        assertEquivalentWindowingMode(WINDOWING_MODE_FREEFORM, mResult.mWindowingMode,
+                WINDOWING_MODE_FULLSCREEN);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
index 35b9710..59a31b1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TransitionTests.java
@@ -479,6 +479,8 @@
         wallpaperWindow.mHasSurface = true;
         doReturn(true).when(mDisplayContent).isAttached();
         transition.collect(mDisplayContent);
+        assertFalse("The change of non-interesting window container should be skipped",
+                transition.mChanges.containsKey(mDisplayContent.getParent()));
         mDisplayContent.getWindowConfiguration().setRotation(
                 (mDisplayContent.getWindowConfiguration().getRotation() + 1) % 4);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index 9090c55..94b5b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -54,6 +54,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.DisplayShape;
 import android.view.Gravity;
 import android.view.InsetsState;
 import android.view.PrivacyIndicatorBounds;
@@ -165,7 +166,8 @@
         final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
         final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
         final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(),
-                info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+                info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+                DisplayShape.NONE);
         wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
 
         // Check that the wallpaper has the same frame in landscape than in portrait
@@ -369,7 +371,7 @@
         final SurfaceControl.Transaction t = mock(SurfaceControl.Transaction.class);
         token.finishSync(t, false /* cancel */);
         transit.onTransactionReady(transit.getSyncId(), t);
-        dc.mTransitionController.finishTransition(transit);
+        dc.mTransitionController.finishTransition(transit.getToken());
         assertFalse(wallpaperWindow.isVisible());
         assertFalse(token.isVisible());
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
index 4429aef..871030f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowManagerServiceTests.java
@@ -16,12 +16,16 @@
 
 package com.android.server.wm;
 
+import static android.Manifest.permission.ADD_TRUSTED_DISPLAY;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_FOCUS;
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED;
 import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.Display.FLAG_OWN_FOCUS;
 import static android.view.WindowManager.LayoutParams.INVALID_WINDOW_TYPE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
@@ -81,6 +85,9 @@
 import android.window.WindowContainerToken;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.AdoptShellPermissionsRule;
 
 import org.junit.Rule;
 import org.junit.Test;
@@ -99,6 +106,11 @@
     @Rule
     public ExpectedException mExpectedException = ExpectedException.none();
 
+    @Rule
+    public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule(
+            InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+            ADD_TRUSTED_DISPLAY);
+
     @Test
     public void testAddWindowToken() {
         IBinder token = mock(IBinder.class);
@@ -396,9 +408,15 @@
     @Test
     public void testSetInTouchMode_multiDisplay_globalTouchModeUpdate() {
         // Create one extra display
-        final VirtualDisplay virtualDisplay = createVirtualDisplay();
+        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
+        final VirtualDisplay virtualDisplayOwnTouchMode =
+                createVirtualDisplay(/* ownFocus= */ true);
         final int numberOfDisplays = mWm.mRoot.mChildren.size();
-        assertThat(numberOfDisplays).isAtLeast(2);
+        assertThat(numberOfDisplays).isAtLeast(3);
+        final int numberOfGlobalTouchModeDisplays = (int) mWm.mRoot.mChildren.stream()
+                        .filter(d -> (d.getDisplay().getFlags() & FLAG_OWN_FOCUS) == 0)
+                        .count();
+        assertThat(numberOfGlobalTouchModeDisplays).isAtLeast(2);
 
         // Enable global touch mode (config_perDisplayFocusEnabled set to false)
         Resources mockResources = mock(Resources.class);
@@ -417,15 +435,15 @@
 
         mWm.setInTouchMode(!currentTouchMode, DEFAULT_DISPLAY);
 
-        verify(mWm.mInputManager, times(numberOfDisplays)).setInTouchMode(
+        verify(mWm.mInputManager, times(numberOfGlobalTouchModeDisplays)).setInTouchMode(
                 eq(!currentTouchMode), eq(callingPid), eq(callingUid),
                 /* hasPermission= */ eq(true), /* displayId= */ anyInt());
     }
 
     @Test
-    public void testSetInTouchMode_multiDisplay_singleDisplayTouchModeUpdate() {
+    public void testSetInTouchMode_multiDisplay_perDisplayFocus_singleDisplayTouchModeUpdate() {
         // Create one extra display
-        final VirtualDisplay virtualDisplay = createVirtualDisplay();
+        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ false);
         final int numberOfDisplays = mWm.mRoot.mChildren.size();
         assertThat(numberOfDisplays).isAtLeast(2);
 
@@ -452,14 +470,47 @@
                 virtualDisplay.getDisplay().getDisplayId());
     }
 
-    private VirtualDisplay createVirtualDisplay() {
+    @Test
+    public void testSetInTouchMode_multiDisplay_ownTouchMode_singleDisplayTouchModeUpdate() {
+        // Create one extra display
+        final VirtualDisplay virtualDisplay = createVirtualDisplay(/* ownFocus= */ true);
+        final int numberOfDisplays = mWm.mRoot.mChildren.size();
+        assertThat(numberOfDisplays).isAtLeast(2);
+
+        // Enable global touch mode (config_perDisplayFocusEnabled set to false)
+        Resources mockResources = mock(Resources.class);
+        spyOn(mContext);
+        when(mContext.getResources()).thenReturn(mockResources);
+        doReturn(false).when(mockResources).getBoolean(
+                com.android.internal.R.bool.config_perDisplayFocusEnabled);
+
+        // Get current touch mode state and setup WMS to run setInTouchMode
+        boolean currentTouchMode = mWm.isInTouchMode(DEFAULT_DISPLAY);
+        int callingPid = Binder.getCallingPid();
+        int callingUid = Binder.getCallingUid();
+        doReturn(false).when(mWm).checkCallingPermission(anyString(), anyString(), anyBoolean());
+        when(mWm.mAtmService.instrumentationSourceHasPermission(callingPid,
+                android.Manifest.permission.MODIFY_TOUCH_MODE_STATE)).thenReturn(true);
+
+        mWm.setInTouchMode(!currentTouchMode, virtualDisplay.getDisplay().getDisplayId());
+
+        // Ensure that new display touch mode state has changed.
+        verify(mWm.mInputManager).setInTouchMode(
+                !currentTouchMode, callingPid, callingUid, /* hasPermission= */ true,
+                virtualDisplay.getDisplay().getDisplayId());
+    }
+
+    private VirtualDisplay createVirtualDisplay(boolean ownFocus) {
         // Create virtual display
         Point surfaceSize = new Point(
                 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
                 mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+        int flags = VIRTUAL_DISPLAY_FLAG_PUBLIC;
+        if (ownFocus) {
+            flags |= VIRTUAL_DISPLAY_FLAG_OWN_FOCUS | VIRTUAL_DISPLAY_FLAG_TRUSTED;
+        }
         VirtualDisplay virtualDisplay = mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay",
-                surfaceSize.x, surfaceSize.y,
-                DisplayMetrics.DENSITY_140, new Surface(), VIRTUAL_DISPLAY_FLAG_PUBLIC);
+                surfaceSize.x, surfaceSize.y, DisplayMetrics.DENSITY_140, new Surface(), flags);
         final int displayId = virtualDisplay.getDisplay().getDisplayId();
         mWm.mRoot.onDisplayAdded(displayId);
 
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 1348770..5a261bc65 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1746,7 +1746,7 @@
         }
 
         void startTransition() {
-            mOrganizer.startTransition(mLastTransit, null);
+            mOrganizer.startTransition(mLastTransit.getToken(), null);
         }
 
         void onTransactionReady(SurfaceControl.Transaction t) {
@@ -1759,7 +1759,7 @@
         }
 
         public void finish() {
-            mController.finishTransition(mLastTransit);
+            mController.finishTransition(mLastTransit.getToken());
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/StateMachineTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/StateMachineTest.java
new file mode 100644
index 0000000..e82a7c2
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/StateMachineTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils;
+
+import static com.android.server.wm.utils.StateMachine.isIn;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+/**
+ * Build/Install/Run:
+ *  atest WmTests:StateMachineTest
+ */
+@SmallTest
+@Presubmit
+public class StateMachineTest {
+    static class LoggingHandler implements StateMachine.Handler {
+        final int mState;
+        final StringBuffer mStringBuffer;
+        // True if process #handle
+        final boolean mHandleSelf;
+
+        LoggingHandler(int state, StringBuffer sb, boolean handleSelf) {
+            mHandleSelf = handleSelf;
+            mState = state;
+            mStringBuffer = sb;
+        }
+
+        LoggingHandler(int state, StringBuffer sb) {
+            this(state, sb, true /* handleSelf */);
+        }
+
+        @Override
+        public void enter() {
+            mStringBuffer.append('i');
+            mStringBuffer.append(Integer.toHexString(mState));
+            mStringBuffer.append(';');
+        }
+
+        @Override
+        public void exit() {
+            mStringBuffer.append('o');
+            mStringBuffer.append(Integer.toHexString(mState));
+            mStringBuffer.append(';');
+        }
+
+        @Override
+        public boolean handle(int event, Object param) {
+            if (mHandleSelf) {
+                mStringBuffer.append('h');
+                mStringBuffer.append(Integer.toHexString(mState));
+                mStringBuffer.append(';');
+            }
+            return mHandleSelf;
+        }
+    }
+
+    static class LoggingHandlerTransferInExit extends LoggingHandler {
+        final StateMachine mStateMachine;
+        final int mStateToTransit;
+
+        LoggingHandlerTransferInExit(int state, StringBuffer sb, StateMachine stateMachine,
+                int stateToTransit) {
+            super(state, sb);
+            mStateMachine = stateMachine;
+            mStateToTransit = stateToTransit;
+        }
+
+        @Override
+        public void exit() {
+            super.exit();
+            mStateMachine.transit(mStateToTransit);
+        }
+    }
+
+    @Test
+    public void testStateMachineIsIn() {
+        assertTrue(isIn(0x112, 0x1));
+        assertTrue(isIn(0x112, 0x11));
+        assertTrue(isIn(0x112, 0x112));
+
+        assertFalse(isIn(0x1, 0x112));
+        assertFalse(isIn(0x12, 0x2));
+    }
+
+    @Test
+    public void testStateMachineInitialState() {
+        StateMachine stateMachine = new StateMachine();
+        assertEquals(0, stateMachine.getState());
+
+        stateMachine = new StateMachine(0x23);
+        assertEquals(0x23, stateMachine.getState());
+    }
+
+    @Test
+    public void testStateMachineTransitToChild() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine();
+        stateMachine.addStateHandler(0x1, new LoggingHandler(0x1, log));
+        stateMachine.addStateHandler(0x12, new LoggingHandler(0x12, log));
+        stateMachine.addStateHandler(0x123, new LoggingHandler(0x123, log));
+        stateMachine.addStateHandler(0x1233, new LoggingHandler(0x1233, log));
+
+        // 0x0 -> 0x12
+        stateMachine.transit(0x12);
+        assertEquals("i1;i12;", log.toString());
+        assertEquals(0x12, stateMachine.getState());
+
+        // 0x12 -> 0x1233
+        log.setLength(0);
+        stateMachine.transit(0x1233);
+        assertEquals(0x1233, stateMachine.getState());
+        assertEquals("i123;i1233;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineTransitToParent() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x253);
+        stateMachine.addStateHandler(0x2, new LoggingHandler(0x2, log));
+        stateMachine.addStateHandler(0x25, new LoggingHandler(0x25, log));
+        stateMachine.addStateHandler(0x253, new LoggingHandler(0x253, log));
+
+        // 0x253 -> 0x2
+        stateMachine.transit(0x2);
+        assertEquals(0x2, stateMachine.getState());
+        assertEquals("o253;o25;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineTransitSelf() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x253);
+        stateMachine.addStateHandler(0x2, new LoggingHandler(0x2, log));
+        stateMachine.addStateHandler(0x25, new LoggingHandler(0x25, log));
+        stateMachine.addStateHandler(0x253, new LoggingHandler(0x253, log));
+
+        // 0x253 -> 0x253
+        stateMachine.transit(0x253);
+        assertEquals(0x253, stateMachine.getState());
+        assertEquals("o253;i253;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineTransitGeneral() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x1351);
+        stateMachine.addStateHandler(0x1, new LoggingHandler(0x1, log));
+        stateMachine.addStateHandler(0x13, new LoggingHandler(0x13, log));
+        stateMachine.addStateHandler(0x132, new LoggingHandler(0x132, log));
+        stateMachine.addStateHandler(0x1322, new LoggingHandler(0x1322, log));
+        stateMachine.addStateHandler(0x1322, new LoggingHandler(0x1322, log));
+        stateMachine.addStateHandler(0x135, new LoggingHandler(0x135, log));
+        stateMachine.addStateHandler(0x1351, new LoggingHandler(0x1351, log));
+
+        // 0x1351 -> 0x1322
+        // least common ancestor = 0x13
+        stateMachine.transit(0x1322);
+        assertEquals(0x1322, stateMachine.getState());
+        assertEquals("o1351;o135;i132;i1322;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineTriggerStateAction() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x253);
+        stateMachine.addStateHandler(0x2, new LoggingHandler(0x2, log));
+        stateMachine.addStateHandler(0x25, new LoggingHandler(0x25, log));
+        stateMachine.addStateHandler(0x253, new LoggingHandler(0x253, log));
+
+        // state 0x253 handles the message itself
+        stateMachine.handle(0, null);
+        assertEquals("h253;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineTriggerStateActionDelegate() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x253);
+        stateMachine.addStateHandler(0x2, new LoggingHandler(0x2, log));
+        stateMachine.addStateHandler(0x25, new LoggingHandler(0x25, log));
+        stateMachine.addStateHandler(0x253,
+                new LoggingHandler(0x253, log, false /* handleSelf */));
+
+        // state 0x253 delegate the message handling to its parent state
+        stateMachine.handle(0, null);
+        assertEquals("h25;", log.toString());
+    }
+
+    @Test
+    public void testStateMachineNestedTransition() {
+        final StringBuffer log = new StringBuffer();
+
+        StateMachine stateMachine = new StateMachine(0x25);
+        stateMachine.addStateHandler(0x1, new LoggingHandler(0x1, log));
+
+        // Force transit to state 0x3 in exit()
+        stateMachine.addStateHandler(0x2,
+                new LoggingHandlerTransferInExit(0x2, log, stateMachine, 0x3));
+        stateMachine.addStateHandler(0x25, new LoggingHandler(0x25, log));
+        stateMachine.addStateHandler(0x3, new LoggingHandler(0x3, log));
+
+        stateMachine.transit(0x1);
+        // Start transit to 0x1
+        //  0x25 -> 0x2 [transit(0x3) requested] -> 0x1
+        //  0x1 -> 0x3
+        // Immediately set the status to 0x1, no enter/exit
+        assertEquals("o25;o2;i1;o1;i3;", log.toString());
+    }
+}
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 3b50fa4..133f924 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -29,9 +29,10 @@
         "android.hardware.usb-V1.1-java",
         "android.hardware.usb-V1.2-java",
         "android.hardware.usb-V1.3-java",
-	"android.hardware.usb-V1-java",
+        "android.hardware.usb-V2-java",
         "android.hardware.usb.gadget-V1.0-java",
         "android.hardware.usb.gadget-V1.1-java",
         "android.hardware.usb.gadget-V1.2-java",
+        "android.hardware.usb.gadget-V1-java",
     ],
 }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1c081c1..b6aed2db 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -44,6 +44,7 @@
 import android.debug.AdbNotifications;
 import android.debug.AdbTransportType;
 import android.debug.IAdbTransport;
+import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.ParcelableUsbPort;
 import android.hardware.usb.UsbAccessory;
 import android.hardware.usb.UsbConfiguration;
@@ -54,9 +55,7 @@
 import android.hardware.usb.UsbPort;
 import android.hardware.usb.UsbPortStatus;
 import android.hardware.usb.gadget.V1_0.GadgetFunction;
-import android.hardware.usb.gadget.V1_0.IUsbGadget;
 import android.hardware.usb.gadget.V1_0.Status;
-import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
 import android.hardware.usb.gadget.V1_2.UsbSpeed;
 import android.hidl.manager.V1_0.IServiceManager;
 import android.hidl.manager.V1_0.IServiceNotification;
@@ -88,9 +87,12 @@
 import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
 import com.android.internal.notification.SystemNotificationChannels;
 import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.dump.DualDumpOutputStream;
 import com.android.server.FgThread;
 import com.android.server.LocalServices;
+import com.android.server.usb.hal.gadget.UsbGadgetHal;
+import com.android.server.usb.hal.gadget.UsbGadgetHalInstance;
 import com.android.server.utils.EventLogger;
 import com.android.server.wm.ActivityTaskManagerInternal;
 
@@ -106,6 +108,7 @@
 import java.util.NoSuchElementException;
 import java.util.Scanner;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -216,6 +219,13 @@
 
     private static EventLogger sEventLogger;
 
+    private static UsbGadgetHal mUsbGadgetHal;
+
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     static {
         sDenyInterfaces = new HashSet<>();
         sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -298,15 +308,11 @@
         mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
         initRndisAddress();
 
+        int operationId = sUsbOperationCount.incrementAndGet();
         boolean halNotPresent = false;
-        try {
-            IUsbGadget.getService(true);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
-        } catch (NoSuchElementException e) {
-            halNotPresent = true;
-            Slog.i(TAG, "USB GADGET HAL not present in the device", e);
-        }
+
+        mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
+        Slog.d(TAG, "getInstance done");
 
         mControlFds = new HashMap<>();
         FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
@@ -320,7 +326,7 @@
         }
         mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
 
-        if (halNotPresent) {
+        if (mUsbGadgetHal == null) {
             /**
              * Initialze the legacy UsbHandler
              */
@@ -334,6 +340,8 @@
                     alsaManager, permissionManager);
         }
 
+        mHandler.handlerInitDone(operationId);
+
         if (nativeIsStartRequested()) {
             if (DEBUG) Slog.d(TAG, "accessory attached at boot");
             startAccessoryMode();
@@ -455,6 +463,8 @@
     private void startAccessoryMode() {
         if (!mHasUsbAccessory) return;
 
+        int operationId = sUsbOperationCount.incrementAndGet();
+
         mAccessoryStrings = nativeGetAccessoryStrings();
         boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
         // don't start accessory mode if our mandatory strings have not been set
@@ -475,7 +485,7 @@
                     ACCESSORY_REQUEST_TIMEOUT);
             mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_HANDSHAKE_TIMEOUT),
                     ACCESSORY_HANDSHAKE_TIMEOUT);
-            setCurrentFunctions(functions);
+            setCurrentFunctions(functions, operationId);
         }
     }
 
@@ -504,6 +514,20 @@
         }
     }
 
+    public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+        Slog.println(priority, TAG, msg);
+        if (pw != null) {
+            pw.println(msg);
+        }
+    }
+
+    public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+        Slog.e(TAG, msg, e);
+        if (pw != null) {
+            pw.println(msg + e);
+        }
+    }
+
     abstract static class UsbHandler extends Handler {
 
         // current USB state
@@ -608,6 +632,19 @@
             sendMessage(m);
         }
 
+        public boolean sendMessage(int what) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            return sendMessageDelayed(m,0);
+        }
+
+        public void sendMessage(int what, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, Object arg) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -615,6 +652,22 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, Object arg, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            m.arg1 = operationId;
+            sendMessage(m);
+        }
+
+        public void sendMessage(int what, boolean arg, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.arg1 = (arg ? 1 : 0);
+            m.arg2 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, Object arg, boolean arg1) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -623,6 +676,15 @@
             sendMessage(m);
         }
 
+        public void sendMessage(int what, long arg, boolean arg1, int operationId) {
+            removeMessages(what);
+            Message m = Message.obtain(this, what);
+            m.obj = arg;
+            m.arg1 = (arg1 ? 1 : 0);
+            m.arg2 = operationId;
+            sendMessage(m);
+        }
+
         public void sendMessage(int what, boolean arg1, boolean arg2) {
             removeMessages(what);
             Message m = Message.obtain(this, what);
@@ -680,7 +742,7 @@
             sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
         }
 
-        private void setAdbEnabled(boolean enable) {
+        private void setAdbEnabled(boolean enable, int operationId) {
             if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
 
             if (enable) {
@@ -689,7 +751,7 @@
                 setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, "");
             }
 
-            setEnabledFunctions(mCurrentFunctions, true);
+            setEnabledFunctions(mCurrentFunctions, true, operationId);
             updateAdbNotification(false);
         }
 
@@ -701,6 +763,8 @@
         private void updateCurrentAccessory() {
             // We are entering accessory mode if we have received a request from the host
             // and the request has not timed out yet.
+            int operationId = sUsbOperationCount.incrementAndGet();
+
             boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
 
             if (mConfigured && enteringAccessoryMode) {
@@ -732,18 +796,18 @@
                 }
             } else {
                 if (!enteringAccessoryMode) {
-                    notifyAccessoryModeExit();
+                    notifyAccessoryModeExit(operationId);
                 } else if (DEBUG) {
                     Slog.v(TAG, "Debouncing accessory mode exit");
                 }
             }
         }
 
-        private void notifyAccessoryModeExit() {
+        private void notifyAccessoryModeExit(int operationId) {
             // make sure accessory mode is off
             // and restore default functions
             Slog.d(TAG, "exited USB accessory mode");
-            setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+            setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
 
             if (mCurrentAccessory != null) {
                 if (mBootCompleted) {
@@ -869,8 +933,8 @@
                     mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
         }
 
-        private void setScreenUnlockedFunctions() {
-            setEnabledFunctions(mScreenUnlockedFunctions, false);
+        private void setScreenUnlockedFunctions(int operationId) {
+            setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
         }
 
         private static class AdbTransport extends IAdbTransport.Stub {
@@ -883,7 +947,8 @@
             @Override
             public void onAdbEnabled(boolean enabled, byte transportType) {
                 if (transportType == AdbTransportType.USB) {
-                    mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
                 }
             }
         }
@@ -906,6 +971,7 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_UPDATE_STATE:
+                    int operationId = sUsbOperationCount.incrementAndGet();
                     mConnected = (msg.arg1 == 1);
                     mConfigured = (msg.arg2 == 1);
 
@@ -923,9 +989,9 @@
                             // restore defaults when USB is disconnected
                             if (!mScreenLocked
                                     && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
-                                setScreenUnlockedFunctions();
+                                setScreenUnlockedFunctions(operationId);
                             } else {
-                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                                setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                             }
                         }
                         updateUsbFunctions();
@@ -1036,13 +1102,15 @@
                     updateUsbNotification(false);
                     break;
                 case MSG_ENABLE_ADB:
-                    setAdbEnabled(msg.arg1 == 1);
+                    setAdbEnabled(msg.arg1 == 1, msg.arg2);
                     break;
                 case MSG_SET_CURRENT_FUNCTIONS:
                     long functions = (Long) msg.obj;
-                    setEnabledFunctions(functions, false);
+                    operationId = (int) msg.arg1;
+                    setEnabledFunctions(functions, false, operationId);
                     break;
                 case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mScreenUnlockedFunctions = (Long) msg.obj;
                     if (mSettings != null) {
                         SharedPreferences.Editor editor = mSettings.edit();
@@ -1053,12 +1121,13 @@
                     }
                     if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
                         // If the screen is unlocked, also set current functions.
-                        setScreenUnlockedFunctions();
+                        setScreenUnlockedFunctions(operationId);
                     } else {
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     }
                     break;
                 case MSG_UPDATE_SCREEN_LOCK:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (msg.arg1 == 1 == mScreenLocked) {
                         break;
                     }
@@ -1068,23 +1137,25 @@
                     }
                     if (mScreenLocked) {
                         if (!mConnected) {
-                            setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                            setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                         }
                     } else {
                         if (mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE
                                 && mCurrentFunctions == UsbManager.FUNCTION_NONE) {
                             // Set the screen unlocked functions if current function is charging.
-                            setScreenUnlockedFunctions();
+                            setScreenUnlockedFunctions(operationId);
                         }
                     }
                     break;
                 case MSG_UPDATE_USER_RESTRICTIONS:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     // Restart the USB stack if USB transfer is enabled but no longer allowed.
                     if (isUsbDataTransferActive(mCurrentFunctions) && !isUsbTransferAllowed()) {
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, true);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, true, operationId);
                     }
                     break;
                 case MSG_SYSTEM_READY:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mNotificationManager = (NotificationManager)
                             mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 
@@ -1102,17 +1173,19 @@
                                         NotificationManager.IMPORTANCE_HIGH));
                     }
                     mSystemReady = true;
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_LOCALE_CHANGED:
                     updateAdbNotification(true);
                     updateUsbNotification(true);
                     break;
                 case MSG_BOOT_COMPLETED:
+                    operationId = sUsbOperationCount.incrementAndGet();
                     mBootCompleted = true;
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_USER_SWITCHED: {
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (mCurrentUser != msg.arg1) {
                         if (DEBUG) {
                             Slog.v(TAG, "Current user switched to " + msg.arg1);
@@ -1125,16 +1198,18 @@
                                     mSettings.getString(String.format(Locale.ENGLISH,
                                             UNLOCKED_CONFIG_PREF, mCurrentUser), ""));
                         }
-                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                        setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     }
                     break;
                 }
                 case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (DEBUG) {
-                        Slog.v(TAG, "Accessory mode enter timeout: " + mConnected);
+                        Slog.v(TAG, "Accessory mode enter timeout: " + mConnected
+                                    + " ,operationId: " + operationId);
                     }
                     if (!mConnected || (mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) == 0) {
-                        notifyAccessoryModeExit();
+                        notifyAccessoryModeExit(operationId);
                     }
                     break;
                 }
@@ -1157,7 +1232,9 @@
             }
         }
 
-        protected void finishBoot() {
+        public abstract void handlerInitDone(int operationId);
+
+        protected void finishBoot(int operationId) {
             if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
                 if (mPendingBootBroadcast) {
                     updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
@@ -1165,9 +1242,9 @@
                 }
                 if (!mScreenLocked
                         && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
-                    setScreenUnlockedFunctions();
+                    setScreenUnlockedFunctions(operationId);
                 } else {
-                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                 }
                 if (mCurrentAccessory != null) {
                     mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -1507,7 +1584,8 @@
         /**
          * Evaluates USB function policies and applies the change accordingly.
          */
-        protected abstract void setEnabledFunctions(long functions, boolean forceRestart);
+        protected abstract void setEnabledFunctions(long functions,
+                boolean forceRestart, int operationId);
 
         public void setAccessoryUEventTime(long accessoryConnectionStartTime) {
             mAccessoryConnectionStartTime = accessoryConnectionStartTime;
@@ -1522,6 +1600,11 @@
             mSendStringCount = 0;
             mStartAccessory = false;
         }
+
+        public abstract void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions);
+
+        public abstract void getUsbSpeedCb(int speed);
     }
 
     private static final class UsbHandlerLegacy extends UsbHandler {
@@ -1540,6 +1623,11 @@
         private String mCurrentFunctionsStr;
         private boolean mUsbDataUnlocked;
 
+        /**
+         * Keeps track of the latest setCurrentUsbFunctions request number.
+         */
+        private int mCurrentRequest = 0;
+
         UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
                 UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
             super(looper, context, deviceManager, alsaManager, permissionManager);
@@ -1573,6 +1661,10 @@
             }
         }
 
+        @Override
+        public void handlerInitDone(int operationId) {
+        }
+
         private void readOemUsbOverrideConfig(Context context) {
             String[] configList = context.getResources().getStringArray(
                     com.android.internal.R.array.config_oemUsbModeOverride);
@@ -1675,11 +1767,14 @@
         }
 
         @Override
-        protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
+        protected void setEnabledFunctions(long usbFunctions,
+                boolean forceRestart, int operationId) {
             boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
             if (DEBUG) {
-                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", "
-                        + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+                Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions +
+                        " ,forceRestart=" + forceRestart +
+                        " ,usbDataUnlocked=" + usbDataUnlocked +
+                        " ,operationId=" + operationId);
             }
 
             if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -1775,7 +1870,6 @@
                     || !mCurrentFunctionsStr.equals(functions)
                     || !mCurrentFunctionsApplied
                     || forceRestart) {
-                Slog.i(TAG, "Setting USB config to " + functions);
                 mCurrentFunctionsStr = functions;
                 mCurrentOemFunctions = oemFunctions;
                 mCurrentFunctionsApplied = false;
@@ -1871,16 +1965,19 @@
             if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
             return true;
         }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed){
+        }
     }
 
     private static final class UsbHandlerHal extends UsbHandler {
 
-        /**
-         * Proxy object for the usb gadget hal daemon.
-         */
-        @GuardedBy("mGadgetProxyLock")
-        private IUsbGadget mGadgetProxy;
-
         private final Object mGadgetProxyLock = new Object();
 
         /**
@@ -1926,33 +2023,20 @@
         UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
                 UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
             super(looper, context, deviceManager, alsaManager, permissionManager);
+            int operationId = sUsbOperationCount.incrementAndGet();
             try {
-                ServiceNotification serviceNotification = new ServiceNotification();
-
-                boolean ret = IServiceManager.getService()
-                        .registerForNotifications(GADGET_HAL_FQ_NAME, "", serviceNotification);
-                if (!ret) {
-                    Slog.e(TAG, "Failed to register usb gadget service start notification");
-                    return;
-                }
 
                 synchronized (mGadgetProxyLock) {
-                    mGadgetProxy = IUsbGadget.getService(true);
-                    mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
-                            USB_GADGET_HAL_DEATH_COOKIE);
                     mCurrentFunctions = UsbManager.FUNCTION_NONE;
                     mCurrentUsbFunctionsRequested = true;
                     mUsbSpeed = UsbSpeed.UNKNOWN;
                     mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
-                    mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+                    updateUsbGadgetHalVersion();
                 }
                 String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
                 updateState(state);
-                updateUsbGadgetHalVersion();
             } catch (NoSuchElementException e) {
                 Slog.e(TAG, "Usb gadget hal not found", e);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Usb Gadget hal not responding", e);
             } catch (Exception e) {
                 Slog.e(TAG, "Error initializing UsbHandler", e);
             }
@@ -1965,7 +2049,7 @@
                 if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
                     Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
                     synchronized (mGadgetProxyLock) {
-                        mGadgetProxy = null;
+                        mUsbGadgetHal = null;
                     }
                 }
             }
@@ -1988,18 +2072,22 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_SET_CHARGING_FUNCTIONS:
-                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+                    int operationId = sUsbOperationCount.incrementAndGet();
+                    setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
                     break;
                 case MSG_SET_FUNCTIONS_TIMEOUT:
-                    Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+                    operationId = sUsbOperationCount.incrementAndGet();
+                    Slog.e(TAG, "Set functions timed out! no reply from usb hal"
+                                + " ,operationId:" + operationId);
                     if (msg.arg1 != 1) {
                         // Set this since default function may be selected from Developer options
-                        setEnabledFunctions(mScreenUnlockedFunctions, false);
+                        setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
                     }
                     break;
                 case MSG_GET_CURRENT_USB_FUNCTIONS:
                     Slog.i(TAG, "processing MSG_GET_CURRENT_USB_FUNCTIONS");
                     mCurrentUsbFunctionsReceived = true;
+                    operationId = msg.arg2;
 
                     if (mCurrentUsbFunctionsRequested) {
                         Slog.i(TAG, "updating mCurrentFunctions");
@@ -2009,91 +2097,71 @@
                                 "mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
                         mCurrentFunctionsApplied = msg.arg1 == 1;
                     }
-                    finishBoot();
+                    finishBoot(operationId);
                     break;
                 case MSG_FUNCTION_SWITCH_TIMEOUT:
                     /**
                      * Dont force to default when the configuration is already set to default.
                      */
+                    operationId = sUsbOperationCount.incrementAndGet();
                     if (msg.arg1 != 1) {
                         // Set this since default function may be selected from Developer options
-                        setEnabledFunctions(mScreenUnlockedFunctions, false);
+                        setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
                     }
                     break;
                 case MSG_GADGET_HAL_REGISTERED:
                     boolean preexisting = msg.arg1 == 1;
+                    operationId = sUsbOperationCount.incrementAndGet();
                     synchronized (mGadgetProxyLock) {
                         try {
-                            mGadgetProxy = IUsbGadget.getService();
-                            mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
-                                    USB_GADGET_HAL_DEATH_COOKIE);
+                            mUsbGadgetHal = UsbGadgetHalInstance.getInstance(mUsbDeviceManager,
+                                    null);
                             if (!mCurrentFunctionsApplied && !preexisting) {
-                                setEnabledFunctions(mCurrentFunctions, false);
+                                setEnabledFunctions(mCurrentFunctions, false, operationId);
                             }
                         } catch (NoSuchElementException e) {
                             Slog.e(TAG, "Usb gadget hal not found", e);
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "Usb Gadget hal not responding", e);
                         }
                     }
                     break;
                 case MSG_RESET_USB_GADGET:
                     synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "reset Usb Gadget mGadgetProxy is null");
+                        if (mUsbGadgetHal == null) {
+                            Slog.e(TAG, "reset Usb Gadget mUsbGadgetHal is null");
                             break;
                         }
 
                         try {
-                            android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxy =
-                                    android.hardware.usb.gadget.V1_1.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            gadgetProxy.reset();
-                        } catch (RemoteException e) {
+                            mUsbGadgetHal.reset();
+                        } catch (Exception e) {
                             Slog.e(TAG, "reset Usb Gadget failed", e);
                         }
                     }
                     break;
                 case MSG_UPDATE_USB_SPEED:
-                    synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "mGadgetProxy is null");
-                            break;
-                        }
+                    operationId = sUsbOperationCount.incrementAndGet();
+                    if (mUsbGadgetHal == null) {
+                        Slog.e(TAG, "mGadgetHal is null, operationId:" + operationId);
+                        break;
+                    }
 
-                        try {
-                            android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
-                                    android.hardware.usb.gadget.V1_2.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            if (gadgetProxy != null) {
-                                gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
-                            }
-                        } catch (RemoteException e) {
-                            Slog.e(TAG, "get UsbSpeed failed", e);
-                        }
+                    try {
+                        mUsbGadgetHal.getUsbSpeed(operationId);
+                    } catch (Exception e) {
+                        Slog.e(TAG, "get UsbSpeed failed", e);
                     }
                     break;
                 case MSG_UPDATE_HAL_VERSION:
-                    synchronized (mGadgetProxyLock) {
-                        if (mGadgetProxy == null) {
-                            Slog.e(TAG, "mGadgetProxy is null");
-                            break;
+                    if (mUsbGadgetHal == null) {
+                        Slog.e(TAG, "mUsbGadgetHal is null");
+                        break;
+                    }
+                    else {
+                        try {
+                            mCurrentGadgetHalVersion = mUsbGadgetHal.getGadgetHalVersion();
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "update Usb gadget version failed", e);
                         }
-
-                        android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
-                                android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
-                        if (gadgetProxy == null) {
-                            android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxyV1By1 =
-                                    android.hardware.usb.gadget.V1_1.IUsbGadget
-                                            .castFrom(mGadgetProxy);
-                            if (gadgetProxyV1By1 == null) {
-                                mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
-                                break;
-                            }
-                            mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_1;
-                            break;
-                        }
-                        mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_2;
                     }
                     break;
                 default:
@@ -2101,56 +2169,31 @@
             }
         }
 
-        private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
-            int mRequest;
-            long mFunctions;
-            boolean mChargingFunctions;
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
 
-            UsbGadgetCallback() {
+            if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+                  || (mFunctions != functions)) {
+                return;
             }
 
-            UsbGadgetCallback(int request, long functions,
-                    boolean chargingFunctions) {
-                mRequest = request;
-                mFunctions = functions;
-                mChargingFunctions = chargingFunctions;
-            }
-
-            @Override
-            public void setCurrentUsbFunctionsCb(long functions,
-                    int status) {
-                /**
-                 * Callback called for a previous setCurrenUsbFunction
-                 */
-                if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
-                        || (mFunctions != functions)) {
-                    return;
-                }
-
-                removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
-                Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
-                if (status == Status.SUCCESS) {
-                    mCurrentFunctionsApplied = true;
-                } else if (!mChargingFunctions) {
-                    Slog.e(TAG, "Setting default fuctions");
-                    sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
-                }
-            }
-
-            @Override
-            public void getCurrentUsbFunctionsCb(long functions,
-                    int status) {
-                sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
-                        status == Status.FUNCTIONS_APPLIED);
-            }
-
-            @Override
-            public void getUsbSpeedCb(int speed) {
-                mUsbSpeed = speed;
+            removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+            Slog.i(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+            if (status == Status.SUCCESS) {
+                mCurrentFunctionsApplied = true;
+            } else if (!mChargingFunctions) {
+                Slog.e(TAG, "Setting default fuctions");
+                sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
             }
         }
 
-        private void setUsbConfig(long config, boolean chargingFunctions) {
+        @Override
+        public void getUsbSpeedCb(int speed) {
+            mUsbSpeed = speed;
+        }
+
+        private void setUsbConfig(long config, boolean chargingFunctions, int operationId) {
             if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
             /**
              * Cancel any ongoing requests, if present.
@@ -2160,8 +2203,8 @@
             removeMessages(MSG_SET_CHARGING_FUNCTIONS);
 
             synchronized (mGadgetProxyLock) {
-                if (mGadgetProxy == null) {
-                    Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+                if (mUsbGadgetHal == null) {
+                    Slog.e(TAG, "setUsbConfig mUsbGadgetHal is null");
                     return;
                 }
                 try {
@@ -2178,10 +2221,9 @@
                         LocalServices.getService(AdbManagerInternal.class)
                                 .stopAdbdForTransport(AdbTransportType.USB);
                     }
-                    UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
-                            config, chargingFunctions);
-                    mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,
-                            SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+                    mUsbGadgetHal.setCurrentUsbFunctions(mCurrentRequest,
+                            config, chargingFunctions,
+                            SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS, operationId);
                     sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
                             SET_FUNCTIONS_TIMEOUT_MS);
                     if (mConnected) {
@@ -2190,17 +2232,19 @@
                                 SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
                     }
                     if (DEBUG) Slog.d(TAG, "timeout message queued");
-                } catch (RemoteException e) {
+                } catch (Exception e) {//RemoteException e) {
                     Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
                 }
             }
         }
 
         @Override
-        protected void setEnabledFunctions(long functions, boolean forceRestart) {
+        protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
             if (DEBUG) {
-                Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
-                        + "forceRestart=" + forceRestart);
+                Slog.d(TAG, "setEnabledFunctionsi " +
+                        "functions=" + functions +
+                        ", forceRestart=" + forceRestart +
+                        ", operationId=" + operationId);
             }
             if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
                 if ((functions & UsbManager.FUNCTION_NCM) != 0) {
@@ -2221,7 +2265,7 @@
                 functions = getAppliedFunctions(functions);
 
                 // Set the new USB configuration.
-                setUsbConfig(functions, chargingFunctions);
+                setUsbConfig(functions, chargingFunctions, operationId);
 
                 if (mBootCompleted && isUsbDataTransferActive(functions)) {
                     // Start up dependent services.
@@ -2229,6 +2273,11 @@
                 }
             }
         }
+
+        @Override
+        public void handlerInitDone(int operationId) {
+            mUsbGadgetHal.getCurrentUsbFunctions(operationId);
+        }
     }
 
     /* returns the currently attached USB accessory */
@@ -2270,6 +2319,21 @@
         return mHandler.getGadgetHalVersion();
     }
 
+    public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
+        mHandler.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+    }
+
+    public void getCurrentUsbFunctionsCb(long functions, int status) {
+        mHandler.sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+                    status == Status.FUNCTIONS_APPLIED);
+    }
+
+    public void getUsbSpeedCb(int speed) {
+        mHandler.getUsbSpeedCb(speed);
+    }
+
     /**
      * Returns a dup of the control file descriptor for the given function.
      */
@@ -2295,7 +2359,7 @@
      *
      * @param functions The functions to set, or empty to set the charging function.
      */
-    public void setCurrentFunctions(long functions) {
+    public void setCurrentFunctions(long functions, int operationId) {
         if (DEBUG) {
             Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
         }
@@ -2312,7 +2376,7 @@
         } else if (functions == UsbManager.FUNCTION_ACCESSORY) {
             MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
         }
-        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
+        mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, operationId);
     }
 
     /**
@@ -2340,7 +2404,8 @@
     }
 
     private void onAdbEnabled(boolean enabled) {
-        mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+        int operationId = sUsbOperationCount.incrementAndGet();
+        mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
     }
 
     /**
diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java
index f8df6c6..4bb9de5 100644
--- a/services/usb/java/com/android/server/usb/UsbPortManager.java
+++ b/services/usb/java/com/android/server/usb/UsbPortManager.java
@@ -73,6 +73,7 @@
 import android.service.usb.UsbPortInfoProto;
 import android.service.usb.UsbPortManagerProto;
 import android.util.ArrayMap;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.Slog;
 
@@ -87,6 +88,7 @@
 import com.android.server.usb.hal.port.UsbPortHal;
 import com.android.server.usb.hal.port.UsbPortHalInstance;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.NoSuchElementException;
 import java.util.Objects;
@@ -754,6 +756,31 @@
         }
     }
 
+    /**
+     * Sets Compliance Warnings for simulated USB port objects.
+     */
+    public void simulateComplianceWarnings(String portId, String complianceWarningsString,
+            IndentingPrintWriter pw) {
+        synchronized (mLock) {
+            final RawPortInfo portInfo = mSimulatedPorts.get(portId);
+            if (portInfo == null) {
+                pw.println("Simulated port not found");
+                return;
+            }
+
+            IntArray complianceWarnings = new IntArray();
+            for (String s : complianceWarningsString.split("[, ]")) {
+                if (s.length() > 0) {
+                    complianceWarnings.add(Integer.parseInt(s));
+                }
+            }
+            pw.println("Simulating Compliance Warnings: portId=" + portId
+                    + " Warnings=" + complianceWarningsString);
+            portInfo.complianceWarnings = complianceWarnings.toArray();
+            updatePortsLocked(pw, null);
+        }
+    }
+
     public void disconnectSimulatedPort(String portId, IndentingPrintWriter pw) {
         synchronized (mLock) {
             final RawPortInfo portInfo = mSimulatedPorts.get(portId);
@@ -842,7 +869,10 @@
                         portInfo.contaminantDetectionStatus,
                         portInfo.usbDataStatus,
                         portInfo.powerTransferLimited,
-                        portInfo.powerBrickConnectionStatus, pw);
+                        portInfo.powerBrickConnectionStatus,
+                        portInfo.supportsComplianceWarnings,
+                        portInfo.complianceWarnings,
+                        pw);
             }
         } else {
             for (RawPortInfo currentPortInfo : newPortInfo) {
@@ -857,7 +887,10 @@
                         currentPortInfo.contaminantDetectionStatus,
                         currentPortInfo.usbDataStatus,
                         currentPortInfo.powerTransferLimited,
-                        currentPortInfo.powerBrickConnectionStatus, pw);
+                        currentPortInfo.powerBrickConnectionStatus,
+                        currentPortInfo.supportsComplianceWarnings,
+                        currentPortInfo.complianceWarnings,
+                        pw);
             }
         }
 
@@ -880,6 +913,9 @@
                     handlePortRemovedLocked(portInfo, pw);
                     break;
             }
+            if (portInfo.mComplianceWarningChange == portInfo.COMPLIANCE_WARNING_CHANGED) {
+                handlePortComplianceWarningLocked(portInfo, pw);
+            }
         }
     }
 
@@ -896,6 +932,8 @@
             int usbDataStatus,
             boolean powerTransferLimited,
             int powerBrickConnectionStatus,
+            boolean supportsComplianceWarnings,
+            @NonNull int[] complianceWarnings,
             IndentingPrintWriter pw) {
         // Only allow mode switch capability for dual role ports.
         // Validate that the current mode matches the supported modes we expect.
@@ -949,13 +987,15 @@
             portInfo = new PortInfo(mContext.getSystemService(UsbManager.class),
                 portId, supportedModes, supportedContaminantProtectionModes,
                 supportsEnableContaminantPresenceProtection,
-                supportsEnableContaminantPresenceDetection);
+                supportsEnableContaminantPresenceDetection,
+                supportsComplianceWarnings);
             portInfo.setStatus(currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickConnectionStatus);
+                    powerTransferLimited, powerBrickConnectionStatus,
+                    complianceWarnings);
             mPorts.put(portId, portInfo);
         } else {
             // Validate that ports aren't changing definition out from under us.
@@ -987,13 +1027,13 @@
                         + ", current=" + supportsEnableContaminantPresenceDetection);
             }
 
-
             if (portInfo.setStatus(currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
                     currentDataRole, canChangeDataRole,
                     supportedRoleCombinations, contaminantProtectionStatus,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickConnectionStatus)) {
+                    powerTransferLimited, powerBrickConnectionStatus,
+                    complianceWarnings)) {
                 portInfo.mDisposition = PortInfo.DISPOSITION_CHANGED;
             } else {
                 portInfo.mDisposition = PortInfo.DISPOSITION_READY;
@@ -1019,6 +1059,11 @@
         handlePortLocked(portInfo, pw);
     }
 
+    private void handlePortComplianceWarningLocked(PortInfo portInfo, IndentingPrintWriter pw) {
+        logAndPrint(Log.INFO, pw, "USB port compliance warning changed: " + portInfo);
+        sendComplianceWarningBroadcastLocked(portInfo);
+    }
+
     private void handlePortRemovedLocked(PortInfo portInfo, IndentingPrintWriter pw) {
         logAndPrint(Log.INFO, pw, "USB port removed: " + portInfo);
         handlePortLocked(portInfo, pw);
@@ -1056,6 +1101,23 @@
                 Manifest.permission.MANAGE_USB));
     }
 
+    private void sendComplianceWarningBroadcastLocked(PortInfo portInfo) {
+        if (portInfo.mComplianceWarningChange == portInfo.COMPLIANCE_WARNING_UNCHANGED) {
+            return;
+        }
+        final Intent intent = new Intent(UsbManager.ACTION_USB_PORT_COMPLIANCE_CHANGED);
+        intent.addFlags(
+                Intent.FLAG_RECEIVER_FOREGROUND |
+                        Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+        intent.putExtra(UsbManager.EXTRA_PORT, ParcelableUsbPort.of(portInfo.mUsbPort));
+        intent.putExtra(UsbManager.EXTRA_PORT_STATUS, portInfo.mUsbPortStatus);
+
+        // Guard against possible reentrance by posting the broadcast from the handler
+        // instead of from within the critical section.
+        mHandler.post(() -> mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+                Manifest.permission.MANAGE_USB));
+    }
+
     private void enableContaminantDetectionIfNeeded(PortInfo portInfo, IndentingPrintWriter pw) {
         if (!mConnected.containsKey(portInfo.mUsbPort.getId())) {
             return;
@@ -1180,6 +1242,9 @@
         public static final int DISPOSITION_READY = 2;
         public static final int DISPOSITION_REMOVED = 3;
 
+        public static final int COMPLIANCE_WARNING_UNCHANGED = 0;
+        public static final int COMPLIANCE_WARNING_CHANGED = 1;
+
         public final UsbPort mUsbPort;
         public UsbPortStatus mUsbPortStatus;
         public boolean mCanChangeMode;
@@ -1191,15 +1256,29 @@
         public long mConnectedAtMillis;
         // 0 when port is connected. Else reports the last connected duration
         public long mLastConnectDurationMillis;
+        // default initialized to 0 which means no changes reported
+        public int mComplianceWarningChange;
 
         PortInfo(@NonNull UsbManager usbManager, @NonNull String portId, int supportedModes,
                 int supportedContaminantProtectionModes,
                 boolean supportsEnableContaminantPresenceDetection,
-                boolean supportsEnableContaminantPresenceProtection) {
+                boolean supportsEnableContaminantPresenceProtection,
+                boolean supportsComplianceWarnings) {
             mUsbPort = new UsbPort(usbManager, portId, supportedModes,
                     supportedContaminantProtectionModes,
                     supportsEnableContaminantPresenceDetection,
-                    supportsEnableContaminantPresenceProtection);
+                    supportsEnableContaminantPresenceProtection,
+                    supportsComplianceWarnings);
+            mComplianceWarningChange = COMPLIANCE_WARNING_UNCHANGED;
+        }
+
+        public boolean complianceWarningsChanged(@NonNull int[] complianceWarnings) {
+            if (Arrays.equals(complianceWarnings, mUsbPortStatus.getComplianceWarnings())) {
+                mComplianceWarningChange = COMPLIANCE_WARNING_UNCHANGED;
+                return false;
+            }
+            mComplianceWarningChange = COMPLIANCE_WARNING_CHANGED;
+            return true;
         }
 
         public boolean setStatus(int currentMode, boolean canChangeMode,
@@ -1221,7 +1300,8 @@
                         supportedRoleCombinations, UsbPortStatus.CONTAMINANT_PROTECTION_NONE,
                         UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED,
                         UsbPortStatus.DATA_STATUS_UNKNOWN, false,
-                        UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN);
+                        UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN,
+                        new int[] {});
                 dispositionChanged = true;
             }
 
@@ -1266,7 +1346,8 @@
                 mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
                         supportedRoleCombinations, contaminantProtectionStatus,
                         contaminantDetectionStatus, usbDataStatus,
-                        powerTransferLimited, powerBrickConnectionStatus);
+                        powerTransferLimited, powerBrickConnectionStatus,
+                        new int[] {});
                 dispositionChanged = true;
             }
 
@@ -1281,6 +1362,62 @@
             return dispositionChanged;
         }
 
+        public boolean setStatus(int currentMode, boolean canChangeMode,
+                int currentPowerRole, boolean canChangePowerRole,
+                int currentDataRole, boolean canChangeDataRole,
+                int supportedRoleCombinations, int contaminantProtectionStatus,
+                int contaminantDetectionStatus, int usbDataStatus,
+                boolean powerTransferLimited, int powerBrickConnectionStatus,
+                @NonNull int[] complianceWarnings) {
+            boolean dispositionChanged = false;
+
+            mCanChangeMode = canChangeMode;
+            mCanChangePowerRole = canChangePowerRole;
+            mCanChangeDataRole = canChangeDataRole;
+            if (mUsbPortStatus == null
+                    || mUsbPortStatus.getCurrentMode() != currentMode
+                    || mUsbPortStatus.getCurrentPowerRole() != currentPowerRole
+                    || mUsbPortStatus.getCurrentDataRole() != currentDataRole
+                    || mUsbPortStatus.getSupportedRoleCombinations()
+                    != supportedRoleCombinations
+                    || mUsbPortStatus.getContaminantProtectionStatus()
+                    != contaminantProtectionStatus
+                    || mUsbPortStatus.getContaminantDetectionStatus()
+                    != contaminantDetectionStatus
+                    || mUsbPortStatus.getUsbDataStatus()
+                    != usbDataStatus
+                    || mUsbPortStatus.isPowerTransferLimited()
+                    != powerTransferLimited
+                    || mUsbPortStatus.getPowerBrickConnectionStatus()
+                    != powerBrickConnectionStatus) {
+                if (mUsbPortStatus == null && complianceWarnings.length > 0) {
+                    mComplianceWarningChange = COMPLIANCE_WARNING_CHANGED;
+                }
+                mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+                        supportedRoleCombinations, contaminantProtectionStatus,
+                        contaminantDetectionStatus, usbDataStatus,
+                        powerTransferLimited, powerBrickConnectionStatus,
+                        complianceWarnings);
+                dispositionChanged = true;
+            } else if (complianceWarningsChanged(complianceWarnings)) {
+                mUsbPortStatus = new UsbPortStatus(currentMode, currentPowerRole, currentDataRole,
+                        supportedRoleCombinations, contaminantProtectionStatus,
+                        contaminantDetectionStatus, usbDataStatus,
+                        powerTransferLimited, powerBrickConnectionStatus,
+                        complianceWarnings);
+            }
+
+            if (mUsbPortStatus.isConnected() && mConnectedAtMillis == 0) {
+                mConnectedAtMillis = SystemClock.elapsedRealtime();
+                mLastConnectDurationMillis = 0;
+            } else if (!mUsbPortStatus.isConnected() && mConnectedAtMillis != 0) {
+                mLastConnectDurationMillis = SystemClock.elapsedRealtime() - mConnectedAtMillis;
+                mConnectedAtMillis = 0;
+            }
+
+            return dispositionChanged;
+        }
+
         void dump(@NonNull DualDumpOutputStream dump, @NonNull String idName, long id) {
             long token = dump.start(idName, id);
 
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 72f6cc3..d09f729 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -622,16 +622,16 @@
     }
 
     @Override
-    public void setCurrentFunctions(long functions) {
+    public void setCurrentFunctions(long functions, int operationId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
         Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
         Preconditions.checkState(mDeviceManager != null);
-        mDeviceManager.setCurrentFunctions(functions);
+        mDeviceManager.setCurrentFunctions(functions, operationId);
     }
 
     @Override
-    public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
-        setCurrentFunctions(UsbManager.usbFunctionsFromString(functions));
+    public void setCurrentFunction(String functions, boolean usbDataUnlocked, int operationId) {
+        setCurrentFunctions(UsbManager.usbFunctionsFromString(functions), operationId);
     }
 
     @Override
@@ -1093,6 +1093,23 @@
                     mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
                             "", 0);
                 }
+            } else if ("set-compliance-reasons".equals(args[0]) && args.length == 3) {
+                final String portId = args[1];
+                final String complianceWarnings = args[2];
+                if (mPortManager != null) {
+                    mPortManager.simulateComplianceWarnings(portId, complianceWarnings, pw);
+                    pw.println();
+                    mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
+                            "", 0);
+                }
+            } else if ("clear-compliance-reasons".equals(args[0]) && args.length == 2) {
+                final String portId = args[1];
+                if (mPortManager != null) {
+                    mPortManager.simulateComplianceWarnings(portId, "", pw);
+                    pw.println();
+                    mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
+                            "", 0);
+                }
             } else if ("ports".equals(args[0]) && args.length == 1) {
                 if (mPortManager != null) {
                     mPortManager.dump(new DualDumpOutputStream(new IndentingPrintWriter(pw, "  ")),
@@ -1142,6 +1159,17 @@
                 pw.println("  dumpsys usb set-contaminant-status \"matrix\" true");
                 pw.println("  dumpsys usb set-contaminant-status \"matrix\" false");
                 pw.println();
+                pw.println("Example simulate compliance warnings:");
+                pw.println("  dumpsys usb add-port \"matrix\" dual");
+                pw.println("  dumpsys usb set-compliance-reasons \"matrix\" <reason-list>");
+                pw.println("  dumpsys usb clear-compliance-reasons \"matrix\"");
+                pw.println("<reason-list> is expected to be formatted as \"1, ..., 4\"");
+                pw.println("with reasons that need to be simulated.");
+                pw.println("  1: debug accessory");
+                pw.println("  2: bc12");
+                pw.println("  3: missing rp");
+                pw.println("  4: type c");
+                pw.println();
                 pw.println("Example USB device descriptors:");
                 pw.println("  dumpsys usb dump-descriptors -dump-short");
                 pw.println("  dumpsys usb dump-descriptors -dump-tree");
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
new file mode 100644
index 0000000..bdfe60a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_V2_0;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.IUsbGadget;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.os.ServiceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Implements the methods to interact with AIDL USB HAL.
+ */
+public final class UsbGadgetAidl implements UsbGadgetHal {
+    private static final String TAG = UsbGadgetAidl.class.getSimpleName();
+    private static final String USB_GADGET_AIDL_SERVICE = IUsbGadget.DESCRIPTOR + "/default";
+    // Proxy object for the usb gadget hal daemon.
+    @GuardedBy("mGadgetProxyLock")
+    private IUsbGadget mGadgetProxy;
+    private final UsbDeviceManager mDeviceManager;
+    public final IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mGadgetProxyLock = new Object();
+    // Callback when the UsbDevice status is changed by the kernel.
+    private UsbGadgetCallback mUsbGadgetCallback;
+
+    public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy == null) {
+                throw new RemoteException("IUsb not initialized yet");
+            }
+        }
+        Slog.i(TAG, "USB Gadget HAL AIDL version: GADGET_HAL_V2_0");
+        return GADGET_HAL_V2_0;
+    }
+
+    @Override
+    public void systemReady() {
+    }
+
+    public void serviceDied() {
+        logAndPrint(Log.ERROR, mPw, "Usb Gadget AIDL hal service died");
+        synchronized (mGadgetProxyLock) {
+            mGadgetProxy = null;
+        }
+        connectToProxy(null);
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy != null) {
+                return;
+            }
+
+            try {
+                mGadgetProxy = IUsbGadget.Stub.asInterface(
+                        ServiceManager.waitForService(USB_GADGET_AIDL_SERVICE));
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+                        + " Did the service fail to start?", e);
+            }
+        }
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            return ServiceManager.isDeclared(USB_GADGET_AIDL_SERVICE);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb gadget Aidl hal service not found.", e);
+        }
+
+        return false;
+    }
+
+    public UsbGadgetAidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+        mDeviceManager = Objects.requireNonNull(deviceManager);
+        mPw = pw;
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void getCurrentUsbFunctions(long operationId) {
+        synchronized (mGadgetProxyLock) {
+            try {
+                mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback(), operationId);
+            } catch (RemoteException e) {
+                logAndPrintException(mPw,
+                        "RemoteException while calling getCurrentUsbFunctions"
+                        + ", opID:" + operationId, e);
+                return;
+            }
+        }
+    }
+
+    @Override
+    public void getUsbSpeed(long operationId) {
+        try {
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.getUsbSpeed(new UsbGadgetCallback(), operationId);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed"
+                    + ", opID:" + operationId, e);
+            return;
+        }
+    }
+
+    @Override
+    public void reset() {
+        try {
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.reset();
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed", e);
+            return;
+        }
+    }
+
+    @Override
+    public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+            boolean mChargingFunctions, int timeout, long operationId) {
+        try {
+            mUsbGadgetCallback = new UsbGadgetCallback(mRequest,
+                                      mFunctions, mChargingFunctions);
+            synchronized (mGadgetProxyLock) {
+                mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback,
+                        timeout, operationId);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling setCurrentUsbFunctions: "
+                    + "mRequest=" + mRequest
+                    + ", mFunctions=" + mFunctions
+                    + ", mChargingFunctions=" + mChargingFunctions
+                    + ", timeout=" + timeout
+                    + ", opID:" + operationId, e);
+            return;
+        }
+    }
+
+    private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+        public int mRequest;
+        public long mFunctions;
+        public boolean mChargingFunctions;
+
+        UsbGadgetCallback() {
+        }
+
+        UsbGadgetCallback(int request, long functions,
+                boolean chargingFunctions) {
+            mRequest = request;
+            mFunctions = functions;
+            mChargingFunctions = chargingFunctions;
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                int status, long transactionId) {
+            mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+        }
+
+        @Override
+        public void getCurrentUsbFunctionsCb(long functions,
+                int status, long transactionId) {
+            mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed, long transactionId) {
+            mDeviceManager.getUsbSpeedCb(speed);
+        }
+
+        @Override
+        public String getInterfaceHash() {
+            return IUsbGadgetCallback.HASH;
+        }
+
+        @Override
+        public int getInterfaceVersion() {
+            return IUsbGadgetCallback.VERSION;
+        }
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
new file mode 100644
index 0000000..267247b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.usb.hal.gadget;
+
+import android.annotation.IntDef;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.os.RemoteException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.String;
+
+/**
+ * @hide
+ */
+public interface UsbGadgetHal {
+    /**
+     * Power role: This USB port can act as a source (provide power).
+     * @hide
+     */
+    public static final int HAL_POWER_ROLE_SOURCE = 1;
+
+    /**
+     * Power role: This USB port can act as a sink (receive power).
+     * @hide
+     */
+    public static final int HAL_POWER_ROLE_SINK = 2;
+
+    @IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
+            HAL_POWER_ROLE_SOURCE,
+            HAL_POWER_ROLE_SINK
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbPowerRole{}
+
+    /**
+     * Data role: This USB port can act as a host (access data services).
+     * @hide
+     */
+    public static final int HAL_DATA_ROLE_HOST = 1;
+
+    /**
+     * Data role: This USB port can act as a device (offer data services).
+     * @hide
+     */
+    public static final int HAL_DATA_ROLE_DEVICE = 2;
+
+    @IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
+            HAL_DATA_ROLE_HOST,
+            HAL_DATA_ROLE_DEVICE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbDataRole{}
+
+    /**
+     * This USB port can act as a downstream facing port (host).
+     *
+     * @hide
+     */
+    public static final int HAL_MODE_DFP = 1;
+
+    /**
+     * This USB port can act as an upstream facing port (device).
+     *
+     * @hide
+     */
+    public static final int HAL_MODE_UFP = 2;
+    @IntDef(prefix = { "HAL_MODE_" }, value = {
+            HAL_MODE_DFP,
+            HAL_MODE_UFP,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    @interface HalUsbPortMode{}
+
+    /**
+     * UsbPortManager would call this when the system is done booting.
+     */
+    public void systemReady();
+
+    /**
+     * This function is used to query the USB functions included in the
+     * current USB configuration.
+     *
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void getCurrentUsbFunctions(long transactionId);
+
+    /**
+     * The function is used to query current USB speed.
+     *
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void getUsbSpeed(long transactionId);
+
+    /**
+     * This function is used to reset USB gadget driver.
+     * Performs USB data connection reset. The connection will disconnect and
+     * reconnect.
+     */
+    public void reset();
+
+    /**
+     * Invoked to query the version of current gadget hal implementation.
+     */
+    public @UsbHalVersion int getGadgetHalVersion() throws RemoteException;
+
+    /**
+     * This function is used to set the current USB gadget configuration.
+     * The USB gadget needs to be torn down if a USB configuration is already
+     * active.
+     *
+     * @param functions list of functions defined by GadgetFunction to be
+     *                  included in the gadget composition.
+     * @param timeout The maximum time (in milliseconds) within which the
+     *                IUsbGadgetCallback needs to be returned.
+     * @param transactionId Used for tracking the current request and is passed down to the HAL
+     *                      implementation as needed.
+     */
+    public void setCurrentUsbFunctions(int request, long functions,
+        boolean chargingFunctions, int timeout, long transactionId);
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
new file mode 100644
index 0000000..d268315
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.usb.hal.gadget;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.gadget.UsbGadgetHidl;
+import com.android.server.usb.hal.gadget.UsbGadgetAidl;
+import com.android.server.usb.UsbDeviceManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbGadgetHalInstance {
+
+    public static UsbGadgetHal getInstance(UsbDeviceManager deviceManager,
+            IndentingPrintWriter pw) {
+
+        logAndPrint(Log.DEBUG, pw, "Querying USB Gadget HAL version");
+        if (UsbGadgetAidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, pw, "USB Gadget HAL AIDL present");
+            return new UsbGadgetAidl(deviceManager, pw);
+        }
+        if (UsbGadgetHidl.isServicePresent(null)) {
+            logAndPrint(Log.INFO, pw, "USB Gadget HAL HIDL present");
+            return new UsbGadgetHidl(deviceManager, pw);
+        }
+
+        logAndPrint(Log.ERROR, pw, "USB Gadget HAL AIDL/HIDL not present");
+        return null;
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
new file mode 100644
index 0000000..3e5ecc5
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_0;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_1;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_2;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IHwBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbGadgetHidl implements UsbGadgetHal {
+    // Cookie sent for usb gadget hal death notification.
+    private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+    // Proxy object for the usb gadget hal daemon.
+    @GuardedBy("mGadgetProxyLock")
+    private IUsbGadget mGadgetProxy;
+    private UsbDeviceManager mDeviceManager;
+    private final IndentingPrintWriter mPw;
+    // Mutex for all mutable shared state.
+    private final Object mGadgetProxyLock = new Object();
+    private UsbGadgetCallback mUsbGadgetCallback;
+
+    public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+        int version;
+        synchronized(mGadgetProxyLock) {
+            if (mGadgetProxy == null) {
+                throw new RemoteException("IUsbGadget not initialized yet");
+            }
+            if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                version = UsbManager.GADGET_HAL_V1_2;
+            } else if (android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                version = UsbManager.GADGET_HAL_V1_1;
+            } else {
+                version = UsbManager.GADGET_HAL_V1_0;
+            }
+            logAndPrint(Log.INFO, mPw, "USB Gadget HAL HIDL version: " + version);
+            return version;
+        }
+    }
+
+    final class DeathRecipient implements IHwBinder.DeathRecipient {
+        private final IndentingPrintWriter mPw;
+
+        DeathRecipient(IndentingPrintWriter pw) {
+            mPw = pw;
+        }
+
+        @Override
+        public void serviceDied(long cookie) {
+            if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+                logAndPrint(Log.ERROR, mPw, "Usb Gadget hal service died cookie: " + cookie);
+                synchronized (mGadgetProxyLock) {
+                    mGadgetProxy = null;
+                }
+            }
+        }
+    }
+
+    final class ServiceNotification extends IServiceNotification.Stub {
+        @Override
+        public void onRegistration(String fqName, String name, boolean preexisting) {
+            logAndPrint(Log.INFO, mPw, "Usb gadget hal service started " + fqName + " " + name);
+            connectToProxy(null);
+        }
+    }
+
+    private void connectToProxy(IndentingPrintWriter pw) {
+        synchronized (mGadgetProxyLock) {
+            if (mGadgetProxy != null) {
+                return;
+            }
+
+            try {
+                mGadgetProxy = IUsbGadget.getService();
+                mGadgetProxy.linkToDeath(new DeathRecipient(pw), USB_GADGET_HAL_DEATH_COOKIE);
+            } catch (NoSuchElementException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+                        + " Did the service fail to start?", e);
+            } catch (RemoteException e) {
+                logAndPrintException(pw, "connectToProxy: usb gadget hal service not responding"
+                        , e);
+            }
+        }
+    }
+
+    @Override
+    public void systemReady() {
+    }
+
+    static boolean isServicePresent(IndentingPrintWriter pw) {
+        try {
+            IUsbGadget.getService(true);
+        } catch (NoSuchElementException e) {
+            logAndPrintException(pw, "connectToProxy: usb gadget hidl hal service not found.", e);
+            return false;
+        } catch (RemoteException e) {
+            logAndPrintException(pw, "IUSBGadget hal service present but failed to get service", e);
+        }
+
+        return true;
+    }
+
+    public UsbGadgetHidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+        mDeviceManager = Objects.requireNonNull(deviceManager);
+        mPw = pw;
+        try {
+            ServiceNotification serviceNotification = new ServiceNotification();
+
+            boolean ret = IServiceManager.getService()
+                    .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+                            "", serviceNotification);
+            if (!ret) {
+                logAndPrint(Log.ERROR, pw, "Failed to register service start notification");
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(pw, "Failed to register service start notification", e);
+            return;
+        }
+        connectToProxy(mPw);
+    }
+
+    @Override
+    public void getCurrentUsbFunctions(long transactionId) {
+        try {
+            synchronized(mGadgetProxyLock) {
+                mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getCurrentUsbFunctions", e);
+            return;
+        }
+    }
+
+    @Override
+    public void getUsbSpeed(long transactionId) {
+        try {
+            synchronized(mGadgetProxyLock) {
+                if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                    android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+                    android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+                    gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
+                }
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw, "get UsbSpeed failed", e);
+        }
+    }
+
+    @Override
+    public void reset() {
+        try {
+            synchronized(mGadgetProxyLock) {
+                if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+                    android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+                    android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+                    gadgetProxy.reset();
+                }
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling getUsbSpeed", e);
+            return;
+        }
+    }
+
+    @Override
+    public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+            boolean mChargingFunctions, int timeout, long operationId) {
+        try {
+            mUsbGadgetCallback = new UsbGadgetCallback(null, mRequest,
+                                      mFunctions, mChargingFunctions);
+            synchronized(mGadgetProxyLock) {
+                mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback, timeout);
+            }
+        } catch (RemoteException e) {
+            logAndPrintException(mPw,
+                    "RemoteException while calling setCurrentUsbFunctions"
+                    + " mRequest = " + mRequest
+                    + ", mFunctions = " + mFunctions
+                    + ", timeout = " + timeout
+                    + ", mChargingFunctions = " + mChargingFunctions
+                    + ", operationId =" + operationId, e);
+            return;
+        }
+    }
+
+    private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+        public int mRequest;
+        public long mFunctions;
+        public boolean mChargingFunctions;
+
+        UsbGadgetCallback() {
+        }
+        UsbGadgetCallback(IndentingPrintWriter pw, int request,
+                long functions, boolean chargingFunctions) {
+            mRequest = request;
+            mFunctions = functions;
+            mChargingFunctions = chargingFunctions;
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                int status) {
+            mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+                    mRequest, mFunctions, mChargingFunctions);
+        }
+
+        @Override
+        public void getCurrentUsbFunctionsCb(long functions,
+                int status) {
+            mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed) {
+            mDeviceManager.getUsbSpeedCb(speed);
+        }
+    }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
index 128a051..e6a3e53 100644
--- a/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
+++ b/services/usb/java/com/android/server/usb/hal/port/RawPortInfo.java
@@ -40,6 +40,8 @@
     public int usbDataStatus;
     public boolean powerTransferLimited;
     public int powerBrickConnectionStatus;
+    public final boolean supportsComplianceWarnings;
+    public int[] complianceWarnings;
 
     public RawPortInfo(String portId, int supportedModes) {
         this.portId = portId;
@@ -50,9 +52,10 @@
         this.supportsEnableContaminantPresenceDetection = false;
         this.contaminantDetectionStatus = UsbPortStatus.CONTAMINANT_DETECTION_NOT_SUPPORTED;
         this.usbDataStatus = UsbPortStatus.DATA_STATUS_UNKNOWN;
-
         this.powerTransferLimited = false;
         this.powerBrickConnectionStatus = UsbPortStatus.POWER_BRICK_STATUS_UNKNOWN;
+        this.supportsComplianceWarnings = false;
+        this.complianceWarnings = new int[] {};
     }
 
     public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
@@ -66,6 +69,29 @@
             int usbDataStatus,
             boolean powerTransferLimited,
             int powerBrickConnectionStatus) {
+        this(portId, supportedModes, supportedContaminantProtectionModes,
+                    currentMode, canChangeMode,
+                    currentPowerRole, canChangePowerRole,
+                    currentDataRole, canChangeDataRole,
+                    supportsEnableContaminantPresenceProtection, contaminantProtectionStatus,
+                    supportsEnableContaminantPresenceDetection, contaminantDetectionStatus,
+                    usbDataStatus, powerTransferLimited, powerBrickConnectionStatus,
+                    false, new int[] {});
+    }
+
+    public RawPortInfo(String portId, int supportedModes, int supportedContaminantProtectionModes,
+            int currentMode, boolean canChangeMode,
+            int currentPowerRole, boolean canChangePowerRole,
+            int currentDataRole, boolean canChangeDataRole,
+            boolean supportsEnableContaminantPresenceProtection,
+            int contaminantProtectionStatus,
+            boolean supportsEnableContaminantPresenceDetection,
+            int contaminantDetectionStatus,
+            int usbDataStatus,
+            boolean powerTransferLimited,
+            int powerBrickConnectionStatus,
+            boolean supportsComplianceWarnings,
+            int[] complianceWarnings) {
         this.portId = portId;
         this.supportedModes = supportedModes;
         this.supportedContaminantProtectionModes = supportedContaminantProtectionModes;
@@ -84,6 +110,8 @@
         this.usbDataStatus = usbDataStatus;
         this.powerTransferLimited = powerTransferLimited;
         this.powerBrickConnectionStatus = powerBrickConnectionStatus;
+        this.supportsComplianceWarnings = supportsComplianceWarnings;
+        this.complianceWarnings = complianceWarnings;
     }
 
     @Override
@@ -109,6 +137,8 @@
         dest.writeInt(usbDataStatus);
         dest.writeBoolean(powerTransferLimited);
         dest.writeInt(powerBrickConnectionStatus);
+        dest.writeBoolean(supportsComplianceWarnings);
+        dest.writeIntArray(complianceWarnings);
     }
 
     public static final Parcelable.Creator<RawPortInfo> CREATOR =
@@ -131,6 +161,8 @@
             int usbDataStatus = in.readInt();
             boolean powerTransferLimited = in.readBoolean();
             int powerBrickConnectionStatus = in.readInt();
+            boolean supportsComplianceWarnings = in.readBoolean();
+            int[] complianceWarnings = in.createIntArray();
             return new RawPortInfo(id, supportedModes,
                     supportedContaminantProtectionModes, currentMode, canChangeMode,
                     currentPowerRole, canChangePowerRole,
@@ -139,7 +171,8 @@
                     contaminantProtectionStatus,
                     supportsEnableContaminantPresenceDetection,
                     contaminantDetectionStatus, usbDataStatus,
-                    powerTransferLimited, powerBrickConnectionStatus);
+                    powerTransferLimited, powerBrickConnectionStatus,
+                    supportsComplianceWarnings, complianceWarnings);
         }
 
         @Override
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
index 94273a3..ca11629 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortAidl.java
@@ -34,9 +34,12 @@
 import android.hardware.usb.IUsbCallback;
 import android.hardware.usb.PortRole;
 import android.hardware.usb.PortStatus;
+import android.hardware.usb.ComplianceWarning;
+import android.os.Build;
 import android.os.ServiceManager;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Slog;
@@ -46,6 +49,7 @@
 import com.android.server.usb.UsbPortManager;
 import com.android.server.usb.hal.port.RawPortInfo;
 
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.NoSuchElementException;
@@ -551,6 +555,24 @@
             return usbDataStatus;
         }
 
+        private int[] formatComplianceWarnings(int[] complianceWarnings) {
+            Objects.requireNonNull(complianceWarnings);
+            IntArray newComplianceWarnings = new IntArray();
+            Arrays.sort(complianceWarnings);
+            for (int warning : complianceWarnings) {
+                if (newComplianceWarnings.indexOf(warning) == -1
+                        && warning >= UsbPortStatus.COMPLIANCE_WARNING_OTHER) {
+                    // ComplianceWarnings range from [1, 4] in Android U
+                    if (warning > UsbPortStatus.COMPLIANCE_WARNING_MISSING_RP) {
+                        newComplianceWarnings.add(UsbPortStatus.COMPLIANCE_WARNING_OTHER);
+                    } else {
+                        newComplianceWarnings.add(warning);
+                    }
+                }
+            }
+            return newComplianceWarnings.toArray();
+        }
+
         @Override
         public void notifyPortStatusChange(
                android.hardware.usb.PortStatus[] currentPortStatus, int retval) {
@@ -584,7 +606,9 @@
                         current.contaminantDetectionStatus,
                         toUsbDataStatusInt(current.usbDataStatus),
                         current.powerTransferLimited,
-                        current.powerBrickStatus);
+                        current.powerBrickStatus,
+                        current.supportsComplianceWarnings,
+                        formatComplianceWarnings(current.complianceWarnings));
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback AIDL V1: "
                         + current.portName);
diff --git a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
index 23d913c..10403c1 100644
--- a/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
+++ b/services/usb/java/com/android/server/usb/hal/port/UsbPortHidl.java
@@ -421,7 +421,8 @@
                         current.currentDataRole, current.canChangeDataRole,
                         false, CONTAMINANT_PROTECTION_NONE,
                         false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
-                        false, POWER_BRICK_STATUS_UNKNOWN);
+                        false, POWER_BRICK_STATUS_UNKNOWN,
+                        false, new int[] {});
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_0: "
                         + current.portName);
@@ -455,7 +456,8 @@
                         current.status.currentDataRole, current.status.canChangeDataRole,
                         false, CONTAMINANT_PROTECTION_NONE,
                         false, CONTAMINANT_DETECTION_NOT_SUPPORTED, sUsbDataStatus,
-                        false, POWER_BRICK_STATUS_UNKNOWN);
+                        false, POWER_BRICK_STATUS_UNKNOWN,
+                        false, new int[] {});
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_1: "
                         + current.status.portName);
@@ -493,7 +495,8 @@
                         current.supportsEnableContaminantPresenceDetection,
                         current.contaminantDetectionStatus,
                         sUsbDataStatus,
-                        false, POWER_BRICK_STATUS_UNKNOWN);
+                        false, POWER_BRICK_STATUS_UNKNOWN,
+                        false, new int[] {});
                 newPortInfo.add(temp);
                 UsbPortManager.logAndPrint(Log.INFO, mPw, "ClientCallback V1_2: "
                         + current.status_1_1.status.portName);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
new file mode 100644
index 0000000..81cd194
--- /dev/null
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamCopier.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.voiceinteraction;
+
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.service.voice.HotwordAudioStream.KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES;
+
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION;
+import static com.android.internal.util.FrameworkStatsLog.HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START;
+import static com.android.server.voiceinteraction.HotwordDetectionConnection.DEBUG;
+
+import android.annotation.NonNull;
+import android.app.AppOpsManager;
+import android.os.ParcelFileDescriptor;
+import android.os.PersistableBundle;
+import android.service.voice.HotwordAudioStream;
+import android.service.voice.HotwordDetectedResult;
+import android.util.Slog;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Copies the audio streams in {@link HotwordDetectedResult}s. This allows the system to manage the
+ * lifetime of the {@link ParcelFileDescriptor}s and ensures that the flow of data is in the right
+ * direction from the {@link android.service.voice.HotwordDetectionService} to the client (i.e., the
+ * voice interactor).
+ *
+ * @hide
+ */
+final class HotwordAudioStreamCopier {
+
+    private static final String TAG = "HotwordAudioStreamCopier";
+    private static final String OP_MESSAGE = "Streaming hotword audio to VoiceInteractionService";
+    private static final String TASK_ID_PREFIX = "HotwordDetectedResult@";
+    private static final String THREAD_NAME_PREFIX = "Copy-";
+    private static final int DEFAULT_COPY_BUFFER_LENGTH_BYTES = 2_560;
+
+    // Corresponds to the OS pipe capacity in bytes
+    private static final int MAX_COPY_BUFFER_LENGTH_BYTES = 65_536;
+
+    private final AppOpsManager mAppOpsManager;
+    private final int mDetectorType;
+    private final int mVoiceInteractorUid;
+    private final String mVoiceInteractorPackageName;
+    private final String mVoiceInteractorAttributionTag;
+    private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
+
+    HotwordAudioStreamCopier(@NonNull AppOpsManager appOpsManager, int detectorType,
+            int voiceInteractorUid, @NonNull String voiceInteractorPackageName,
+            @NonNull String voiceInteractorAttributionTag) {
+        mAppOpsManager = appOpsManager;
+        mDetectorType = detectorType;
+        mVoiceInteractorUid = voiceInteractorUid;
+        mVoiceInteractorPackageName = voiceInteractorPackageName;
+        mVoiceInteractorAttributionTag = voiceInteractorAttributionTag;
+    }
+
+    /**
+     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
+     * <p>
+     * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
+     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
+     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamCopier}. The
+     * returned value should be passed on to the client (i.e., the voice interactor).
+     * </p>
+     *
+     * @throws IOException If there was an error creating the managed pipe.
+     */
+    @NonNull
+    public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result)
+            throws IOException {
+        List<HotwordAudioStream> audioStreams = result.getAudioStreams();
+        if (audioStreams.isEmpty()) {
+            HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                    HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_EMPTY_AUDIO_STREAM_LIST,
+                    mVoiceInteractorUid);
+            return result;
+        }
+
+        List<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size());
+        List<CopyTaskInfo> copyTaskInfos = new ArrayList<>(audioStreams.size());
+        for (HotwordAudioStream audioStream : audioStreams) {
+            ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe();
+            ParcelFileDescriptor clientAudioSource = clientPipe[0];
+            ParcelFileDescriptor clientAudioSink = clientPipe[1];
+            HotwordAudioStream newAudioStream =
+                    audioStream.buildUpon().setAudioStreamParcelFileDescriptor(
+                            clientAudioSource).build();
+            newAudioStreams.add(newAudioStream);
+
+            int copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES;
+            PersistableBundle metadata = audioStream.getMetadata();
+            if (metadata.containsKey(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES)) {
+                copyBufferLength = metadata.getInt(KEY_AUDIO_STREAM_COPY_BUFFER_LENGTH_BYTES, -1);
+                if (copyBufferLength < 1 || copyBufferLength > MAX_COPY_BUFFER_LENGTH_BYTES) {
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_ILLEGAL_COPY_BUFFER_SIZE,
+                            mVoiceInteractorUid);
+                    Slog.w(TAG, "Attempted to set an invalid copy buffer length ("
+                            + copyBufferLength + ") for: " + audioStream);
+                    copyBufferLength = DEFAULT_COPY_BUFFER_LENGTH_BYTES;
+                } else if (DEBUG) {
+                    Slog.i(TAG, "Copy buffer length set to " + copyBufferLength + " for: "
+                            + audioStream);
+                }
+            }
+
+            ParcelFileDescriptor serviceAudioSource =
+                    audioStream.getAudioStreamParcelFileDescriptor();
+            copyTaskInfos.add(new CopyTaskInfo(serviceAudioSource, clientAudioSink,
+                    copyBufferLength));
+        }
+
+        String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result);
+        mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, copyTaskInfos));
+
+        return result.buildUpon().setAudioStreams(newAudioStreams).build();
+    }
+
+    private static class CopyTaskInfo {
+        private final ParcelFileDescriptor mSource;
+        private final ParcelFileDescriptor mSink;
+        private final int mCopyBufferLength;
+
+        CopyTaskInfo(ParcelFileDescriptor source, ParcelFileDescriptor sink, int copyBufferLength) {
+            mSource = source;
+            mSink = sink;
+            mCopyBufferLength = copyBufferLength;
+        }
+    }
+
+    private class HotwordDetectedResultCopyTask implements Runnable {
+        private final String mResultTaskId;
+        private final List<CopyTaskInfo> mCopyTaskInfos;
+        private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
+
+        HotwordDetectedResultCopyTask(String resultTaskId, List<CopyTaskInfo> copyTaskInfos) {
+            mResultTaskId = resultTaskId;
+            mCopyTaskInfos = copyTaskInfos;
+        }
+
+        @Override
+        public void run() {
+            Thread.currentThread().setName(THREAD_NAME_PREFIX + mResultTaskId);
+            int size = mCopyTaskInfos.size();
+            List<SingleAudioStreamCopyTask> tasks = new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                CopyTaskInfo copyTaskInfo = mCopyTaskInfos.get(i);
+                String streamTaskId = mResultTaskId + "@" + i;
+                tasks.add(new SingleAudioStreamCopyTask(streamTaskId, copyTaskInfo.mSource,
+                        copyTaskInfo.mSink, copyTaskInfo.mCopyBufferLength, mDetectorType,
+                        mVoiceInteractorUid));
+            }
+
+            if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                    mVoiceInteractorUid, mVoiceInteractorPackageName,
+                    mVoiceInteractorAttributionTag, OP_MESSAGE) == MODE_ALLOWED) {
+                try {
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_START,
+                            mVoiceInteractorUid);
+                    // TODO(b/244599891): Set timeout, close after inactivity
+                    mExecutorService.invokeAll(tasks);
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_END, mVoiceInteractorUid);
+                } catch (InterruptedException e) {
+                    HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                            HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_INTERRUPTED_EXCEPTION,
+                            mVoiceInteractorUid);
+                    Slog.e(TAG, mResultTaskId + ": Task was interrupted", e);
+                    bestEffortPropagateError(e.getMessage());
+                } finally {
+                    mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
+                            mVoiceInteractorUid, mVoiceInteractorPackageName,
+                            mVoiceInteractorAttributionTag);
+                }
+            } else {
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_NO_PERMISSION,
+                        mVoiceInteractorUid);
+                bestEffortPropagateError(
+                        "Failed to obtain RECORD_AUDIO_HOTWORD permission for voice interactor with"
+                                + " uid=" + mVoiceInteractorUid
+                                + " packageName=" + mVoiceInteractorPackageName
+                                + " attributionTag=" + mVoiceInteractorAttributionTag);
+            }
+        }
+
+        private void bestEffortPropagateError(@NonNull String errorMessage) {
+            try {
+                for (CopyTaskInfo copyTaskInfo : mCopyTaskInfos) {
+                    copyTaskInfo.mSource.closeWithError(errorMessage);
+                    copyTaskInfo.mSink.closeWithError(errorMessage);
+                }
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM,
+                        mVoiceInteractorUid);
+            } catch (IOException e) {
+                Slog.e(TAG, mResultTaskId + ": Failed to propagate error", e);
+            }
+        }
+    }
+
+    private static class SingleAudioStreamCopyTask implements Callable<Void> {
+        private final String mStreamTaskId;
+        private final ParcelFileDescriptor mAudioSource;
+        private final ParcelFileDescriptor mAudioSink;
+        private final int mCopyBufferLength;
+
+        private final int mDetectorType;
+        private final int mUid;
+
+        SingleAudioStreamCopyTask(String streamTaskId, ParcelFileDescriptor audioSource,
+                ParcelFileDescriptor audioSink, int copyBufferLength, int detectorType, int uid) {
+            mStreamTaskId = streamTaskId;
+            mAudioSource = audioSource;
+            mAudioSink = audioSink;
+            mCopyBufferLength = copyBufferLength;
+            mDetectorType = detectorType;
+            mUid = uid;
+        }
+
+        @Override
+        public Void call() throws Exception {
+            Thread.currentThread().setName(THREAD_NAME_PREFIX + mStreamTaskId);
+
+            // Note: We are intentionally NOT using try-with-resources here. If we did,
+            // the ParcelFileDescriptors will be automatically closed WITHOUT errors before we go
+            // into the IOException-catch block. We want to propagate the error while closing the
+            // PFDs.
+            InputStream fis = null;
+            OutputStream fos = null;
+            try {
+                fis = new ParcelFileDescriptor.AutoCloseInputStream(mAudioSource);
+                fos = new ParcelFileDescriptor.AutoCloseOutputStream(mAudioSink);
+                byte[] buffer = new byte[mCopyBufferLength];
+                while (true) {
+                    if (Thread.interrupted()) {
+                        Slog.e(TAG,
+                                mStreamTaskId + ": SingleAudioStreamCopyTask task was interrupted");
+                        break;
+                    }
+
+                    int bytesRead = fis.read(buffer);
+                    if (bytesRead < 0) {
+                        Slog.i(TAG, mStreamTaskId + ": Reached end of audio stream");
+                        break;
+                    }
+                    if (bytesRead > 0) {
+                        if (DEBUG) {
+                            // TODO(b/244599440): Add proper logging
+                            Slog.d(TAG, mStreamTaskId + ": Copied " + bytesRead
+                                    + " bytes from audio stream. First 20 bytes=" + Arrays.toString(
+                                    Arrays.copyOfRange(buffer, 0, 20)));
+                        }
+                        fos.write(buffer, 0, bytesRead);
+                    }
+                    // TODO(b/244599891): Close PFDs after inactivity
+                }
+            } catch (IOException e) {
+                mAudioSource.closeWithError(e.getMessage());
+                mAudioSink.closeWithError(e.getMessage());
+                Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e);
+                HotwordMetricsLogger.writeDetectorEvent(mDetectorType,
+                        HOTWORD_DETECTOR_EVENTS__EVENT__AUDIO_EGRESS_CLOSE_ERROR_FROM_SYSTEM, mUid);
+            } finally {
+                if (fis != null) {
+                    fis.close();
+                }
+                if (fos != null) {
+                    fos.close();
+                }
+            }
+
+            return null;
+        }
+    }
+
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamManager.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamManager.java
deleted file mode 100644
index d5eea1f..0000000
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordAudioStreamManager.java
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.voiceinteraction;
-
-import static android.app.AppOpsManager.MODE_ALLOWED;
-
-import static com.android.server.voiceinteraction.HotwordDetectionConnection.DEBUG;
-
-import android.annotation.NonNull;
-import android.app.AppOpsManager;
-import android.media.permission.Identity;
-import android.os.ParcelFileDescriptor;
-import android.service.voice.HotwordAudioStream;
-import android.service.voice.HotwordDetectedResult;
-import android.util.Pair;
-import android.util.Slog;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-final class HotwordAudioStreamManager {
-
-    private static final String TAG = "HotwordAudioStreamManager";
-    private static final String OP_MESSAGE = "Streaming hotword audio to VoiceInteractionService";
-    private static final String TASK_ID_PREFIX = "HotwordDetectedResult@";
-    private static final String THREAD_NAME_PREFIX = "Copy-";
-
-    private final AppOpsManager mAppOpsManager;
-    private final Identity mVoiceInteractorIdentity;
-    private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
-
-    HotwordAudioStreamManager(@NonNull AppOpsManager appOpsManager,
-            @NonNull Identity voiceInteractorIdentity) {
-        mAppOpsManager = appOpsManager;
-        mVoiceInteractorIdentity = voiceInteractorIdentity;
-    }
-
-    /**
-     * Starts copying the audio streams in the given {@link HotwordDetectedResult}.
-     * <p>
-     * The returned {@link HotwordDetectedResult} is identical the one that was passed in, except
-     * that the {@link ParcelFileDescriptor}s within {@link HotwordDetectedResult#getAudioStreams()}
-     * are replaced with descriptors from pipes managed by {@link HotwordAudioStreamManager}. The
-     * returned value should be passed on to the client (i.e., the voice interactor).
-     * </p>
-     *
-     * @throws IOException If there was an error creating the managed pipe.
-     */
-    @NonNull
-    public HotwordDetectedResult startCopyingAudioStreams(@NonNull HotwordDetectedResult result)
-            throws IOException {
-        List<HotwordAudioStream> audioStreams = result.getAudioStreams();
-        if (audioStreams.isEmpty()) {
-            return result;
-        }
-
-        List<HotwordAudioStream> newAudioStreams = new ArrayList<>(audioStreams.size());
-        List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> sourcesAndSinks = new ArrayList<>(
-                audioStreams.size());
-        for (HotwordAudioStream audioStream : audioStreams) {
-            ParcelFileDescriptor[] clientPipe = ParcelFileDescriptor.createReliablePipe();
-            ParcelFileDescriptor clientAudioSource = clientPipe[0];
-            ParcelFileDescriptor clientAudioSink = clientPipe[1];
-            HotwordAudioStream newAudioStream =
-                    audioStream.buildUpon().setAudioStreamParcelFileDescriptor(
-                            clientAudioSource).build();
-            newAudioStreams.add(newAudioStream);
-
-            ParcelFileDescriptor serviceAudioSource =
-                    audioStream.getAudioStreamParcelFileDescriptor();
-            sourcesAndSinks.add(new Pair<>(serviceAudioSource, clientAudioSink));
-        }
-
-        String resultTaskId = TASK_ID_PREFIX + System.identityHashCode(result);
-        mExecutorService.execute(new HotwordDetectedResultCopyTask(resultTaskId, sourcesAndSinks));
-
-        return result.buildUpon().setAudioStreams(newAudioStreams).build();
-    }
-
-    private class HotwordDetectedResultCopyTask implements Runnable {
-        private final String mResultTaskId;
-        private final List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> mSourcesAndSinks;
-        private final ExecutorService mExecutorService = Executors.newCachedThreadPool();
-
-        HotwordDetectedResultCopyTask(String resultTaskId,
-                List<Pair<ParcelFileDescriptor, ParcelFileDescriptor>> sourcesAndSinks) {
-            mResultTaskId = resultTaskId;
-            mSourcesAndSinks = sourcesAndSinks;
-        }
-
-        @Override
-        public void run() {
-            Thread.currentThread().setName(THREAD_NAME_PREFIX + mResultTaskId);
-            int size = mSourcesAndSinks.size();
-            List<SingleAudioStreamCopyTask> tasks = new ArrayList<>(size);
-            for (int i = 0; i < size; i++) {
-                Pair<ParcelFileDescriptor, ParcelFileDescriptor> sourceAndSink =
-                        mSourcesAndSinks.get(i);
-                ParcelFileDescriptor serviceAudioSource = sourceAndSink.first;
-                ParcelFileDescriptor clientAudioSink = sourceAndSink.second;
-                String streamTaskId = mResultTaskId + "@" + i;
-                tasks.add(new SingleAudioStreamCopyTask(streamTaskId, serviceAudioSource,
-                        clientAudioSink));
-            }
-
-            if (mAppOpsManager.startOpNoThrow(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                    mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName,
-                    mVoiceInteractorIdentity.attributionTag, OP_MESSAGE) == MODE_ALLOWED) {
-                try {
-                    // TODO(b/244599891): Set timeout, close after inactivity
-                    mExecutorService.invokeAll(tasks);
-                } catch (InterruptedException e) {
-                    Slog.e(TAG, mResultTaskId + ": Task was interrupted", e);
-                    bestEffortPropagateError(e.getMessage());
-                } finally {
-                    mAppOpsManager.finishOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD,
-                            mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName,
-                            mVoiceInteractorIdentity.attributionTag);
-                }
-            } else {
-                bestEffortPropagateError(
-                        "Failed to obtain RECORD_AUDIO_HOTWORD permission for "
-                                + SoundTriggerSessionPermissionsDecorator.toString(
-                                mVoiceInteractorIdentity));
-            }
-        }
-
-        private void bestEffortPropagateError(@NonNull String errorMessage) {
-            try {
-                for (Pair<ParcelFileDescriptor, ParcelFileDescriptor> sourceAndSink :
-                        mSourcesAndSinks) {
-                    ParcelFileDescriptor serviceAudioSource = sourceAndSink.first;
-                    ParcelFileDescriptor clientAudioSink = sourceAndSink.second;
-                    serviceAudioSource.closeWithError(errorMessage);
-                    clientAudioSink.closeWithError(errorMessage);
-                }
-            } catch (IOException e) {
-                Slog.e(TAG, mResultTaskId + ": Failed to propagate error", e);
-            }
-        }
-    }
-
-    private static class SingleAudioStreamCopyTask implements Callable<Void> {
-        // TODO: Make this buffer size customizable from updateState()
-        private static final int COPY_BUFFER_LENGTH = 2_560;
-
-        private final String mStreamTaskId;
-        private final ParcelFileDescriptor mAudioSource;
-        private final ParcelFileDescriptor mAudioSink;
-
-        SingleAudioStreamCopyTask(String streamTaskId, ParcelFileDescriptor audioSource,
-                ParcelFileDescriptor audioSink) {
-            mStreamTaskId = streamTaskId;
-            mAudioSource = audioSource;
-            mAudioSink = audioSink;
-        }
-
-        @Override
-        public Void call() throws Exception {
-            Thread.currentThread().setName(THREAD_NAME_PREFIX + mStreamTaskId);
-
-            // Note: We are intentionally NOT using try-with-resources here. If we did,
-            // the ParcelFileDescriptors will be automatically closed WITHOUT errors before we go
-            // into the IOException-catch block. We want to propagate the error while closing the
-            // PFDs.
-            InputStream fis = null;
-            OutputStream fos = null;
-            try {
-                fis = new ParcelFileDescriptor.AutoCloseInputStream(mAudioSource);
-                fos = new ParcelFileDescriptor.AutoCloseOutputStream(mAudioSink);
-                byte[] buffer = new byte[COPY_BUFFER_LENGTH];
-                while (true) {
-                    if (Thread.interrupted()) {
-                        Slog.e(TAG,
-                                mStreamTaskId + ": SingleAudioStreamCopyTask task was interrupted");
-                        break;
-                    }
-
-                    int bytesRead = fis.read(buffer);
-                    if (bytesRead < 0) {
-                        Slog.i(TAG, mStreamTaskId + ": Reached end of audio stream");
-                        break;
-                    }
-                    if (bytesRead > 0) {
-                        if (DEBUG) {
-                            // TODO(b/244599440): Add proper logging
-                            Slog.d(TAG, mStreamTaskId + ": Copied " + bytesRead
-                                    + " bytes from audio stream. First 20 bytes=" + Arrays.toString(
-                                    Arrays.copyOfRange(buffer, 0, 20)));
-                        }
-                        fos.write(buffer, 0, bytesRead);
-                    }
-                    // TODO(b/244599891): Close PFDs after inactivity
-                }
-            } catch (IOException e) {
-                mAudioSource.closeWithError(e.getMessage());
-                mAudioSink.closeWithError(e.getMessage());
-                Slog.e(TAG, mStreamTaskId + ": Failed to copy audio stream", e);
-            } finally {
-                if (fis != null) {
-                    fis.close();
-                }
-                if (fos != null) {
-                    fos.close();
-                }
-            }
-
-            return null;
-        }
-    }
-
-}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index 4151663..2ac25b6 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -183,7 +183,7 @@
     private final ScheduledExecutorService mScheduledExecutorService =
             Executors.newSingleThreadScheduledExecutor();
     private final AppOpsManager mAppOpsManager;
-    private final HotwordAudioStreamManager mHotwordAudioStreamManager;
+    private final HotwordAudioStreamCopier mHotwordAudioStreamCopier;
     @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
     private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
     private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
@@ -245,8 +245,9 @@
         mVoiceInteractionServiceUid = voiceInteractionServiceUid;
         mVoiceInteractorIdentity = voiceInteractorIdentity;
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
-        mHotwordAudioStreamManager = new HotwordAudioStreamManager(mAppOpsManager,
-                mVoiceInteractorIdentity);
+        mHotwordAudioStreamCopier = new HotwordAudioStreamCopier(mAppOpsManager, detectorType,
+                mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName,
+                mVoiceInteractorIdentity.attributionTag);
         mDetectionComponentName = serviceName;
         mUser = userId;
         mCallback = callback;
@@ -506,7 +507,7 @@
                     saveProximityValueToBundle(result);
                     HotwordDetectedResult newResult;
                     try {
-                        newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result);
+                        newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
                     } catch (IOException e) {
                         // TODO: Write event
                         mSoftwareCallback.onError();
@@ -641,7 +642,7 @@
                     saveProximityValueToBundle(result);
                     HotwordDetectedResult newResult;
                     try {
-                        newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result);
+                        newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
                     } catch (IOException e) {
                         // TODO: Write event
                         externalCallback.onError(CALLBACK_ONDETECTED_STREAM_COPY_ERROR);
@@ -1000,7 +1001,7 @@
                                     HotwordDetectedResult newResult;
                                     try {
                                         newResult =
-                                                mHotwordAudioStreamManager.startCopyingAudioStreams(
+                                                mHotwordAudioStreamCopier.startCopyingAudioStreams(
                                                         triggerResult);
                                     } catch (IOException e) {
                                         // TODO: Write event
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/TrustedHotwordDetectorSession.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/TrustedHotwordDetectorSession.java
index b87b8f7..02f5889 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/TrustedHotwordDetectorSession.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/TrustedHotwordDetectorSession.java
@@ -183,7 +183,7 @@
     private final ScheduledExecutorService mScheduledExecutorService =
             Executors.newSingleThreadScheduledExecutor();
     private final AppOpsManager mAppOpsManager;
-    private final HotwordAudioStreamManager mHotwordAudioStreamManager;
+    private final HotwordAudioStreamCopier mHotwordAudioStreamCopier;
     @Nullable private final ScheduledFuture<?> mCancellationTaskFuture;
     private final AtomicBoolean mUpdateStateAfterStartFinished = new AtomicBoolean(false);
     private final IBinder.DeathRecipient mAudioServerDeathRecipient = this::audioServerDied;
@@ -245,8 +245,9 @@
         mVoiceInteractionServiceUid = voiceInteractionServiceUid;
         mVoiceInteractorIdentity = voiceInteractorIdentity;
         mAppOpsManager = mContext.getSystemService(AppOpsManager.class);
-        mHotwordAudioStreamManager = new HotwordAudioStreamManager(mAppOpsManager,
-                mVoiceInteractorIdentity);
+        mHotwordAudioStreamCopier = new HotwordAudioStreamCopier(mAppOpsManager, detectorType,
+                mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName,
+                mVoiceInteractorIdentity.attributionTag);
         mDetectionComponentName = serviceName;
         mUser = userId;
         mCallback = callback;
@@ -506,7 +507,7 @@
                     saveProximityValueToBundle(result);
                     HotwordDetectedResult newResult;
                     try {
-                        newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result);
+                        newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
                     } catch (IOException e) {
                         // TODO: Write event
                         mSoftwareCallback.onError();
@@ -641,7 +642,7 @@
                     saveProximityValueToBundle(result);
                     HotwordDetectedResult newResult;
                     try {
-                        newResult = mHotwordAudioStreamManager.startCopyingAudioStreams(result);
+                        newResult = mHotwordAudioStreamCopier.startCopyingAudioStreams(result);
                     } catch (IOException e) {
                         // TODO: Write event
                         externalCallback.onError(CALLBACK_ONDETECTED_STREAM_COPY_ERROR);
@@ -1000,7 +1001,7 @@
                                     HotwordDetectedResult newResult;
                                     try {
                                         newResult =
-                                                mHotwordAudioStreamManager.startCopyingAudioStreams(
+                                                mHotwordAudioStreamCopier.startCopyingAudioStreams(
                                                         triggerResult);
                                     } catch (IOException e) {
                                         // TODO: Write event
diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING
deleted file mode 100644
index 791e471..0000000
--- a/startop/view_compiler/TEST_MAPPING
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "presubmit": [
-    {
-      "name": "dex-builder-test"
-    },
-    {
-      "name": "CtsViewTestCases",
-      "options": [
-        {
-          "include-filter": "android.view.cts.PrecompiledLayoutTest"
-        }
-      ]
-    }
-  ]
-}
diff --git a/startop/view_compiler/apk_layout_compiler.cc b/startop/view_compiler/apk_layout_compiler.cc
index 5cb0c17..1d3b6481 100644
--- a/startop/view_compiler/apk_layout_compiler.cc
+++ b/startop/view_compiler/apk_layout_compiler.cc
@@ -100,56 +100,60 @@
       dex_file.MakeClass(StringPrintf("%s.CompiledView", package_name.c_str()))};
   std::vector<dex::MethodBuilder> methods;
 
-  assets->GetAssetsProvider()->ForEachFile("res/", [&](const android::StringPiece& s,
-                                                       android::FileType) {
-    if (s == "layout") {
-      auto path = StringPrintf("res/%s/", s.to_string().c_str());
-      assets->GetAssetsProvider()->ForEachFile(path, [&](const android::StringPiece& layout_file,
-                                                         android::FileType) {
-        auto layout_path = StringPrintf("%s%s", path.c_str(), layout_file.to_string().c_str());
-        android::ApkAssetsCookie cookie = android::kInvalidCookie;
-        auto asset = resources.OpenNonAsset(layout_path, android::Asset::ACCESS_RANDOM, &cookie);
-        CHECK(asset);
-        CHECK(android::kInvalidCookie != cookie);
-        const auto dynamic_ref_table = resources.GetDynamicRefTableForCookie(cookie);
-        CHECK(nullptr != dynamic_ref_table);
-        android::ResXMLTree xml_tree{dynamic_ref_table};
-        xml_tree.setTo(asset->getBuffer(/*wordAligned=*/true),
-                       asset->getLength(),
-                       /*copy_data=*/true);
-        android::ResXMLParser parser{xml_tree};
-        parser.restart();
-        if (CanCompileLayout(&parser)) {
-          parser.restart();
-          const std::string layout_name = startop::util::FindLayoutNameFromFilename(layout_path);
-          ResXmlVisitorAdapter adapter{&parser};
-          switch (target) {
-            case CompilationTarget::kDex: {
-              methods.push_back(compiled_view.CreateMethod(
-                  layout_name,
-                  dex::Prototype{dex::TypeDescriptor::FromClassname("android.view.View"),
-                                 dex::TypeDescriptor::FromClassname("android.content.Context"),
-                                 dex::TypeDescriptor::Int()}));
-              DexViewBuilder builder(&methods.back());
-              builder.Start();
-              LayoutCompilerVisitor visitor{&builder};
-              adapter.Accept(&visitor);
-              builder.Finish();
-              methods.back().Encode();
-              break;
-            }
-            case CompilationTarget::kJavaLanguage: {
-              JavaLangViewBuilder builder{package_name, layout_name, target_out};
-              builder.Start();
-              LayoutCompilerVisitor visitor{&builder};
-              adapter.Accept(&visitor);
-              builder.Finish();
-              break;
-            }
-          }
-        }
-      });
-    }
+  assets->GetAssetsProvider()->ForEachFile("res/", [&](android::StringPiece s, android::FileType) {
+      if (s == "layout") {
+          auto path = StringPrintf("res/%.*s/", (int)s.size(), s.data());
+          assets->GetAssetsProvider()
+                  ->ForEachFile(path, [&](android::StringPiece layout_file, android::FileType) {
+                      auto layout_path = StringPrintf("%s%.*s", path.c_str(),
+                                                      (int)layout_file.size(), layout_file.data());
+                      android::ApkAssetsCookie cookie = android::kInvalidCookie;
+                      auto asset = resources.OpenNonAsset(layout_path,
+                                                          android::Asset::ACCESS_RANDOM, &cookie);
+                      CHECK(asset);
+                      CHECK(android::kInvalidCookie != cookie);
+                      const auto dynamic_ref_table = resources.GetDynamicRefTableForCookie(cookie);
+                      CHECK(nullptr != dynamic_ref_table);
+                      android::ResXMLTree xml_tree{dynamic_ref_table};
+                      xml_tree.setTo(asset->getBuffer(/*wordAligned=*/true), asset->getLength(),
+                                     /*copy_data=*/true);
+                      android::ResXMLParser parser{xml_tree};
+                      parser.restart();
+                      if (CanCompileLayout(&parser)) {
+                          parser.restart();
+                          const std::string layout_name =
+                                  startop::util::FindLayoutNameFromFilename(layout_path);
+                          ResXmlVisitorAdapter adapter{&parser};
+                          switch (target) {
+                              case CompilationTarget::kDex: {
+                                  methods.push_back(compiled_view.CreateMethod(
+                                          layout_name,
+                                          dex::Prototype{dex::TypeDescriptor::FromClassname(
+                                                                 "android.view.View"),
+                                                         dex::TypeDescriptor::FromClassname(
+                                                                 "android.content.Context"),
+                                                         dex::TypeDescriptor::Int()}));
+                                  DexViewBuilder builder(&methods.back());
+                                  builder.Start();
+                                  LayoutCompilerVisitor visitor{&builder};
+                                  adapter.Accept(&visitor);
+                                  builder.Finish();
+                                  methods.back().Encode();
+                                  break;
+                              }
+                              case CompilationTarget::kJavaLanguage: {
+                                  JavaLangViewBuilder builder{package_name, layout_name,
+                                                              target_out};
+                                  builder.Start();
+                                  LayoutCompilerVisitor visitor{&builder};
+                                  adapter.Accept(&visitor);
+                                  builder.Finish();
+                                  break;
+                              }
+                          }
+                      }
+                  });
+      }
   });
 
   if (target == CompilationTarget::kDex) {
diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java
index f848c40..a9cdf7e 100644
--- a/telephony/common/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/common/com/android/internal/telephony/SmsApplication.java
@@ -210,6 +210,15 @@
     }
 
     /**
+     * Returns the userHandle of the current process, if called from a system app,
+     * otherwise it returns the caller's userHandle
+     * @return userHandle of the caller.
+     */
+    private static UserHandle getIncomingUserHandle() {
+        return UserHandle.of(getIncomingUserId());
+    }
+
+    /**
      * Returns the list of available SMS apps defined as apps that are registered for both the
      * SMS_RECEIVED_ACTION (SMS) and WAP_PUSH_RECEIVED_ACTION (MMS) broadcasts (and their broadcast
      * receivers are enabled)
@@ -951,24 +960,28 @@
      */
     @UnsupportedAppUsage
     public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
-        return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultSmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default SMS application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver SMS messages to
      */
-    @VisibleForTesting
     public static ComponentName getDefaultSmsApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mSmsReceiverClass);
@@ -987,23 +1000,28 @@
      */
     @UnsupportedAppUsage
     public static ComponentName getDefaultMmsApplication(Context context, boolean updateIfNeeded) {
-        return getDefaultMmsApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultMmsApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default MMS application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured.
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver MMS messages to.
      */
     public static ComponentName getDefaultMmsApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mMmsReceiverClass);
@@ -1024,23 +1042,28 @@
     public static ComponentName getDefaultRespondViaMessageApplication(Context context,
             boolean updateIfNeeded) {
         return getDefaultRespondViaMessageApplicationAsUser(context, updateIfNeeded,
-                getIncomingUserId());
+                getIncomingUserHandle());
     }
 
     /**
      * Gets the default Respond Via Message application on a given user
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to direct Respond Via Message intent to
      */
     public static ComponentName getDefaultRespondViaMessageApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
                         smsApplicationData.mRespondViaMessageClass);
@@ -1062,6 +1085,7 @@
     public static ComponentName getDefaultSendToApplication(Context context,
             boolean updateIfNeeded) {
         int userId = getIncomingUserId();
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
@@ -1087,7 +1111,7 @@
     public static ComponentName getDefaultExternalTelephonyProviderChangedApplication(
             Context context, boolean updateIfNeeded) {
         return getDefaultExternalTelephonyProviderChangedApplicationAsUser(context, updateIfNeeded,
-                getIncomingUserId());
+                getIncomingUserHandle());
     }
 
     /**
@@ -1095,16 +1119,21 @@
      * MmsProvider on a given user.
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver change intents to.
      */
     public static ComponentName getDefaultExternalTelephonyProviderChangedApplicationAsUser(
-            Context context, boolean updateIfNeeded, int userId) {
+            Context context, boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null
                     && smsApplicationData.mProviderChangedReceiverClass != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
@@ -1124,23 +1153,28 @@
      */
     public static ComponentName getDefaultSimFullApplication(
             Context context, boolean updateIfNeeded) {
-        return getDefaultSimFullApplicationAsUser(context, updateIfNeeded, getIncomingUserId());
+        return getDefaultSimFullApplicationAsUser(context, updateIfNeeded, getIncomingUserHandle());
     }
 
     /**
      * Gets the default application that handles sim full event on a given user.
      * @param context context from the calling app
      * @param updateIfNeeded update the default app if there is no valid default app configured
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return component name of the app and class to deliver change intents to
      */
     public static ComponentName getDefaultSimFullApplicationAsUser(Context context,
-            boolean updateIfNeeded, int userId) {
+            boolean updateIfNeeded, @Nullable UserHandle userHandle) {
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         final long token = Binder.clearCallingIdentity();
         try {
             ComponentName component = null;
             SmsApplicationData smsApplicationData = getApplication(context, updateIfNeeded,
-                    userId);
+                    userHandle.getIdentifier());
             if (smsApplicationData != null
                     && smsApplicationData.mSimFullReceiverClass != null) {
                 component = new ComponentName(smsApplicationData.mPackageName,
@@ -1153,19 +1187,35 @@
     }
 
     /**
-     * Returns whether need to wrgetIncomingUserIdite the SMS message to SMS database for this
-     * package.
+     * Returns whether it is required to write the SMS message to SMS database for this package.
+     *
+     * @param packageName the name of the package to be checked
+     * @param context context from the calling app
+     * @return true if it is required to write SMS message to SMS database for this package.
+     *
      * <p>
      * Caller must pass in the correct user context if calling from a singleton service.
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static boolean shouldWriteMessageForPackage(String packageName, Context context) {
-        return !shouldWriteMessageForPackageAsUser(packageName, context, getIncomingUserId());
+        return !shouldWriteMessageForPackageAsUser(packageName, context, getIncomingUserHandle());
     }
 
+    /**
+     * Returns whether it is required to write the SMS message to SMS database for this package.
+     *
+     * @param packageName the name of the package to be checked
+     * @param context context from the calling app
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
+     * @return true if it is required to write SMS message to SMS database for this package.
+     *
+     * <p>
+     * Caller must pass in the correct user context if calling from a singleton service.
+     */
     public static boolean shouldWriteMessageForPackageAsUser(String packageName, Context context,
-            int userId) {
-        return !isDefaultSmsApplicationAsUser(context, packageName, userId);
+            @Nullable UserHandle userHandle) {
+        return !isDefaultSmsApplicationAsUser(context, packageName, userHandle);
     }
 
     /**
@@ -1177,7 +1227,7 @@
      */
     @UnsupportedAppUsage
     public static boolean isDefaultSmsApplication(Context context, String packageName) {
-        return isDefaultSmsApplicationAsUser(context, packageName, getIncomingUserId());
+        return isDefaultSmsApplicationAsUser(context, packageName, getIncomingUserHandle());
     }
 
     /**
@@ -1185,16 +1235,22 @@
      *
      * @param context context from the calling app
      * @param packageName the name of the package to be checked
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return true if the package is default sms app or bluetooth
      */
     public static boolean isDefaultSmsApplicationAsUser(Context context, String packageName,
-            int userId) {
+            @Nullable UserHandle userHandle) {
         if (packageName == null) {
             return false;
         }
+
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         ComponentName component = getDefaultSmsApplicationAsUser(context, false,
-                userId);
+                userHandle);
         if (component == null) {
             return false;
         }
@@ -1222,7 +1278,7 @@
      */
     @UnsupportedAppUsage
     public static boolean isDefaultMmsApplication(Context context, String packageName) {
-        return isDefaultMmsApplicationAsUser(context, packageName, getIncomingUserId());
+        return isDefaultMmsApplicationAsUser(context, packageName, getIncomingUserHandle());
     }
 
     /**
@@ -1230,17 +1286,22 @@
      *
      * @param context context from the calling app
      * @param packageName the name of the package to be checked
-     * @param userId target user ID.
+     * @param userHandle target user handle
+     * if {@code null} is passed in then calling package uid is used to find out target user handle.
      * @return true if the package is default mms app or bluetooth
      */
     public static boolean isDefaultMmsApplicationAsUser(Context context, String packageName,
-            int userId) {
+            @Nullable UserHandle userHandle) {
         if (packageName == null) {
             return false;
         }
 
+        if (userHandle == null) {
+            userHandle = getIncomingUserHandle();
+        }
+
         ComponentName component = getDefaultMmsApplicationAsUser(context, false,
-                userId);
+                userHandle);
         if (component == null) {
             return false;
         }
diff --git a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
index 76d2b7d..3dc7111 100644
--- a/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
+++ b/telephony/common/com/android/internal/telephony/util/TelephonyUtils.java
@@ -27,6 +27,8 @@
 import android.os.Bundle;
 import android.os.PersistableBundle;
 import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 
 import java.io.PrintWriter;
@@ -212,4 +214,30 @@
                 return "UNKNOWN(" + mobileDataPolicy + ")";
         }
     }
-}
+
+    /**
+     * Utility method to get user handle associated with this subscription.
+     *
+     * This method should be used internally as it returns null instead of throwing
+     * IllegalArgumentException or IllegalStateException.
+     *
+     * @param context Context object
+     * @param subId the subId of the subscription.
+     * @return userHandle associated with this subscription
+     * or {@code null} if:
+     * 1. subscription is not associated with any user
+     * 2. subId is invalid.
+     * 3. subscription service is not available.
+     *
+     * @throws SecurityException if the caller doesn't have permissions required.
+     */
+    @Nullable
+    public static UserHandle getSubscriptionUserHandle(Context context, int subId) {
+        UserHandle userHandle = null;
+        SubscriptionManager subManager =  context.getSystemService(SubscriptionManager.class);
+        if ((subManager != null) && (SubscriptionManager.isValidSubscriptionId(subId))) {
+            userHandle = subManager.getSubscriptionUserHandle(subId);
+        }
+        return userHandle;
+    }
+}
\ No newline at end of file
diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java
index 8ec500b..7eccd1a 100644
--- a/telephony/java/android/service/euicc/EuiccProfileInfo.java
+++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java
@@ -49,7 +49,6 @@
             POLICY_RULE_DO_NOT_DELETE,
             POLICY_RULE_DELETE_AFTER_DISABLING
     })
-    /** @hide */
     public @interface PolicyRule {}
     /** Once this profile is enabled, it cannot be disabled. */
     public static final int POLICY_RULE_DO_NOT_DISABLE = 1;
@@ -66,7 +65,6 @@
             PROFILE_CLASS_OPERATIONAL,
             PROFILE_CLASS_UNSET
     })
-    /** @hide */
     public @interface ProfileClass {}
     /** Testing profiles */
     public static final int PROFILE_CLASS_TESTING = 0;
@@ -87,7 +85,6 @@
             PROFILE_STATE_ENABLED,
             PROFILE_STATE_UNSET
     })
-    /** @hide */
     public @interface ProfileState {}
     /** Disabled profiles */
     public static final int PROFILE_STATE_DISABLED = 0;
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 86b98f1..2435243 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -5,6 +5,7 @@
 import android.net.NetworkCapabilities;
 import android.telecom.Connection;
 import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsCallProfile;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -494,7 +495,7 @@
             PreciseCallState.PRECISE_CALL_STATE_HOLDING,
             PreciseCallState.PRECISE_CALL_STATE_DIALING,
             PreciseCallState.PRECISE_CALL_STATE_ALERTING,
-            PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+            PreciseCallState.PRECISE_CALL_STATE_INCOMING,
             PreciseCallState.PRECISE_CALL_STATE_WAITING,
             PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
             PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
@@ -727,6 +728,36 @@
     })
     public @interface ValidationStatus {}
 
+    /**
+     * IMS call Service types
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "SERVICE_TYPE_" }, value = {
+            ImsCallProfile.SERVICE_TYPE_NONE,
+            ImsCallProfile.SERVICE_TYPE_NORMAL,
+            ImsCallProfile.SERVICE_TYPE_EMERGENCY,
+    })
+    public @interface ImsCallServiceType {}
+
+    /**
+     * IMS call types
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(prefix = { "CALL_TYPE_" }, value = {
+            ImsCallProfile.CALL_TYPE_NONE,
+            ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO,
+            ImsCallProfile.CALL_TYPE_VOICE,
+            ImsCallProfile.CALL_TYPE_VIDEO_N_VOICE,
+            ImsCallProfile.CALL_TYPE_VT,
+            ImsCallProfile.CALL_TYPE_VT_TX,
+            ImsCallProfile.CALL_TYPE_VT_RX,
+            ImsCallProfile.CALL_TYPE_VT_NODIR,
+            ImsCallProfile.CALL_TYPE_VS,
+            ImsCallProfile.CALL_TYPE_VS_TX,
+            ImsCallProfile.CALL_TYPE_VS_RX,
+    })
+    public @interface ImsCallType {}
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index b7bef39..1dc64a9 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -29,8 +29,10 @@
  * Contains information about a call's attributes as passed up from the HAL. If there are multiple
  * ongoing calls, the CallAttributes will pertain to the call in the foreground.
  * @hide
+ * @deprecated use {@link CallState} for call information for each call.
  */
 @SystemApi
+@Deprecated
 public final class CallAttributes implements Parcelable {
     private PreciseCallState mPreciseCallState;
     @NetworkType
diff --git a/telephony/java/android/telephony/CallState.aidl b/telephony/java/android/telephony/CallState.aidl
new file mode 100644
index 0000000..dd5af8e
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.telephony;
+
+parcelable CallState;
+
diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java
new file mode 100644
index 0000000..51ecfb0
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.ImsCallServiceType;
+import android.telephony.Annotation.ImsCallType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
+
+import java.util.Objects;
+
+/**
+ * Contains information about various states for a call.
+ * @hide
+ */
+@SystemApi
+public final class CallState implements Parcelable {
+
+    /**
+     * Call classifications are just used for backward compatibility of deprecated API {@link
+     * TelephonyCallback#CallAttributesListener#onCallAttributesChanged}, Since these will be
+     * removed when the deprecated API is removed, they should not be opened.
+     */
+    /**
+     * Call classification is not valid. It should not be opened.
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_UNKNOWN = -1;
+
+    /**
+     * Call classification indicating foreground call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_RINGING = 0;
+
+    /**
+     * Call classification indicating background call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_FOREGROUND = 1;
+
+    /**
+     * Call classification indicating ringing call
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_BACKGROUND = 2;
+
+    /**
+     * Call classification Max value.
+     * @hide
+     */
+    public static final int CALL_CLASSIFICATION_MAX = CALL_CLASSIFICATION_BACKGROUND + 1;
+
+    @PreciseCallStates
+    private final int mPreciseCallState;
+
+    @NetworkType
+    private final int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints
+    private final CallQuality mCallQuality;
+
+    private final int mCallClassification;
+    /**
+     * IMS call session ID. {@link ImsCallSession#getCallId()}
+     */
+    @Nullable
+    private String mImsCallId;
+
+    /**
+     * IMS call service type of this call
+     */
+    @ImsCallServiceType
+    private int mImsCallServiceType;
+
+    /**
+     * IMS call type of this call.
+     */
+    @ImsCallType
+    private int mImsCallType;
+
+    /**
+     * Constructor of CallAttributes
+     *
+     * @param callState call state defined in {@link PreciseCallState}
+     * @param networkType network type for this call attributes
+     * @param callQuality call quality for this call attributes, only CallState in
+     *                    {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call
+     *                    quality.
+     * @param callClassification call classification
+     * @param imsCallId IMS call session ID for this call attributes
+     * @param imsCallServiceType IMS call service type for this call attributes
+     * @param imsCallType IMS call type for this call attributes
+     */
+    private CallState(@PreciseCallStates int callState, @NetworkType int networkType,
+            @NonNull CallQuality callQuality, int callClassification, @Nullable String imsCallId,
+            @ImsCallServiceType int imsCallServiceType, @ImsCallType int imsCallType) {
+        this.mPreciseCallState = callState;
+        this.mNetworkType = networkType;
+        this.mCallQuality = callQuality;
+        this.mCallClassification = callClassification;
+        this.mImsCallId = imsCallId;
+        this.mImsCallServiceType = imsCallServiceType;
+        this.mImsCallType = imsCallType;
+    }
+
+    @NonNull
+    @Override
+    public String toString() {
+        return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
+                + " mCallQuality=" + mCallQuality + " mCallClassification" + mCallClassification
+                + " mImsCallId=" + mImsCallId + " mImsCallServiceType=" + mImsCallServiceType
+                + " mImsCallType=" + mImsCallType;
+    }
+
+    private CallState(Parcel in) {
+        this.mPreciseCallState = in.readInt();
+        this.mNetworkType = in.readInt();
+        this.mCallQuality = in.readParcelable(
+                CallQuality.class.getClassLoader(), CallQuality.class);
+        this.mCallClassification = in.readInt();
+        this.mImsCallId = in.readString();
+        this.mImsCallServiceType = in.readInt();
+        this.mImsCallType = in.readInt();
+    }
+
+    // getters
+    /**
+     * Returns the precise call state of the call.
+     */
+    @PreciseCallStates
+    public int getCallState() {
+        return mPreciseCallState;
+    }
+
+    /**
+     * Returns the {@link TelephonyManager#NetworkType} of the call.
+     *
+     * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+     * @see TelephonyManager#NETWORK_TYPE_GPRS
+     * @see TelephonyManager#NETWORK_TYPE_EDGE
+     * @see TelephonyManager#NETWORK_TYPE_UMTS
+     * @see TelephonyManager#NETWORK_TYPE_CDMA
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+     * @see TelephonyManager#NETWORK_TYPE_1xRTT
+     * @see TelephonyManager#NETWORK_TYPE_HSDPA
+     * @see TelephonyManager#NETWORK_TYPE_HSUPA
+     * @see TelephonyManager#NETWORK_TYPE_HSPA
+     * @see TelephonyManager#NETWORK_TYPE_IDEN
+     * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+     * @see TelephonyManager#NETWORK_TYPE_LTE
+     * @see TelephonyManager#NETWORK_TYPE_EHRPD
+     * @see TelephonyManager#NETWORK_TYPE_HSPAP
+     * @see TelephonyManager#NETWORK_TYPE_GSM
+     * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA
+     * @see TelephonyManager#NETWORK_TYPE_IWLAN
+     * @see TelephonyManager#NETWORK_TYPE_LTE_CA
+     * @see TelephonyManager#NETWORK_TYPE_NR
+     */
+    @NetworkType
+    public int getNetworkType() {
+        return mNetworkType;
+    }
+
+    /**
+     * Returns the {#link CallQuality} of the call.
+     * @return call quality for this call attributes, only CallState in {@link
+     *         PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call quality. It will be
+     *         null for the call which is not in {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}.
+     */
+    @Nullable
+    public CallQuality getCallQuality() {
+        return mCallQuality;
+    }
+
+    /**
+     * Returns the call classification.
+     * @hide
+     */
+    public int getCallClassification() {
+        return mCallClassification;
+    }
+
+    /**
+     * Returns the IMS call session ID.
+     */
+    @Nullable
+    public String getImsCallSessionId() {
+        return mImsCallId;
+    }
+
+    /**
+     * Returns the IMS call service type.
+     */
+    @ImsCallServiceType
+    public int getImsCallServiceType() {
+        return mImsCallServiceType;
+    }
+
+    /**
+     * Returns the IMS call type.
+     */
+    @ImsCallType
+    public int getImsCallType() {
+        return mImsCallType;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality, mCallClassification,
+                mImsCallId, mImsCallServiceType, mImsCallType);
+    }
+
+    @Override
+    public boolean equals(@Nullable Object o) {
+        if (o == null || !(o instanceof CallState) || hashCode() != o.hashCode()) {
+            return false;
+        }
+
+        if (this == o) {
+            return true;
+        }
+
+        CallState s = (CallState) o;
+
+        return (mPreciseCallState == s.mPreciseCallState
+                && mNetworkType == s.mNetworkType
+                && Objects.equals(mCallQuality, s.mCallQuality)
+                && mCallClassification == s.mCallClassification
+                && Objects.equals(mImsCallId, s.mImsCallId)
+                && mImsCallType == s.mImsCallType
+                && mImsCallServiceType == s.mImsCallServiceType);
+    }
+
+    /**
+     * {@link Parcelable#describeContents}
+     */
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * {@link Parcelable#writeToParcel}
+     */
+    public void writeToParcel(@Nullable Parcel dest, int flags) {
+        dest.writeInt(mPreciseCallState);
+        dest.writeInt(mNetworkType);
+        dest.writeParcelable(mCallQuality, flags);
+        dest.writeInt(mCallClassification);
+        dest.writeString(mImsCallId);
+        dest.writeInt(mImsCallServiceType);
+        dest.writeInt(mImsCallType);
+    }
+
+    public static final @NonNull Creator<CallState> CREATOR = new Creator() {
+        public CallState createFromParcel(Parcel in) {
+            return new CallState(in);
+        }
+
+        public CallState[] newArray(int size) {
+            return new CallState[size];
+        }
+    };
+
+    /**
+     * Builder of {@link CallState}
+     *
+     * <p>The example below shows how you might create a new {@code CallState}:
+     *
+     * <pre><code>
+     *
+     * CallState = new CallState.Builder()
+     *     .setCallState(3)
+     *     .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE})
+     *     .setCallQuality({@link CallQuality})
+     *     .setImsCallSessionId({@link String})
+     *     .setImsCallServiceType({@link ImsCallProfile#SERVICE_TYPE_NORMAL})
+     *     .setImsCallType({@link ImsCallProfile#CALL_TYPE_VOICE})
+     *     .build();
+     * </code></pre>
+     */
+    public static final class Builder {
+        private @PreciseCallStates int mPreciseCallState;
+        private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+        private CallQuality mCallQuality = null;
+        private int mCallClassification = CALL_CLASSIFICATION_UNKNOWN;
+        private String mImsCallId;
+        private @ImsCallServiceType int mImsCallServiceType = ImsCallProfile.SERVICE_TYPE_NONE;
+        private @ImsCallType int mImsCallType = ImsCallProfile.CALL_TYPE_NONE;
+
+
+        /**
+         * Default constructor for the Builder.
+         */
+        public Builder(@PreciseCallStates int preciseCallState) {
+            mPreciseCallState = preciseCallState;
+        }
+
+        /**
+         * Set network type of this call.
+         *
+         * @param networkType the transport type.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setNetworkType(@NetworkType int networkType) {
+            this.mNetworkType = networkType;
+            return this;
+        }
+
+        /**
+         * Set the call quality {@link CallQuality} of this call.
+         *
+         * @param callQuality call quality of active call.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setCallQuality(@Nullable CallQuality callQuality) {
+            this.mCallQuality = callQuality;
+            return this;
+        }
+
+        /**
+         * Set call classification for this call.
+         *
+         * @param classification call classification type defined in this class.
+         * @return The same instance of the builder.
+         * @hide
+         */
+        @NonNull
+        public CallState.Builder setCallClassification(int classification) {
+            this.mCallClassification = classification;
+            return this;
+        }
+
+        /**
+         * Set IMS call session ID of this call.
+         *
+         * @param imsCallId  IMS call session ID.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallSessionId(@Nullable String imsCallId) {
+            this.mImsCallId = imsCallId;
+            return this;
+        }
+
+        /**
+         * Set IMS call service type of this call.
+         *
+         * @param serviceType IMS call service type defined in {@link ImsCallProfile}.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallServiceType(@ImsCallServiceType int serviceType) {
+            this.mImsCallServiceType = serviceType;
+            return this;
+        }
+
+        /**
+         * Set IMS call type of this call.
+         *
+         * @param callType IMS call type defined in {@link ImsCallProfile}.
+         * @return The same instance of the builder.
+         */
+        @NonNull
+        public CallState.Builder setImsCallType(@ImsCallType int callType) {
+            this.mImsCallType = callType;
+            return this;
+        }
+
+        /**
+         * Build the {@link CallState}
+         *
+         * @return the {@link CallState} object
+         */
+        @NonNull
+        public CallState build() {
+            return new CallState(
+                    mPreciseCallState,
+                    mNetworkType,
+                    mCallQuality,
+                    mCallClassification,
+                    mImsCallId,
+                    mImsCallServiceType,
+                    mImsCallType);
+        }
+    }
+}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ed96a9b..22cd31a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1996,6 +1996,15 @@
             "nr_advanced_threshold_bandwidth_khz_int";
 
     /**
+     * Indicating whether to include LTE cell bandwidths when determining whether the aggregated
+     * cell bandwidth meets the required threshold for NR advanced.
+     *
+     * @see TelephonyDisplayInfo#OVERRIDE_NETWORK_TYPE_NR_ADVANCED
+     */
+    public static final String KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL =
+            "include_lte_for_nr_advanced_threshold_bandwidth_bool";
+
+    /**
      * Boolean indicating if operator name should be shown in the status bar
      * @hide
      */
@@ -9577,6 +9586,7 @@
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
         sDefaults.putInt(KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT, 20000);
         sDefaults.putInt(KEY_NR_ADVANCED_THRESHOLD_BANDWIDTH_KHZ_INT, 0);
+        sDefaults.putBoolean(KEY_INCLUDE_LTE_FOR_NR_ADVANCED_THRESHOLD_BANDWIDTH_BOOL, false);
         sDefaults.putIntArray(KEY_CARRIER_NR_AVAILABILITIES_INT_ARRAY,
                 new int[]{CARRIER_NR_AVAILABILITY_NSA, CARRIER_NR_AVAILABILITY_SA});
         sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 4ce2ca1..794fe72 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -155,6 +155,10 @@
     private static final String CACHE_KEY_SLOT_INDEX_PROPERTY =
             "cache_key.telephony.get_slot_index";
 
+    /** The IPC cache key shared by all subscription manager service cacheable properties. */
+    private static final String CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY =
+            "cache_key.telephony.subscription_manager_service";
+
     /** @hide */
     public static final String GET_SIM_SPECIFIC_SETTINGS_METHOD_NAME = "getSimSpecificSettings";
 
@@ -269,37 +273,72 @@
                     CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
+    private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSubIdCache =
+            new VoidPropertyInvalidatedCache<>(ISub::getDefaultSubId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SUBSCRIPTION_ID);
+
     private static VoidPropertyInvalidatedCache<Integer> sDefaultDataSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
                     CACHE_KEY_DEFAULT_DATA_SUB_ID_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
+    private static VoidPropertyInvalidatedCache<Integer> sGetDefaultDataSubIdCache =
+            new VoidPropertyInvalidatedCache<>(ISub::getDefaultDataSubId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SUBSCRIPTION_ID);
+
     private static VoidPropertyInvalidatedCache<Integer> sDefaultSmsSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
                     CACHE_KEY_DEFAULT_SMS_SUB_ID_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
+    private static VoidPropertyInvalidatedCache<Integer> sGetDefaultSmsSubIdCache =
+            new VoidPropertyInvalidatedCache<>(ISub::getDefaultSmsSubId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SUBSCRIPTION_ID);
+
     private static VoidPropertyInvalidatedCache<Integer> sActiveDataSubIdCache =
             new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
                     CACHE_KEY_ACTIVE_DATA_SUB_ID_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
+    private static VoidPropertyInvalidatedCache<Integer> sGetActiveDataSubscriptionIdCache =
+            new VoidPropertyInvalidatedCache<>(ISub::getActiveDataSubscriptionId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SUBSCRIPTION_ID);
+
     private static IntegerPropertyInvalidatedCache<Integer> sSlotIndexCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
                     CACHE_KEY_SLOT_INDEX_PROPERTY,
                     INVALID_SIM_SLOT_INDEX);
 
+    private static IntegerPropertyInvalidatedCache<Integer> sGetSlotIndexCache =
+            new IntegerPropertyInvalidatedCache<>(ISub::getSlotIndex,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SIM_SLOT_INDEX);
+
     private static IntegerPropertyInvalidatedCache<Integer> sSubIdCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
                     CACHE_KEY_SLOT_INDEX_PROPERTY,
                     INVALID_SUBSCRIPTION_ID);
 
+    private static IntegerPropertyInvalidatedCache<Integer> sGetSubIdCache =
+            new IntegerPropertyInvalidatedCache<>(ISub::getSubId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_SUBSCRIPTION_ID);
+
     /** Cache depends on getDefaultSubId, so we use the defaultSubId cache key */
     private static IntegerPropertyInvalidatedCache<Integer> sPhoneIdCache =
             new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
                     CACHE_KEY_DEFAULT_SUB_ID_PROPERTY,
                     INVALID_PHONE_INDEX);
 
+    private static IntegerPropertyInvalidatedCache<Integer> sGetPhoneIdCache =
+            new IntegerPropertyInvalidatedCache<>(ISub::getPhoneId,
+                    CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY,
+                    INVALID_PHONE_INDEX);
+
     /**
      * Generates a content {@link Uri} used to receive updates on simInfo change
      * on the given subscriptionId
@@ -1298,6 +1337,8 @@
 
     private final Context mContext;
 
+    private static boolean sIsSubscriptionManagerServiceEnabled = false;
+
     // Cache of Resource that has been created in getResourcesForSubId. Key is a Pair containing
     // the Context and subId.
     private static final Map<Pair<Context, Integer>, Resources> sResourcesCache =
@@ -1383,6 +1424,19 @@
     public SubscriptionManager(Context context) {
         if (DBG) logd("SubscriptionManager created");
         mContext = context;
+
+        sIsSubscriptionManagerServiceEnabled = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_using_subscription_manager_service);
+    }
+
+    /**
+     * @return {@code true} if the new subscription manager service is used. This is temporary and
+     * will be removed before Android 14 release.
+     *
+     * @hide
+     */
+    public static boolean isSubscriptionManagerServiceEnabled() {
+        return sIsSubscriptionManagerServiceEnabled;
     }
 
     private NetworkPolicyManager getNetworkPolicyManager() {
@@ -1663,17 +1717,33 @@
     }
 
     /**
-     * @return List of all SubscriptionInfo records in database,
-     * include those that were inserted before, maybe empty but not null.
+     * Get all subscription info records from SIMs that are inserted now or were inserted before.
+     *
+     * <p>
+     * If the caller does not have {@link Manifest.permission#READ_PHONE_NUMBERS} permission,
+     * {@link SubscriptionInfo#getNumber()} will return empty string.
+     * If the caller does not have {@link Manifest.permission#USE_ICC_AUTH_WITH_DEVICE_IDENTIFIER},
+     * {@link SubscriptionInfo#getIccId()} and {@link SubscriptionInfo#getCardString()} will return
+     * empty string, and {@link SubscriptionInfo#getGroupUuid()} will return {@code null}.
+     *
+     * <p>
+     * The carrier app will always have full {@link SubscriptionInfo} for the subscriptions
+     * that it has carrier privilege.
+     *
+     * @return List of all {@link SubscriptionInfo} records from SIMs that are inserted or
+     * inserted before. Sorted by {@link SubscriptionInfo#getSimSlotIndex()}, then
+     * {@link SubscriptionInfo#getSubscriptionId()}.
+     *
      * @hide
      */
+    @RequiresPermission(anyOf = {
+            Manifest.permission.READ_PHONE_STATE,
+            Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
+            "carrier privileges",
+    })
     @NonNull
-    @UnsupportedAppUsage
     public List<SubscriptionInfo> getAllSubscriptionInfoList() {
-        if (VDBG) logd("[getAllSubscriptionInfoList]+");
-
         List<SubscriptionInfo> result = null;
-
         try {
             ISub iSub = TelephonyManager.getSubscriptionService();
             if (iSub != null) {
@@ -2142,6 +2212,7 @@
      * subscriptionId doesn't have an associated slot index.
      */
     public static int getSlotIndex(int subscriptionId) {
+        if (isSubscriptionManagerServiceEnabled()) return sGetSlotIndexCache.query(subscriptionId);
         return sSlotIndexCache.query(subscriptionId);
     }
 
@@ -2191,12 +2262,14 @@
             return SubscriptionManager.INVALID_SUBSCRIPTION_ID;
         }
 
+        if (isSubscriptionManagerServiceEnabled()) return sGetSubIdCache.query(slotIndex);
         return sSubIdCache.query(slotIndex);
     }
 
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public static int getPhoneId(int subId) {
+        if (isSubscriptionManagerServiceEnabled()) return sGetPhoneIdCache.query(subId);
         return sPhoneIdCache.query(subId);
     }
 
@@ -2218,6 +2291,7 @@
      * @return the "system" default subscription id.
      */
     public static int getDefaultSubscriptionId() {
+        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSubIdCache.query(null);
         return sDefaultSubIdCache.query(null);
     }
 
@@ -2306,6 +2380,7 @@
      * @return the default SMS subscription Id.
      */
     public static int getDefaultSmsSubscriptionId() {
+        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultSmsSubIdCache.query(null);
         return sDefaultSmsSubIdCache.query(null);
     }
 
@@ -2340,6 +2415,7 @@
      * @return the default data subscription Id.
      */
     public static int getDefaultDataSubscriptionId() {
+        if (isSubscriptionManagerServiceEnabled()) return sGetDefaultDataSubIdCache.query(null);
         return sDefaultDataSubIdCache.query(null);
     }
 
@@ -3424,7 +3500,6 @@
 
     /**
      * Get subscriptionInfo list of subscriptions that are in the same group of given subId.
-     * See {@link #createSubscriptionGroup(List)} for more details.
      *
      * Caller must have {@link android.Manifest.permission#READ_PHONE_STATE}
      * or carrier privilege permission on the subscription.
@@ -3804,6 +3879,9 @@
      * SubscriptionManager.INVALID_SUBSCRIPTION_ID if not.
      */
     public static int getActiveDataSubscriptionId() {
+        if (isSubscriptionManagerServiceEnabled()) {
+            return sGetActiveDataSubscriptionIdCache.query(null);
+        }
         return sActiveDataSubIdCache.query(null);
     }
 
@@ -3847,6 +3925,11 @@
         PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SLOT_INDEX_PROPERTY);
     }
 
+    /** @hide */
+    public static void invalidateSubscriptionManagerServiceCaches() {
+        PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SUBSCRIPTION_MANAGER_SERVICE_PROPERTY);
+    }
+
     /**
      * Allows a test process to disable client-side caching operations.
      *
@@ -3858,7 +3941,16 @@
         sActiveDataSubIdCache.disableLocal();
         sDefaultSmsSubIdCache.disableLocal();
         sSlotIndexCache.disableLocal();
+        sSubIdCache.disableLocal();
         sPhoneIdCache.disableLocal();
+
+        sGetDefaultSubIdCache.disableLocal();
+        sGetDefaultDataSubIdCache.disableLocal();
+        sGetActiveDataSubscriptionIdCache.disableLocal();
+        sGetDefaultSmsSubIdCache.disableLocal();
+        sGetSlotIndexCache.disableLocal();
+        sGetSubIdCache.disableLocal();
+        sGetPhoneIdCache.disableLocal();
     }
 
     /**
@@ -3871,7 +3963,16 @@
         sActiveDataSubIdCache.clear();
         sDefaultSmsSubIdCache.clear();
         sSlotIndexCache.clear();
+        sSubIdCache.clear();
         sPhoneIdCache.clear();
+
+        sGetDefaultSubIdCache.clear();
+        sGetDefaultDataSubIdCache.clear();
+        sGetActiveDataSubscriptionIdCache.clear();
+        sGetDefaultSmsSubIdCache.clear();
+        sGetSlotIndexCache.clear();
+        sGetSubIdCache.clear();
+        sGetPhoneIdCache.clear();
     }
 
     /**
@@ -4125,6 +4226,26 @@
     }
 
     /**
+     * Convert phone number source to string.
+     *
+     * @param source The phone name source.
+     *
+     * @return The phone name source in string format.
+     *
+     * @hide
+     */
+    @NonNull
+    public static String phoneNumberSourceToString(@PhoneNumberSource int source) {
+        switch (source) {
+            case SubscriptionManager.PHONE_NUMBER_SOURCE_UICC: return "UICC";
+            case SubscriptionManager.PHONE_NUMBER_SOURCE_CARRIER: return "CARRIER";
+            case SubscriptionManager.PHONE_NUMBER_SOURCE_IMS: return "IMS";
+            default:
+                return "UNKNOWN(" + source + ")";
+        }
+    }
+
+    /**
      * Convert display name source to string.
      *
      * @param source The display name source.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index d3ddb1b..3024b89 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -71,6 +71,7 @@
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.SystemProperties;
+import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings.SettingNotFoundException;
 import android.service.carrier.CarrierIdentifier;
@@ -11934,8 +11935,9 @@
     }
 
     /**
-     * Gets the default Respond Via Message application, updating the cache if there is no
-     * respond-via-message application currently configured.
+     * Get the component name of the default app to direct respond-via-message intent for the
+     * user associated with this subscription, update the cache if there is no respond-via-message
+     * application currently configured for this user.
      * @return component name of the app and class to direct Respond Via Message intent to, or
      * {@code null} if the functionality is not supported.
      * @hide
@@ -11944,11 +11946,20 @@
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getAndUpdateDefaultRespondViaMessageApplication() {
-        return SmsApplication.getDefaultRespondViaMessageApplication(mContext, true);
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getDefaultRespondViaMessageApplication(getSubId(), true);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in getAndUpdateDefaultRespondViaMessageApplication: " + e);
+        }
+        return null;
     }
 
     /**
-     * Gets the default Respond Via Message application.
+     * Get the component name of the default app to direct respond-via-message intent for the
+     * user associated with this subscription.
      * @return component name of the app and class to direct Respond Via Message intent to, or
      * {@code null} if the functionality is not supported.
      * @hide
@@ -11957,7 +11968,15 @@
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @RequiresFeature(PackageManager.FEATURE_TELEPHONY_MESSAGING)
     public @Nullable ComponentName getDefaultRespondViaMessageApplication() {
-        return SmsApplication.getDefaultRespondViaMessageApplication(mContext, false);
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.getDefaultRespondViaMessageApplication(getSubId(), false);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error in getDefaultRespondViaMessageApplication: " + e);
+        }
+        return null;
     }
 
     /**
diff --git a/telephony/java/android/telephony/data/DataProfile.java b/telephony/java/android/telephony/data/DataProfile.java
index 5e11163..f346b92 100644
--- a/telephony/java/android/telephony/data/DataProfile.java
+++ b/telephony/java/android/telephony/data/DataProfile.java
@@ -147,7 +147,7 @@
         if (mApnSetting != null) {
             return mApnSetting.getProtocol();
         }
-        return ApnSetting.PROTOCOL_IP;
+        return ApnSetting.PROTOCOL_IPV4V6;
     }
 
     /**
diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java
index e61d1e6..b18eaa53 100644
--- a/telephony/java/android/telephony/euicc/EuiccCardManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java
@@ -75,7 +75,6 @@
             CANCEL_REASON_TIMEOUT,
             CANCEL_REASON_PPR_NOT_ALLOWED
     })
-    /** @hide */
     public @interface CancelReason {
     }
 
@@ -105,7 +104,6 @@
             RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES,
             RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS
     })
-    /** @hide */
     public @interface ResetOption {
     }
 
diff --git a/telephony/java/android/telephony/euicc/EuiccNotification.java b/telephony/java/android/telephony/euicc/EuiccNotification.java
index c348cff..be0048f 100644
--- a/telephony/java/android/telephony/euicc/EuiccNotification.java
+++ b/telephony/java/android/telephony/euicc/EuiccNotification.java
@@ -44,7 +44,6 @@
             EVENT_DISABLE,
             EVENT_DELETE
     })
-    /** @hide */
     public @interface Event {}
 
     /** A profile is downloaded and installed. */
diff --git a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
index d5a05ae..1c6b6b6 100644
--- a/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
+++ b/telephony/java/android/telephony/euicc/EuiccRulesAuthTable.java
@@ -42,7 +42,6 @@
     @IntDef(flag = true, prefix = { "POLICY_RULE_FLAG_" }, value = {
             POLICY_RULE_FLAG_CONSENT_REQUIRED
     })
-    /** @hide */
     public @interface PolicyRuleFlag {}
 
     /** User consent is required to install the profile. */
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index e6d7df3..1ea7fdc 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -78,8 +78,9 @@
     public static final int SERVICE_TYPE_EMERGENCY = 2;
 
     /**
-     * Call types
+     * Call type none
      */
+    public static final int CALL_TYPE_NONE = 0;
     /**
      * IMSPhone to support IR.92 & IR.94 (voice + video upgrade/downgrade)
      */
diff --git a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
index 8519173..ea4480d 100644
--- a/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IImsMmTelFeature.aidl
@@ -65,6 +65,7 @@
     oneway void sendSms(in int token, int messageRef, String format, String smsc, boolean retry,
             in byte[] pdu);
     oneway void acknowledgeSms(int token, int messageRef, int result);
+    oneway void acknowledgeSmsWithPdu(int token, int messageRef, int result, in byte[] pdu);
     oneway void acknowledgeSmsReport(int token, int messageRef, int result);
     String getSmsFormat();
     oneway void onSmsReady();
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index 8147759..d776928 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -275,6 +275,12 @@
         }
 
         @Override
+        public void acknowledgeSmsWithPdu(int token, int messageRef, int result, byte[] pdu) {
+            executeMethodAsyncNoException(() -> MmTelFeature.this
+                    .acknowledgeSms(token, messageRef, result, pdu), "acknowledgeSms");
+        }
+
+        @Override
         public void acknowledgeSmsReport(int token, int messageRef, int result) {
             executeMethodAsyncNoException(() -> MmTelFeature.this
                     .acknowledgeSmsReport(token, messageRef, result), "acknowledgeSmsReport");
@@ -1087,6 +1093,11 @@
         getSmsImplementation().acknowledgeSms(token, messageRef, result);
     }
 
+    private void acknowledgeSms(int token, int messageRef,
+            @ImsSmsImplBase.DeliverStatusResult int result, byte[] pdu) {
+        getSmsImplementation().acknowledgeSms(token, messageRef, result, pdu);
+    }
+
     private void acknowledgeSmsReport(int token, int messageRef,
             @ImsSmsImplBase.StatusReportResult int result) {
         getSmsImplementation().acknowledgeSmsReport(token, messageRef, result);
diff --git a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
index fb997d1..66833d1 100644
--- a/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsSmsImplBase.java
@@ -18,6 +18,7 @@
 
 import android.annotation.IntDef;
 import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.os.RemoteException;
 import android.telephony.SmsManager;
@@ -174,6 +175,9 @@
      * {@link #onSmsReceived(int, String, byte[])} has been called to deliver the result to the IMS
      * provider.
      *
+     * If the framework needs to provide the PDU used to acknowledge the SMS,
+     * {@link #acknowledgeSms(int, int, int, byte[])} will be called.
+     *
      * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
      * @param messageRef the message reference, which may be 1 byte if it is in
      *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
@@ -186,6 +190,27 @@
     }
 
     /**
+     * This method will be called by the platform after
+     * {@link #onSmsReceived(int, String, byte[])} has been called to acknowledge an incoming SMS.
+     *
+     * This method is only called in cases where the framework needs to provide the PDU such as the
+     * case where we provide the Short Message Transfer Layer PDU (see 3GPP TS 23.040). Otherwise,
+     * {@link #acknowledgeSms(int, int, int)} will be used.
+     *
+     * @param token token provided in {@link #onSmsReceived(int, String, byte[])}
+     * @param messageRef the message reference, which may be 1 byte if it is in
+     *     {@link SmsMessage#FORMAT_3GPP} format (see TS.123.040) or 2 bytes if it is in
+     *     {@link SmsMessage#FORMAT_3GPP2} format (see 3GPP2 C.S0015-B).
+     * @param result result of delivering the message.
+     * @param pdu PDU representing the contents of the message.
+     */
+    public void acknowledgeSms(int token, @IntRange(from = 0, to = 65535)  int messageRef,
+            @DeliverStatusResult int result, @NonNull byte[] pdu) {
+        Log.e(LOG_TAG, "acknowledgeSms() not implemented. acknowledgeSms(int, int, int) called.");
+        acknowledgeSms(token, messageRef, result);
+    }
+
+    /**
      * This method will be triggered by the platform after
      * {@link #onSmsStatusReportReceived(int, int, String, byte[])} or
      * {@link #onSmsStatusReportReceived(int, String, byte[])} has been called to provide the
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index abf4cde..616ea50 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -17,6 +17,7 @@
 package com.android.internal.telephony;
 
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentSender;
 import android.os.Bundle;
@@ -2618,4 +2619,14 @@
      * @hide
      */
     boolean isRemovableEsimDefaultEuicc(String callingPackage);
+
+     /**
+      * Get the component name of the default app to direct respond-via-message intent for the
+      * user associated with this subscription, update the cache if there is no respond-via-message
+      * application currently configured for this user.
+      * @return component name of the app and class to direct Respond Via Message intent to, or
+      * {@code null} if the functionality is not supported.
+      * @hide
+      */
+      ComponentName getDefaultRespondViaMessageApplication(int subId, boolean updateIfNeeded);
 }
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 0c14dba..a1257e3 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -546,6 +546,8 @@
     int RIL_REQUEST_UPDATE_IMS_CALL_STATUS = 240;
     int RIL_REQUEST_SET_N1_MODE_ENABLED = 241;
     int RIL_REQUEST_IS_N1_MODE_ENABLED = 242;
+    int RIL_REQUEST_SET_LOCATION_PRIVACY_SETTING = 243;
+    int RIL_REQUEST_GET_LOCATION_PRIVACY_SETTING = 244;
 
     /* Responses begin */
     int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -620,4 +622,5 @@
     int RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION = 1107;
     int RIL_UNSOL_CONNECTION_SETUP_FAILURE = 1108;
     int RIL_UNSOL_NOTIFY_ANBR = 1109;
+    int RIL_UNSOL_ON_NETWORK_INITIATED_LOCATION_RESULT = 1110;
 }
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 5430dee..cfebf34 100644
--- a/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
+++ b/tests/DynamicCodeLoggerIntegrationTests/src/com/android/server/pm/dex/DynamicCodeLoggerIntegrationTests.java
@@ -19,8 +19,11 @@
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.app.UiAutomation;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.Build;
 import android.os.ParcelFileDescriptor;
 import android.os.SystemClock;
@@ -96,7 +99,12 @@
     }
 
     @Before
-    public void primeEventLog() {
+    public void setup() {
+        assumeFalse(sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+        primeEventLog();
+    }
+
+    private void primeEventLog() {
         // Force a round trip to logd to make sure everything is up to date.
         // Without this the first test passes and others don't - we don't see new events in the
         // log. The exact reason is unclear.
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index a7d6a01..84781b4 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -19,6 +19,8 @@
         <option name="run-command" value="pm disable com.google.android.internal.betterbug" />
         <!-- restart launcher to activate TAPL -->
         <option name="run-command" value="setprop ro.test_harness 1 ; am force-stop com.google.android.apps.nexuslauncher" />
+        <!-- Ensure output directory is empty at the start -->
+        <option name="run-command" value="rm -rf /sdcard/flicker" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true"/>
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
index 8a1e1fa..c100a9c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/BaseTest.kt
@@ -20,7 +20,7 @@
 import android.platform.test.annotations.Presubmit
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.launcher3.tapl.LauncherInstrumentation
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.junit.FlickerBuilderProvider
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import org.junit.Assume
@@ -34,12 +34,12 @@
 abstract class BaseTest
 @JvmOverloads
 constructor(
-    protected val testSpec: FlickerTestParameter,
+    protected val flicker: FlickerTest,
     protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation(),
     protected val tapl: LauncherInstrumentation = LauncherInstrumentation()
 ) {
     init {
-        testSpec.setIsTablet(
+        flicker.scenario.setIsTablet(
             WindowManagerStateHelper(instrumentation, clearCacheAfterParsing = false)
                 .currentState
                 .wmState
@@ -58,13 +58,13 @@
     @FlickerBuilderProvider
     fun buildFlicker(): FlickerBuilder {
         return FlickerBuilder(instrumentation).apply {
-            setup { testSpec.setIsTablet(wmHelper.currentState.wmState.isTablet) }
+            setup { flicker.scenario.setIsTablet(wmHelper.currentState.wmState.isTablet) }
             transition()
         }
     }
 
     /** Checks that all parts of the screen are covered during the transition */
-    @Presubmit @Test open fun entireScreenCovered() = testSpec.entireScreenCovered()
+    @Presubmit @Test open fun entireScreenCovered() = flicker.entireScreenCovered()
 
     /**
      * Checks that the [ComponentNameMatcher.NAV_BAR] layer is visible during the whole transition
@@ -74,8 +74,8 @@
     @Presubmit
     @Test
     open fun navBarLayerIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerIsVisibleAtStartAndEnd()
     }
 
     /**
@@ -87,8 +87,8 @@
     @Presubmit
     @Test
     open fun navBarLayerPositionAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerPositionAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerPositionAtStartAndEnd()
     }
 
     /**
@@ -99,8 +99,8 @@
     @Presubmit
     @Test
     open fun navBarWindowIsAlwaysVisible() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsAlwaysVisible()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsAlwaysVisible()
     }
 
     /**
@@ -112,8 +112,8 @@
     @Presubmit
     @Test
     open fun taskBarLayerIsVisibleAtStartAndEnd() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarLayerIsVisibleAtStartAndEnd()
     }
 
     /**
@@ -124,8 +124,8 @@
     @Presubmit
     @Test
     open fun taskBarWindowIsAlwaysVisible() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarWindowIsAlwaysVisible()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarWindowIsAlwaysVisible()
     }
 
     /**
@@ -134,8 +134,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarLayerIsVisibleAtStartAndEnd() =
-        testSpec.statusBarLayerIsVisibleAtStartAndEnd()
+    open fun statusBarLayerIsVisibleAtStartAndEnd() = flicker.statusBarLayerIsVisibleAtStartAndEnd()
 
     /**
      * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
@@ -143,7 +142,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarLayerPositionAtStartAndEnd() = testSpec.statusBarLayerPositionAtStartAndEnd()
+    open fun statusBarLayerPositionAtStartAndEnd() = flicker.statusBarLayerPositionAtStartAndEnd()
 
     /**
      * Checks that the [ComponentNameMatcher.STATUS_BAR] window is visible during the whole
@@ -151,7 +150,7 @@
      */
     @Presubmit
     @Test
-    open fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsAlwaysVisible()
+    open fun statusBarWindowIsAlwaysVisible() = flicker.statusBarWindowIsAlwaysVisible()
 
     /**
      * Checks that all layers that are visible on the trace, are visible for at least 2 consecutive
@@ -160,7 +159,7 @@
     @Presubmit
     @Test
     open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
+        flicker.assertLayers { this.visibleLayersShownMoreThanOneConsecutiveEntry() }
     }
 
     /**
@@ -170,6 +169,19 @@
     @Presubmit
     @Test
     open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
+        flicker.assertWm { this.visibleWindowsShownMoreThanOneConsecutiveEntry() }
+    }
+
+    open fun cujCompleted() {
+        entireScreenCovered()
+        navBarLayerIsVisibleAtStartAndEnd()
+        navBarWindowIsAlwaysVisible()
+        taskBarLayerIsVisibleAtStartAndEnd()
+        taskBarWindowIsAlwaysVisible()
+        statusBarLayerIsVisibleAtStartAndEnd()
+        statusBarLayerPositionAtStartAndEnd()
+        statusBarWindowIsAlwaysVisible()
+        visibleLayersShownMoreThanOneConsecutiveEntry()
+        visibleWindowsShownMoreThanOneConsecutiveEntry()
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index bbffd08..f9a245a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -27,7 +27,7 @@
  * Checks that [ComponentNameMatcher.STATUS_BAR] window is visible and above the app windows in all
  * WM trace entries
  */
-fun FlickerTestParameter.statusBarWindowIsAlwaysVisible() {
+fun FlickerTest.statusBarWindowIsAlwaysVisible() {
     assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.STATUS_BAR) }
 }
 
@@ -35,7 +35,7 @@
  * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows in all WM
  * trace entries
  */
-fun FlickerTestParameter.navBarWindowIsAlwaysVisible() {
+fun FlickerTest.navBarWindowIsAlwaysVisible() {
     assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
 }
 
@@ -43,7 +43,7 @@
  * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
  * start and end of the WM trace
  */
-fun FlickerTestParameter.navBarWindowIsVisibleAtStartAndEnd() {
+fun FlickerTest.navBarWindowIsVisibleAtStartAndEnd() {
     this.navBarWindowIsVisibleAtStart()
     this.navBarWindowIsVisibleAtEnd()
 }
@@ -52,7 +52,7 @@
  * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
  * start of the WM trace
  */
-fun FlickerTestParameter.navBarWindowIsVisibleAtStart() {
+fun FlickerTest.navBarWindowIsVisibleAtStart() {
     assertWmStart { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
 }
 
@@ -60,7 +60,7 @@
  * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the end
  * of the WM trace
  */
-fun FlickerTestParameter.navBarWindowIsVisibleAtEnd() {
+fun FlickerTest.navBarWindowIsVisibleAtEnd() {
     assertWmEnd { this.isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR) }
 }
 
@@ -68,7 +68,7 @@
  * Checks that [ComponentNameMatcher.TASK_BAR] window is visible and above the app windows in all WM
  * trace entries
  */
-fun FlickerTestParameter.taskBarWindowIsAlwaysVisible() {
+fun FlickerTest.taskBarWindowIsAlwaysVisible() {
     assertWm { this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) }
 }
 
@@ -76,7 +76,7 @@
  * Checks that [ComponentNameMatcher.TASK_BAR] window is visible and above the app windows in all WM
  * trace entries
  */
-fun FlickerTestParameter.taskBarWindowIsVisibleAtEnd() {
+fun FlickerTest.taskBarWindowIsVisibleAtEnd() {
     assertWmEnd { this.isAboveAppWindowVisible(ComponentNameMatcher.TASK_BAR) }
 }
 
@@ -90,7 +90,7 @@
  * @param allStates if all states should be checked, othersie, just initial and final
  */
 @JvmOverloads
-fun FlickerTestParameter.entireScreenCovered(allStates: Boolean = true) {
+fun FlickerTest.entireScreenCovered(allStates: Boolean = true) {
     if (allStates) {
         assertLayers {
             this.invoke("entireScreenCovered") { entry ->
@@ -114,19 +114,19 @@
 }
 
 /** Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the start of the SF trace */
-fun FlickerTestParameter.navBarLayerIsVisibleAtStart() {
+fun FlickerTest.navBarLayerIsVisibleAtStart() {
     assertLayersStart { this.isVisible(ComponentNameMatcher.NAV_BAR) }
 }
 
 /** Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the end of the SF trace */
-fun FlickerTestParameter.navBarLayerIsVisibleAtEnd() {
+fun FlickerTest.navBarLayerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(ComponentNameMatcher.NAV_BAR) }
 }
 
 /**
  * Checks that [ComponentNameMatcher.NAV_BAR] layer is visible at the start and end of the SF trace
  */
-fun FlickerTestParameter.navBarLayerIsVisibleAtStartAndEnd() {
+fun FlickerTest.navBarLayerIsVisibleAtStartAndEnd() {
     this.navBarLayerIsVisibleAtStart()
     this.navBarLayerIsVisibleAtEnd()
 }
@@ -134,18 +134,18 @@
 /**
  * Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the start and end of the SF trace
  */
-fun FlickerTestParameter.taskBarLayerIsVisibleAtStartAndEnd() {
+fun FlickerTest.taskBarLayerIsVisibleAtStartAndEnd() {
     this.taskBarLayerIsVisibleAtStart()
     this.taskBarLayerIsVisibleAtEnd()
 }
 
 /** Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the start of the SF trace */
-fun FlickerTestParameter.taskBarLayerIsVisibleAtStart() {
+fun FlickerTest.taskBarLayerIsVisibleAtStart() {
     assertLayersStart { this.isVisible(ComponentNameMatcher.TASK_BAR) }
 }
 
 /** Checks that [ComponentNameMatcher.TASK_BAR] layer is visible at the end of the SF trace */
-fun FlickerTestParameter.taskBarLayerIsVisibleAtEnd() {
+fun FlickerTest.taskBarLayerIsVisibleAtEnd() {
     assertLayersEnd { this.isVisible(ComponentNameMatcher.TASK_BAR) }
 }
 
@@ -153,7 +153,7 @@
  * Checks that [ComponentNameMatcher.STATUS_BAR] layer is visible at the start and end of the SF
  * trace
  */
-fun FlickerTestParameter.statusBarLayerIsVisibleAtStartAndEnd() {
+fun FlickerTest.statusBarLayerIsVisibleAtStartAndEnd() {
     assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
     assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
 }
@@ -162,12 +162,14 @@
  * Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the start of
  * the SF trace
  */
-fun FlickerTestParameter.navBarLayerPositionAtStart() {
+fun FlickerTest.navBarLayerPositionAtStart() {
     assertLayersStart {
         val display =
             this.entry.displays.firstOrNull { !it.isVirtual } ?: error("There is no display!")
         this.visibleRegion(ComponentNameMatcher.NAV_BAR)
-            .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation))
+            .coversExactly(
+                WindowUtils.getNavigationBarPosition(display, scenario.isGesturalNavigation)
+            )
     }
 }
 
@@ -175,13 +177,15 @@
  * Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the end of
  * the SF trace
  */
-fun FlickerTestParameter.navBarLayerPositionAtEnd() {
+fun FlickerTest.navBarLayerPositionAtEnd() {
     assertLayersEnd {
         val display =
             this.entry.displays.minByOrNull { it.id }
                 ?: throw RuntimeException("There is no display!")
         this.visibleRegion(ComponentNameMatcher.NAV_BAR)
-            .coversExactly(WindowUtils.getNavigationBarPosition(display, isGesturalNavigation))
+            .coversExactly(
+                WindowUtils.getNavigationBarPosition(display, scenario.isGesturalNavigation)
+            )
     }
 }
 
@@ -189,7 +193,7 @@
  * Asserts that the [ComponentNameMatcher.NAV_BAR] layer is at the correct position at the start and
  * end of the SF trace
  */
-fun FlickerTestParameter.navBarLayerPositionAtStartAndEnd() {
+fun FlickerTest.navBarLayerPositionAtStartAndEnd() {
     navBarLayerPositionAtStart()
     navBarLayerPositionAtEnd()
 }
@@ -198,7 +202,7 @@
  * Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the start
  * of the SF trace
  */
-fun FlickerTestParameter.statusBarLayerPositionAtStart() {
+fun FlickerTest.statusBarLayerPositionAtStart() {
     assertLayersStart {
         val display =
             this.entry.displays.minByOrNull { it.id }
@@ -212,7 +216,7 @@
  * Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the end of
  * the SF trace
  */
-fun FlickerTestParameter.statusBarLayerPositionAtEnd() {
+fun FlickerTest.statusBarLayerPositionAtEnd() {
     assertLayersEnd {
         val display =
             this.entry.displays.minByOrNull { it.id }
@@ -226,7 +230,7 @@
  * Asserts that the [ComponentNameMatcher.STATUS_BAR] layer is at the correct position at the start
  * and end of the SF trace
  */
-fun FlickerTestParameter.statusBarLayerPositionAtStartAndEnd() {
+fun FlickerTest.statusBarLayerPositionAtStartAndEnd() {
     statusBarLayerPositionAtStart()
     statusBarLayerPositionAtEnd()
 }
@@ -235,9 +239,7 @@
  * Asserts that the visibleRegion of the [ComponentNameMatcher.SNAPSHOT] layer can cover the
  * visibleRegion of the given app component exactly
  */
-fun FlickerTestParameter.snapshotStartingWindowLayerCoversExactlyOnApp(
-    component: IComponentNameMatcher
-) {
+fun FlickerTest.snapshotStartingWindowLayerCoversExactlyOnApp(component: IComponentNameMatcher) {
     assertLayers {
         invoke("snapshotStartingWindowLayerCoversExactlyOnApp") {
             val snapshotLayers =
@@ -291,7 +293,7 @@
  *      otherwise we won't and the layer must appear immediately.
  * ```
  */
-fun FlickerTestParameter.replacesLayer(
+fun FlickerTest.replacesLayer(
     originalLayer: IComponentNameMatcher,
     newLayer: IComponentNameMatcher,
     ignoreEntriesWithRotationLayer: Boolean = false,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING b/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING
new file mode 100644
index 0000000..945de33
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/TEST_MAPPING
@@ -0,0 +1,15 @@
+{
+  "ironwood-postsubmit": [
+    {
+      "name": "FlickerTests",
+      "options": [
+        {
+          "include-annotation": "android.platform.test.annotations.IwTest"
+        },
+        {
+          "exclude-annotation": "org.junit.Ignore"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
index 4cf6691..b7bdeeb7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/ActivityEmbeddingTestBase.kt
@@ -17,11 +17,11 @@
 package com.android.server.wm.flicker.activityembedding
 
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
 import org.junit.Before
 
-abstract class ActivityEmbeddingTestBase(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class ActivityEmbeddingTestBase(flicker: FlickerTest) : BaseTest(flicker) {
     val testApp = ActivityEmbeddingAppHelper(instrumentation)
 
     @Before
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
index b23fb5a..ea67729 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/activityembedding/OpenActivityEmbeddingPlaceholderSplit.kt
@@ -17,14 +17,12 @@
 package com.android.server.wm.flicker.activityembedding
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ActivityEmbeddingAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -41,8 +39,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenActivityEmbeddingPlaceholderSplit(testSpec: FlickerTestParameter) :
-    ActivityEmbeddingTestBase(testSpec) {
+class OpenActivityEmbeddingPlaceholderSplit(flicker: FlickerTest) :
+    ActivityEmbeddingTestBase(flicker) {
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -60,7 +58,7 @@
     @Presubmit
     @Test
     fun mainActivityBecomesInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             isVisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
                 .then()
                 .isInvisible(ActivityEmbeddingAppHelper.MAIN_ACTIVITY_COMPONENT)
@@ -70,12 +68,12 @@
     @Presubmit
     @Test
     fun placeholderSplitBecomesVisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
                 .then()
                 .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_PRIMARY_COMPONENT)
         }
-        testSpec.assertLayers {
+        flicker.assertLayers {
             isInvisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
                 .then()
                 .isVisible(ActivityEmbeddingAppHelper.PLACEHOLDER_SECONDARY_COMPONENT)
@@ -142,21 +140,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index b16bfe0..d891714 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -69,7 +69,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppBackButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+class CloseAppBackButtonTest(flicker: FlickerTest) : CloseAppTransition(flicker) {
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -89,13 +89,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): List<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index 78d0860..cc8ef1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -18,11 +18,11 @@
 
 import android.platform.test.annotations.FlakyTest
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -69,7 +69,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseAppHomeButtonTest(testSpec: FlickerTestParameter) : CloseAppTransition(testSpec) {
+class CloseAppHomeButtonTest(flicker: FlickerTest) : CloseAppTransition(flicker) {
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -91,16 +91,11 @@
     override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
     companion object {
-        /**
-         * Creates the test configurations.
-         *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
-         */
+        /** Creates the test configurations. */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index 5bb227f..23503d2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.Presubmit
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
@@ -28,15 +28,15 @@
 import org.junit.Test
 
 /** Base test class for transitions that close an app back to the launcher screen */
-abstract class CloseAppTransition(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class CloseAppTransition(flicker: FlickerTest) : BaseTest(flicker) {
     protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
             testApp.launchViaIntent(wmHelper)
-            this.setRotation(testSpec.startRotation)
+            this.setRotation(flicker.scenario.startRotation)
         }
         teardown { testApp.exit(wmHelper) }
     }
@@ -48,7 +48,7 @@
     @Presubmit
     @Test
     open fun launcherReplacesAppWindowAsTopWindow() {
-        testSpec.assertWm { this.isAppWindowOnTop(testApp).then().isAppWindowOnTop(LAUNCHER) }
+        flicker.assertWm { this.isAppWindowOnTop(testApp).then().isAppWindowOnTop(LAUNCHER) }
     }
 
     /**
@@ -58,17 +58,17 @@
     @Presubmit
     @Test
     open fun launcherWindowBecomesVisible() {
-        testSpec.assertWm { this.isAppWindowNotOnTop(LAUNCHER).then().isAppWindowOnTop(LAUNCHER) }
+        flicker.assertWm { this.isAppWindowNotOnTop(LAUNCHER).then().isAppWindowOnTop(LAUNCHER) }
     }
 
     /** Checks that [LAUNCHER] layer becomes visible when [testApp] becomes invisible */
     @Presubmit
     @Test
     open fun launcherLayerReplacesApp() {
-        testSpec.replacesLayer(
+        flicker.replacesLayer(
             testApp,
             LAUNCHER,
-            ignoreEntriesWithRotationLayer = testSpec.isLandscapeOrSeascapeAtStart
+            ignoreEntriesWithRotationLayer = flicker.scenario.isLandscapeOrSeascapeAtStart
         )
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
index 48e1e64..368cc56 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ActivityEmbeddingAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import android.util.Log
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
@@ -37,10 +35,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.ActivityEmbedding.MainActivity.LABEL,
-    component: ComponentNameMatcher = MAIN_ACTIVITY_COMPONENT,
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = MAIN_ACTIVITY_COMPONENT
+) : StandardAppHelper(instr, launcherName, component) {
 
     /**
      * Clicks the button to launch the placeholder primary activity, which should launch the
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
index efb92f2..18563ff 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/AssistantAppHelper.kt
@@ -25,45 +25,52 @@
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import org.junit.Assert.assertNotNull
 
-class AssistantAppHelper @JvmOverloads constructor(
+class AssistantAppHelper
+@JvmOverloads
+constructor(
     val instr: Instrumentation,
     val component: ComponentName = ActivityOptions.ASSISTANT_SERVICE_COMPONENT_NAME,
 ) {
     protected val uiDevice: UiDevice = UiDevice.getInstance(instr)
-    protected val defaultAssistant: String? = Settings.Secure.getString(
-        instr.targetContext.contentResolver,
-        Settings.Secure.ASSISTANT)
-    protected val defaultVoiceInteractionService: String? = Settings.Secure.getString(
-        instr.targetContext.contentResolver,
-        Settings.Secure.VOICE_INTERACTION_SERVICE)
+    protected val defaultAssistant: String? =
+        Settings.Secure.getString(instr.targetContext.contentResolver, Settings.Secure.ASSISTANT)
+    protected val defaultVoiceInteractionService: String? =
+        Settings.Secure.getString(
+            instr.targetContext.contentResolver,
+            Settings.Secure.VOICE_INTERACTION_SERVICE
+        )
 
     fun setDefaultAssistant() {
         Settings.Secure.putString(
             instr.targetContext.contentResolver,
             Settings.Secure.VOICE_INTERACTION_SERVICE,
-            component.flattenToString())
+            component.flattenToString()
+        )
         Settings.Secure.putString(
             instr.targetContext.contentResolver,
             Settings.Secure.ASSISTANT,
-            component.flattenToString())
+            component.flattenToString()
+        )
     }
 
     fun resetDefaultAssistant() {
         Settings.Secure.putString(
             instr.targetContext.contentResolver,
             Settings.Secure.VOICE_INTERACTION_SERVICE,
-            defaultVoiceInteractionService)
+            defaultVoiceInteractionService
+        )
         Settings.Secure.putString(
             instr.targetContext.contentResolver,
             Settings.Secure.ASSISTANT,
-            defaultAssistant)
+            defaultAssistant
+        )
     }
 
     /**
      * Open Assistance UI.
      *
-     * @param longpress open the UI by long pressing power button.
-     *  Otherwise open the UI through vioceinteraction shell command directly.
+     * @param longpress open the UI by long pressing power button. Otherwise open the UI through
+     * vioceinteraction shell command directly.
      */
     @JvmOverloads
     fun openUI(longpress: Boolean = false) {
@@ -72,9 +79,11 @@
         } else {
             uiDevice.executeShellCommand("cmd voiceinteraction show")
         }
-        val ui = uiDevice.wait(
-            Until.findObject(By.res(ActivityOptions.FLICKER_APP_PACKAGE, "vis_frame")),
-            FIND_TIMEOUT)
+        val ui =
+            uiDevice.wait(
+                Until.findObject(By.res(ActivityOptions.FLICKER_APP_PACKAGE, "vis_frame")),
+                FIND_TIMEOUT
+            )
         assertNotNull("Can't find Assistant UI after long pressing power button.", ui)
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
index 4340bd7..05b50f0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FixedOrientationAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -29,7 +27,5 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.PortraitOnlyActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.PortraitOnlyActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+        ActivityOptions.PortraitOnlyActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
index 73cb862..2ae8e1d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/FlickerExtensions.kt
@@ -18,15 +18,16 @@
 
 package com.android.server.wm.flicker.helpers
 
-import com.android.server.wm.flicker.Flicker
+import com.android.server.wm.flicker.IFlickerTestData
 import com.android.server.wm.flicker.rules.ChangeDisplayOrientationRule
+import com.android.server.wm.traces.common.service.PlatformConsts
 
 /**
  * Changes the device [rotation] and wait for the rotation animation to complete
  *
  * @param rotation New device rotation
  */
-fun Flicker.setRotation(rotation: Int) =
+fun IFlickerTestData.setRotation(rotation: PlatformConsts.Rotation) =
     ChangeDisplayOrientationRule.setRotation(
         rotation,
         instrumentation,
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
index d45315e..d583bba 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/GameAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.Until
@@ -32,10 +30,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.Game.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.Game.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy,
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = ActivityOptions.Game.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
 
     /**
      * Swipes down in the mock game app.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index ca5b2af..b7eea1b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -26,6 +26,7 @@
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.Condition
 import com.android.server.wm.traces.common.DeviceStateDump
+import com.android.server.wm.traces.common.service.PlatformConsts
 import com.android.server.wm.traces.parser.toFlickerComponent
 import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
 import java.util.regex.Pattern
@@ -34,7 +35,7 @@
 @JvmOverloads
 constructor(
     instr: Instrumentation,
-    private val rotation: Int,
+    private val rotation: PlatformConsts.Rotation,
     private val imePackageName: String = IME_PACKAGE,
     launcherName: String = ActivityOptions.Ime.AutoFocusActivity.LABEL,
     component: ComponentNameMatcher =
@@ -63,7 +64,7 @@
             } else {
                 getPackage()
             }
-        launcherStrategy.launch(appName, expectedPackage)
+        open(expectedPackage)
     }
 
     fun startDialogThemedActivity(wmHelper: WindowManagerStateHelper) {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
index cefbf18..3bb7f4e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -31,10 +29,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.Ime.Default.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.Ime.Default.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = ActivityOptions.Ime.Default.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
     /**
      * Opens the IME and wait for it to be displayed
      *
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
index 1502ad5..69d6a47 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeStateInitializeHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -29,7 +27,5 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.Ime.StateInitializeActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.Ime.StateInitializeActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+        ActivityOptions.Ime.StateInitializeActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
index f00904b..d0935ef 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/MailAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Direction
 import androidx.test.uiautomator.UiObject2
@@ -32,10 +30,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.Mail.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.Mail.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = ActivityOptions.Mail.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
 
     fun openMail(rowIdx: Int) {
         val rowSel =
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
index 34294a6..8b3fa18 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NewTasksAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
@@ -32,10 +30,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.LaunchNewTask.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.LaunchNewTask.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = ActivityOptions.LaunchNewTask.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
     fun openNewTask(device: UiDevice, wmHelper: WindowManagerStateHelper) {
         val button =
             device.wait(Until.findObject(By.res(getPackage(), "launch_new_task")), FIND_TIMEOUT)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
index bbb782d..992a1a1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -29,7 +27,5 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.NonResizeableActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.NonResizeableActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+        ActivityOptions.NonResizeableActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
index a3e32e5..c29c752 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NotificationAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
 import com.android.server.wm.flicker.testapp.ActivityOptions
@@ -31,10 +29,8 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.Notification.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.Notification.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+    component: ComponentNameMatcher = ActivityOptions.Notification.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
     fun postNotification(wmHelper: WindowManagerStateHelper) {
         val button =
             uiDevice.wait(Until.findObject(By.res(getPackage(), "post_notification")), FIND_TIMEOUT)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
index 19ee09a..8fe6aac 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/PipAppHelper.kt
@@ -92,8 +92,12 @@
 
         // if the distance per step is less than 1, carry out the animation in two steps
         gestureHelper.pinch(
-                Tuple(initLeftX, yCoord), Tuple(initRightX, yCoord),
-                Tuple(finalLeftX, yCoord), Tuple(finalRightX, yCoord), adjustedSteps)
+            Tuple(initLeftX, yCoord),
+            Tuple(initRightX, yCoord),
+            Tuple(finalLeftX, yCoord),
+            Tuple(finalRightX, yCoord),
+            adjustedSteps
+        )
 
         waitForPipWindowToExpandFrom(wmHelper, Region.from(windowRect))
     }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
index c904352..c51754c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SeamlessRotationAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -29,7 +27,5 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.SeamlessRotation.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.SeamlessRotation.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+        ActivityOptions.SeamlessRotation.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
index de152cb5..9318f20 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ShowWhenLockedAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -29,7 +27,5 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.ShowWhenLockedActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.ShowWhenLockedActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+        ActivityOptions.ShowWhenLockedActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
index e415990..b46ff2c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/SimpleAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -28,7 +26,5 @@
 constructor(
     instr: Instrumentation,
     launcherName: String = ActivityOptions.SimpleActivity.LABEL,
-    component: ComponentNameMatcher = ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
+    component: ComponentNameMatcher = ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
index 1330190..720d962 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -17,8 +17,6 @@
 package com.android.server.wm.flicker.helpers
 
 import android.app.Instrumentation
-import android.support.test.launcherhelper.ILauncherStrategy
-import android.support.test.launcherhelper.LauncherStrategyFactory
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.Until
@@ -33,10 +31,8 @@
     instr: Instrumentation,
     launcherName: String = ActivityOptions.LaunchNewActivity.LABEL,
     component: ComponentNameMatcher =
-        ActivityOptions.LaunchNewActivity.COMPONENT.toFlickerComponent(),
-    launcherStrategy: ILauncherStrategy =
-        LauncherStrategyFactory.getInstance(instr).launcherStrategy
-) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+        ActivityOptions.LaunchNewActivity.COMPONENT.toFlickerComponent()
+) : StandardAppHelper(instr, launcherName, component) {
 
     private val secondActivityComponent =
         ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 1a49595..c735be0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -17,16 +17,15 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,8 +48,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class CloseImeAutoOpenWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -62,43 +61,37 @@
     @Presubmit
     @Test
     fun imeAppWindowIsAlwaysVisible() {
-        testSpec.assertWm { this.isAppWindowOnTop(testApp) }
+        flicker.assertWm { this.isAppWindowOnTop(testApp) }
     }
 
     @Presubmit
     @Test
     fun imeLayerVisibleStart() {
-        testSpec.assertLayersStart { this.isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.IME) }
     }
 
     @Presubmit
     @Test
     fun imeLayerInvisibleEnd() {
-        testSpec.assertLayersEnd { this.isInvisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.IME) }
     }
 
-    @Presubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+    @Presubmit @Test fun imeLayerBecomesInvisible() = flicker.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
     fun imeAppLayerIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    // b/190352379 (IME doesn't show on app launch in 90 degrees)
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                // b/190352379 (IME doesn't show on app launch in 90 degrees)
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index 463efe8..4024f56 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -17,16 +17,15 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,8 +48,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeAutoOpenWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class CloseImeAutoOpenWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -68,43 +67,37 @@
     @Presubmit
     @Test
     fun imeAppWindowBecomesInvisible() {
-        testSpec.assertWm { this.isAppWindowOnTop(testApp).then().isAppWindowNotOnTop(testApp) }
+        flicker.assertWm { this.isAppWindowOnTop(testApp).then().isAppWindowNotOnTop(testApp) }
     }
 
     @Presubmit
     @Test
     fun imeLayerVisibleStart() {
-        testSpec.assertLayersStart { this.isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.IME) }
     }
 
     @Presubmit
     @Test
     fun imeLayerInvisibleEnd() {
-        testSpec.assertLayersEnd { this.isInvisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.IME) }
     }
 
-    @Presubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+    @Presubmit @Test fun imeLayerBecomesInvisible() = flicker.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
     fun imeAppLayerBecomesInvisible() {
-        testSpec.assertLayers { this.isVisible(testApp).then().isInvisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp).then().isInvisible(testApp) }
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    // b/190352379 (IME doesn't show on app launch in 90 degrees)
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                // b/190352379 (IME doesn't show on app launch in 90 degrees)
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
index 91d9a1f..c72405c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeEditorPopupDialogTest.kt
@@ -17,17 +17,16 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeEditorPopupDialogAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.traces.region.RegionSubject
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -38,7 +37,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeEditorPopupDialogTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class CloseImeEditorPopupDialogTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val imeTestApp = ImeEditorPopupDialogAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -59,14 +58,12 @@
         }
     }
 
-    @Presubmit
-    @Test
-    fun imeWindowBecameInvisible() = testSpec.imeWindowBecomesInvisible()
+    @Presubmit @Test fun imeWindowBecameInvisible() = flicker.imeWindowBecomesInvisible()
 
     @Presubmit
     @Test
     fun imeLayerAndImeSnapshotVisibleOnScreen() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(ComponentNameMatcher.IME)
                 .then()
                 .isVisible(ComponentNameMatcher.IME_SNAPSHOT)
@@ -79,7 +76,7 @@
     @Presubmit
     @Test
     fun imeSnapshotAssociatedOnAppVisibleRegion() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.invoke("imeSnapshotAssociatedOnAppVisibleRegion") {
                 val imeSnapshotLayers =
                     it.subjects.filter { subject ->
@@ -106,16 +103,10 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                    listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                    ),
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index b9c875a..afc5f65 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -17,14 +17,15 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarLayerPositionAtStartAndEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Assume
@@ -42,7 +43,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToAppTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class CloseImeWindowToAppTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = ImeAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -59,7 +60,7 @@
     @Presubmit
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.visibleWindowsShownMoreThanOneConsecutiveEntry(
                 listOf(
                     ComponentNameMatcher.IME,
@@ -74,38 +75,48 @@
     @Presubmit
     @Test
     override fun navBarLayerPositionAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        Assume.assumeFalse(testSpec.isLandscapeOrSeascapeAtStart)
-        testSpec.navBarLayerPositionAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        Assume.assumeFalse(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        flicker.navBarLayerPositionAtStartAndEnd()
     }
 
     @FlakyTest
     @Test
     fun navBarLayerPositionAtStartAndEndLandscapeOrSeascapeAtStart() {
-        Assume.assumeFalse(testSpec.isTablet)
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        testSpec.navBarLayerPositionAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        flicker.navBarLayerPositionAtStartAndEnd()
     }
 
-    @Presubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+    @Presubmit @Test fun imeLayerBecomesInvisible() = flicker.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
     fun imeAppLayerIsAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 
     @Presubmit
     @Test
     fun imeAppWindowIsAlwaysVisible() {
-        testSpec.assertWm { this.isAppWindowOnTop(testApp) }
+        flicker.assertWm { this.isAppWindowOnTop(testApp) }
+    }
+
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        super.cujCompleted()
+        navBarLayerPositionAtStartAndEnd()
+        imeLayerBecomesInvisible()
+        imeAppLayerIsAlwaysVisible()
+        imeAppWindowIsAlwaysVisible()
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 1dc3ca5..aedf965 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -16,17 +16,17 @@
 
 package com.android.server.wm.flicker.ime
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -41,7 +41,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class CloseImeWindowToHomeTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class CloseImeWindowToHomeTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = ImeAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -62,7 +62,7 @@
     @Presubmit
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.visibleWindowsShownMoreThanOneConsecutiveEntry(
                 listOf(
                     ComponentNameMatcher.IME,
@@ -77,42 +77,47 @@
     @Presubmit
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
                 listOf(ComponentNameMatcher.IME, ComponentNameMatcher.SPLASH_SCREEN)
             )
         }
     }
 
-    @Presubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+    @Presubmit @Test fun imeLayerBecomesInvisible() = flicker.imeLayerBecomesInvisible()
 
-    @Presubmit @Test fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+    @Presubmit @Test fun imeWindowBecomesInvisible() = flicker.imeWindowBecomesInvisible()
 
     @Presubmit
     @Test
     fun imeAppWindowBecomesInvisible() {
-        testSpec.assertWm { this.isAppWindowVisible(testApp).then().isAppWindowInvisible(testApp) }
+        flicker.assertWm { this.isAppWindowVisible(testApp).then().isAppWindowInvisible(testApp) }
     }
 
     @Presubmit
     @Test
     fun imeAppLayerBecomesInvisible() {
-        testSpec.assertLayers { this.isVisible(testApp).then().isInvisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp).then().isInvisible(testApp) }
+    }
+
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        super.cujCompleted()
+        navBarLayerPositionAtStartAndEnd()
+        imeLayerBecomesInvisible()
+        imeAppWindowBecomesInvisible()
+        imeWindowBecomesInvisible()
+        imeLayerBecomesInvisible()
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
index e0c5edc..3edc15f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CommonAssertions.kt
@@ -18,22 +18,22 @@
 
 package com.android.server.wm.flicker.ime
 
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.traces.common.ComponentNameMatcher
 
-fun FlickerTestParameter.imeLayerBecomesVisible() {
+fun FlickerTest.imeLayerBecomesVisible() {
     assertLayers {
         this.isInvisible(ComponentNameMatcher.IME).then().isVisible(ComponentNameMatcher.IME)
     }
 }
 
-fun FlickerTestParameter.imeLayerBecomesInvisible() {
+fun FlickerTest.imeLayerBecomesInvisible() {
     assertLayers {
         this.isVisible(ComponentNameMatcher.IME).then().isInvisible(ComponentNameMatcher.IME)
     }
 }
 
-fun FlickerTestParameter.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
+fun FlickerTest.imeWindowIsAlwaysVisible(rotatesScreen: Boolean = false) {
     if (rotatesScreen) {
         assertWm {
             this.isNonAppWindowVisible(ComponentNameMatcher.IME)
@@ -47,7 +47,7 @@
     }
 }
 
-fun FlickerTestParameter.imeWindowBecomesVisible() {
+fun FlickerTest.imeWindowBecomesVisible() {
     assertWm {
         this.isNonAppWindowInvisible(ComponentNameMatcher.IME)
             .then()
@@ -55,7 +55,7 @@
     }
 }
 
-fun FlickerTestParameter.imeWindowBecomesInvisible() {
+fun FlickerTest.imeWindowBecomesInvisible() {
     assertWm {
         this.isNonAppWindowVisible(ComponentNameMatcher.IME)
             .then()
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
index 073da4f..da3c62d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeAndDialogThemeAppTest.kt
@@ -18,19 +18,18 @@
 
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import android.view.WindowInsets.Type.ime
 import android.view.WindowInsets.Type.navigationBars
 import android.view.WindowInsets.Type.statusBars
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assert.assertFalse
 import org.junit.Assert.assertTrue
 import org.junit.FixMethodOrder
@@ -47,8 +46,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class LaunchAppShowImeAndDialogThemeAppTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class LaunchAppShowImeAndDialogThemeAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -75,42 +74,36 @@
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
-    /** Checks that [ComponentMatcher.IME] layer becomes visible during the transition */
-    @Presubmit @Test fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible()
+    /** Checks that [ComponentNameMatcher.IME] layer becomes visible during the transition */
+    @Presubmit @Test fun imeWindowIsAlwaysVisible() = flicker.imeWindowIsAlwaysVisible()
 
-    /** Checks that [ComponentMatcher.IME] layer is visible at the end of the transition */
+    /** Checks that [ComponentNameMatcher.IME] layer is visible at the end of the transition */
     @Presubmit
     @Test
     fun imeLayerExistsEnd() {
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.IME) }
     }
 
-    /** Checks that [ComponentMatcher.IME_SNAPSHOT] layer is invisible always. */
+    /** Checks that [ComponentNameMatcher.IME_SNAPSHOT] layer is invisible always. */
     @Presubmit
     @Test
     fun imeSnapshotNotVisible() {
-        testSpec.assertLayers { this.isInvisible(ComponentNameMatcher.IME_SNAPSHOT) }
+        flicker.assertLayers { this.isInvisible(ComponentNameMatcher.IME_SNAPSHOT) }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
index a93f176..4891901 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/LaunchAppShowImeOnStartTest.kt
@@ -17,18 +17,17 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.ImeStateInitializeHelper
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -73,15 +72,15 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class LaunchAppShowImeOnStartTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class LaunchAppShowImeOnStartTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
     private val initializeApp = ImeStateInitializeHelper(instrumentation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
             initializeApp.launchViaIntent(wmHelper)
-            this.setRotation(testSpec.startRotation)
+            this.setRotation(flicker.scenario.startRotation)
         }
         teardown {
             initializeApp.exit(wmHelper)
@@ -93,45 +92,39 @@
         }
     }
 
-    /** Checks that [ComponentMatcher.IME] window becomes visible during the transition */
-    @Presubmit @Test fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+    /** Checks that [ComponentNameMatcher.IME] window becomes visible during the transition */
+    @Presubmit @Test fun imeWindowBecomesVisible() = flicker.imeWindowBecomesVisible()
 
-    /** Checks that [ComponentMatcher.IME] layer becomes visible during the transition */
-    @Presubmit @Test fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+    /** Checks that [ComponentNameMatcher.IME] layer becomes visible during the transition */
+    @Presubmit @Test fun imeLayerBecomesVisible() = flicker.imeLayerBecomesVisible()
 
-    /** Checks that [ComponentMatcher.IME] layer is invisible at the start of the transition */
+    /** Checks that [ComponentNameMatcher.IME] layer is invisible at the start of the transition */
     @Presubmit
     @Test
     fun imeLayerNotExistsStart() {
-        testSpec.assertLayersStart { this.isInvisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersStart { this.isInvisible(ComponentNameMatcher.IME) }
     }
 
-    /** Checks that [ComponentMatcher.IME] layer is visible at the end of the transition */
+    /** Checks that [ComponentNameMatcher.IME] layer is visible at the end of the transition */
     @Presubmit
     @Test
     fun imeLayerExistsEnd() {
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.IME) }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
index a6bd791..33e9574 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowAndCloseTest.kt
@@ -17,18 +17,18 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -46,7 +46,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowAndCloseTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class OpenImeWindowAndCloseTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val simpleApp = SimpleAppHelper(instrumentation)
     private val testApp = ImeAppHelper(instrumentation)
 
@@ -61,9 +61,9 @@
         teardown { simpleApp.exit(wmHelper) }
     }
 
-    @Presubmit @Test fun imeWindowBecomesInvisible() = testSpec.imeWindowBecomesInvisible()
+    @Presubmit @Test fun imeWindowBecomesInvisible() = flicker.imeWindowBecomesInvisible()
 
-    @Presubmit @Test fun imeLayerBecomesInvisible() = testSpec.imeLayerBecomesInvisible()
+    @Presubmit @Test fun imeLayerBecomesInvisible() = flicker.imeLayerBecomesInvisible()
 
     @Presubmit
     @Test
@@ -79,19 +79,21 @@
         super.visibleLayersShownMoreThanOneConsecutiveEntry()
     }
 
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        super.cujCompleted()
+        imeLayerBecomesInvisible()
+        imeWindowBecomesInvisible()
+    }
+
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
index 3e18d59..197564a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowFromFixedOrientationAppTest.kt
@@ -19,17 +19,16 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.snapshotStartingWindowLayerCoversExactlyOnApp
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -46,9 +45,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowFromFixedOrientationAppTest(testSpec: FlickerTestParameter) :
-    BaseTest(testSpec) {
-    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class OpenImeWindowFromFixedOrientationAppTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -63,61 +61,58 @@
             wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
         }
         transitions {
-            // Bring the exist IME activity to the front in landscape mode device rotation.
-            setRotation(Surface.ROTATION_90)
+            // Bring the existing IME activity to the front in landscape mode device rotation.
+            setRotation(PlatformConsts.Rotation.ROTATION_90)
             imeTestApp.launchViaIntent(wmHelper)
         }
         teardown { imeTestApp.exit(wmHelper) }
     }
 
     /** {@inheritDoc} */
-    @Presubmit
+    @Postsubmit
     @Test
     override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
+    @Postsubmit
+    @Test
+    override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
+
     /** {@inheritDoc} */
     @Postsubmit
     @Test
     override fun taskBarLayerIsVisibleAtStartAndEnd() = super.taskBarLayerIsVisibleAtStartAndEnd()
 
-    @Presubmit
-    @Test
-    fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+    @Presubmit @Test fun imeWindowBecomesVisible() = flicker.imeWindowBecomesVisible()
 
-    @Presubmit
-    @Test
-    fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+    @Presubmit @Test fun imeLayerBecomesVisible() = flicker.imeLayerBecomesVisible()
 
     @Postsubmit
     @Test
     fun snapshotStartingWindowLayerCoversExactlyOnApp() {
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
+        flicker.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
     }
 
     @Presubmit
     @Test
     fun snapshotStartingWindowLayerCoversExactlyOnApp_ShellTransit() {
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
+        flicker.snapshotStartingWindowLayerCoversExactlyOnApp(imeTestApp)
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_90),
-                    supportedNavigationModes =
-                    listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_90)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index b43efea..c097511 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -16,16 +16,16 @@
 
 package com.android.server.wm.flicker.ime
 
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -37,7 +37,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class OpenImeWindowTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = ImeAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -50,35 +50,38 @@
         }
     }
 
-    @Presubmit @Test fun imeWindowBecomesVisible() = testSpec.imeWindowBecomesVisible()
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        super.cujCompleted()
+        imeWindowBecomesVisible()
+        appWindowAlwaysVisibleOnTop()
+        layerAlwaysVisible()
+    }
+
+    @Presubmit @Test fun imeWindowBecomesVisible() = flicker.imeWindowBecomesVisible()
 
     @Presubmit
     @Test
     fun appWindowAlwaysVisibleOnTop() {
-        testSpec.assertWm { this.isAppWindowOnTop(testApp) }
+        flicker.assertWm { this.isAppWindowOnTop(testApp) }
     }
 
-    @Presubmit @Test fun imeLayerBecomesVisible() = testSpec.imeLayerBecomesVisible()
+    @Presubmit @Test fun imeLayerBecomesVisible() = flicker.imeLayerBecomesVisible()
 
     @Presubmit
     @Test
     fun layerAlwaysVisible() {
-        testSpec.assertLayers { this.isVisible(testApp) }
+        flicker.assertLayers { this.isVisible(testApp) }
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0),
-                    supportedNavigationModes =
-                        listOf(
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                            WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                        )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
index 0a7701e..209eb0c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowToOverViewTest.kt
@@ -18,15 +18,13 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtStartAndEnd
 import com.android.server.wm.flicker.statusBarLayerIsVisibleAtStartAndEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
@@ -48,8 +46,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenImeWindowToOverViewTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+class OpenImeWindowToOverViewTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -82,7 +80,7 @@
      */
     private fun waitNavStatusBarVisibility(stateSync: WindowManagerStateHelper.StateSyncBuilder) {
         when {
-            testSpec.isLandscapeOrSeascapeAtStart && !testSpec.isTablet ->
+            flicker.scenario.isLandscapeOrSeascapeAtStart && !flicker.scenario.isTablet ->
                 stateSync.add(WindowManagerConditionsFactory.isStatusBarVisible().negate())
             else -> stateSync.withNavOrTaskBarVisible().withStatusBarVisible()
         }
@@ -91,25 +89,25 @@
     @Presubmit
     @Test
     fun imeWindowIsAlwaysVisible() {
-        testSpec.imeWindowIsAlwaysVisible()
+        flicker.imeWindowIsAlwaysVisible()
     }
 
     @Presubmit
     @Test
     fun navBarLayerIsVisibleAtStartAndEnd3Button() {
-        Assume.assumeFalse(testSpec.isTablet)
-        Assume.assumeFalse(testSpec.isGesturalNavigation)
-        testSpec.navBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+        flicker.navBarLayerIsVisibleAtStartAndEnd()
     }
 
     /** Bars are expected to be hidden while entering overview in landscape (b/227189877) */
     @Presubmit
     @Test
     fun navBarLayerIsVisibleAtStartAndEndGestural() {
-        Assume.assumeFalse(testSpec.isTablet)
-        Assume.assumeTrue(testSpec.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.navBarLayerIsVisibleAtStartAndEnd()
+        flicker.navBarLayerIsVisibleAtStartAndEnd()
     }
 
     /**
@@ -119,12 +117,12 @@
     @Presubmit
     @Test
     fun navBarLayerIsInvisibleInLandscapeGestural() {
-        Assume.assumeFalse(testSpec.isTablet)
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        Assume.assumeTrue(testSpec.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.assertLayersStart { this.isVisible(ComponentNameMatcher.NAV_BAR) }
-        testSpec.assertLayersEnd { this.isInvisible(ComponentNameMatcher.NAV_BAR) }
+        flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.NAV_BAR) }
+        flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.NAV_BAR) }
     }
 
     /**
@@ -134,11 +132,11 @@
     @Presubmit
     @Test
     fun statusBarLayerIsInvisibleInLandscapePhone() {
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        Assume.assumeTrue(testSpec.isGesturalNavigation)
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
-        testSpec.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
     }
 
     /**
@@ -148,35 +146,31 @@
     @Presubmit
     @Test
     fun statusBarLayerIsInvisibleInLandscapeTablet() {
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        Assume.assumeTrue(testSpec.isGesturalNavigation)
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.statusBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.statusBarLayerIsVisibleAtStartAndEnd()
     }
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
-    override fun navBarLayerIsVisibleAtStartAndEnd() {
-    }
+    override fun navBarLayerIsVisibleAtStartAndEnd() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
-    override fun navBarLayerPositionAtStartAndEnd() {
-    }
+    override fun navBarLayerPositionAtStartAndEnd() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
-    override fun statusBarLayerPositionAtStartAndEnd() {
-    }
+    override fun statusBarLayerPositionAtStartAndEnd() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Visibility changes depending on orientation and navigation mode")
-    override fun statusBarLayerIsVisibleAtStartAndEnd() {
-    }
+    override fun statusBarLayerIsVisibleAtStartAndEnd() {}
 
     @Presubmit
     @Test
@@ -185,38 +179,38 @@
     @Presubmit
     @Test
     fun statusBarLayerIsVisibleInPortrait() {
-        Assume.assumeFalse(testSpec.isLandscapeOrSeascapeAtStart)
-        testSpec.statusBarLayerIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        flicker.statusBarLayerIsVisibleAtStartAndEnd()
     }
 
     @Presubmit
     @Test
     fun statusBarLayerIsInvisibleInLandscapeShell() {
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        Assume.assumeFalse(testSpec.isTablet)
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        Assume.assumeFalse(flicker.scenario.isTablet)
         Assume.assumeTrue(isShellTransitionsEnabled)
-        testSpec.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
-        testSpec.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayersStart { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayersEnd { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
     }
 
     @Presubmit
     @Test
     fun statusBarLayerIsVisibleInLandscapeLegacy() {
-        Assume.assumeTrue(testSpec.isLandscapeOrSeascapeAtStart)
-        Assume.assumeTrue(testSpec.isTablet)
+        Assume.assumeTrue(flicker.scenario.isLandscapeOrSeascapeAtStart)
+        Assume.assumeTrue(flicker.scenario.isTablet)
         Assume.assumeFalse(isShellTransitionsEnabled)
-        testSpec.statusBarLayerIsVisibleAtStartAndEnd()
+        flicker.statusBarLayerIsVisibleAtStartAndEnd()
     }
 
     @Presubmit
     @Test
     fun imeLayerIsVisibleAndAssociatedWithAppWidow() {
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             isVisible(ComponentNameMatcher.IME)
                 .visibleRegion(ComponentNameMatcher.IME)
                 .coversAtMost(isVisible(imeTestApp).visibleRegion(imeTestApp).region)
         }
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.invoke("imeLayerIsVisibleAndAlignAppWidow") {
                 val imeVisibleRegion = it.visibleRegion(ComponentNameMatcher.IME)
                 val appVisibleRegion = it.visibleRegion(imeTestApp)
@@ -232,21 +226,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90),
-                    supportedNavigationModes =
-                    listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY,
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
-                    )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index f810fbb..38791a2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -17,17 +17,17 @@
 package com.android.server.wm.flicker.ime
 
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.reopenAppFromOverview
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -41,8 +41,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class ReOpenImeWindowTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
-    private val testApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+open class ReOpenImeWindowTest(flicker: FlickerTest) : BaseTest(flicker) {
+    private val testApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -50,7 +50,7 @@
             tapl.workspace.switchToOverview().dismissAllTasks()
             testApp.launchViaIntent(wmHelper)
             testApp.openIME(wmHelper)
-            this.setRotation(testSpec.startRotation)
+            this.setRotation(flicker.scenario.startRotation)
             device.pressRecentApps()
             wmHelper.StateSyncBuilder().withRecentsActivityVisible().waitForAndVerify()
         }
@@ -68,7 +68,7 @@
         // depends on how much of the animation transactions are sent to SF at once
         // sometimes this layer appears for 2-3 frames, sometimes for only 1
         val recentTaskComponent = ComponentNameMatcher("", "RecentTaskScreenshotSurface")
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
                 listOf(
                     ComponentNameMatcher.SPLASH_SCREEN,
@@ -84,14 +84,14 @@
     @Test
     override fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
         val component = ComponentNameMatcher("", "RecentTaskScreenshotSurface")
-        testSpec.assertWm {
+        flicker.assertWm {
             this.visibleWindowsShownMoreThanOneConsecutiveEntry(
                 ignoreWindows =
-                listOf(
-                    ComponentNameMatcher.SPLASH_SCREEN,
-                    ComponentNameMatcher.SNAPSHOT,
-                    component
-                )
+                    listOf(
+                        ComponentNameMatcher.SPLASH_SCREEN,
+                        ComponentNameMatcher.SNAPSHOT,
+                        component
+                    )
             )
         }
     }
@@ -99,16 +99,14 @@
     @Presubmit
     @Test
     fun launcherWindowBecomesInvisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowVisible(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isAppWindowInvisible(ComponentNameMatcher.LAUNCHER)
         }
     }
 
-    @Presubmit
-    @Test
-    fun imeWindowIsAlwaysVisible() = testSpec.imeWindowIsAlwaysVisible()
+    @Presubmit @Test fun imeWindowIsAlwaysVisible() = flicker.imeWindowIsAlwaysVisible()
 
     @Presubmit
     @Test
@@ -117,19 +115,19 @@
         // and exiting overview. Since we log 1x per frame, sometimes the activity visibility
         // and the app visibility are updated together, sometimes not, thus ignore activity
         // check at the start
-        testSpec.assertWm { this.isAppWindowVisible(testApp) }
+        flicker.assertWm { this.isAppWindowVisible(testApp) }
     }
 
     @Presubmit
     @Test
     fun imeLayerBecomesVisible() {
-        testSpec.assertLayers { this.isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayers { this.isVisible(ComponentNameMatcher.IME) }
     }
 
     @Presubmit
     @Test
     fun appLayerReplacesLauncher() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -141,9 +139,10 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0))
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
index 0ca6457..a6bbf54 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest.kt
@@ -19,19 +19,18 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ImeAppAutoFocusHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -49,9 +48,9 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Presubmit
-open class SwitchImeWindowsFromGestureNavTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+open class SwitchImeWindowsFromGestureNavTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = SimpleAppHelper(instrumentation)
-    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, testSpec.startRotation)
+    private val imeTestApp = ImeAppAutoFocusHelper(instrumentation, flicker.scenario.startRotation)
 
     @Before
     open fun before() {
@@ -63,7 +62,7 @@
         setup {
             tapl.setExpectedRotationCheckEnabled(false)
             tapl.setIgnoreTaskbarVisibility(true)
-            this.setRotation(testSpec.startRotation)
+            this.setRotation(flicker.scenario.startRotation)
             testApp.launchViaIntent(wmHelper)
             wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
 
@@ -143,7 +142,7 @@
     @Presubmit
     @Test
     fun imeAppWindowVisibility() {
-        testSpec.assertWm {
+        flicker.assertWm {
             isAppWindowVisible(imeTestApp)
                 .then()
                 .isAppSnapshotStartingWindowVisibleFor(testApp, isOptional = true)
@@ -159,27 +158,25 @@
     @FlakyTest(bugId = 244414110)
     @Test
     open fun imeLayerIsVisibleWhenSwitchingToImeApp() {
-        testSpec.assertLayersStart { isVisible(ComponentNameMatcher.IME) }
-        testSpec.assertLayersTag(TAG_IME_VISIBLE) { isVisible(ComponentNameMatcher.IME) }
-        testSpec.assertLayersEnd { isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersStart { isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersTag(TAG_IME_VISIBLE) { isVisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersEnd { isVisible(ComponentNameMatcher.IME) }
     }
 
     @Presubmit
     @Test
     fun imeLayerIsInvisibleWhenSwitchingToTestApp() {
-        testSpec.assertLayersTag(TAG_IME_INVISIBLE) { isInvisible(ComponentNameMatcher.IME) }
+        flicker.assertLayersTag(TAG_IME_INVISIBLE) { isInvisible(ComponentNameMatcher.IME) }
     }
 
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL),
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
 
         private const val TAG_IME_VISIBLE = "imeVisible"
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt
index 80ab016..c599b10 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/SwitchImeWindowsFromGestureNavTest_ShellTransit.kt
@@ -18,10 +18,11 @@
 
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd
+import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -39,16 +40,14 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class SwitchImeWindowsFromGestureNavTest_ShellTransit(testSpec: FlickerTestParameter) :
-    SwitchImeWindowsFromGestureNavTest(testSpec) {
+class SwitchImeWindowsFromGestureNavTest_ShellTransit(flicker: FlickerTest) :
+    SwitchImeWindowsFromGestureNavTest(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
     }
 
-    @Presubmit
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    @Presubmit @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     @Presubmit
     @Test
@@ -71,13 +70,13 @@
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /**
-     * Checks that [ComponentMatcher.NAV_BAR] window is visible and above the app windows at the
+     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
      * start and end of the WM trace
      */
     @Presubmit
     @Test
     fun navBarWindowIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsVisibleAtStartAndEnd()
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
index 49bf86d0..5e50b45 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -20,11 +20,11 @@
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.parser.toFlickerComponent
@@ -57,13 +57,13 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ActivitiesTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class ActivitiesTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
             testApp.launchViaIntent(wmHelper)
         }
         teardown { testApp.exit(wmHelper) }
@@ -91,7 +91,7 @@
             ActivityOptions.LaunchNewActivity.COMPONENT.toFlickerComponent()
         val imeAutoFocusActivityComponent =
             ActivityOptions.SimpleActivity.COMPONENT.toFlickerComponent()
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowOnTop(buttonActivityComponent)
                 .then()
                 .isAppWindowOnTop(imeAutoFocusActivityComponent)
@@ -108,7 +108,7 @@
     @Presubmit
     @Test
     fun launcherWindowNotOnTop() {
-        testSpec.assertWm { this.isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER) }
+        flicker.assertWm { this.isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER) }
     }
 
     /**
@@ -117,20 +117,20 @@
     @Presubmit
     @Test
     fun launcherLayerNotVisible() {
-        testSpec.assertLayers { this.isInvisible(ComponentNameMatcher.LAUNCHER) }
+        flicker.assertLayers { this.isInvisible(ComponentNameMatcher.LAUNCHER) }
     }
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
index d0d7bbb..14a6668 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest.kt
@@ -17,12 +17,12 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.CameraAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -41,8 +41,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppAfterCameraTest(testSpec: FlickerTestParameter) :
-    OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppAfterCameraTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
     @Before
     open fun before() {
         Assume.assumeFalse(isShellTransitionsEnabled)
@@ -69,13 +68,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt
index 5686965..99574ef 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppAfterCameraTest_ShellTransit.kt
@@ -18,9 +18,9 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -40,8 +40,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppAfterCameraTest_ShellTransit(testSpec: FlickerTestParameter) :
-    OpenAppAfterCameraTest(testSpec) {
+class OpenAppAfterCameraTest_ShellTransit(flicker: FlickerTest) : OpenAppAfterCameraTest(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
index 5e6fc21..e0df5be 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdFromIcon.kt
@@ -18,13 +18,12 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -55,17 +54,16 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppColdFromIcon(testSpec: FlickerTestParameter) :
-    OpenAppFromLauncherTransition(testSpec) {
+class OpenAppColdFromIcon(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
-                if (testSpec.isTablet) {
-                    tapl.setExpectedRotation(testSpec.startRotation)
+                if (flicker.scenario.isTablet) {
+                    tapl.setExpectedRotation(flicker.scenario.startRotation.value)
                 } else {
-                    tapl.setExpectedRotation(Surface.ROTATION_0)
+                    tapl.setExpectedRotation(PlatformConsts.Rotation.ROTATION_0.value)
                 }
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
             }
@@ -180,19 +178,16 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                // TAPL fails on landscape mode b/240916028
-                .getConfigNonRotationTests(
-                    supportedNavigationModes = listOf(
-                        WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON_OVERLAY
-                    )
-                )
+        fun getParams(): Collection<FlickerTest> {
+            // TAPL fails on landscape mode b/240916028
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_3BUTTON)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index 7576ab9..66af72e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -19,12 +19,12 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
-import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -57,15 +57,14 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppColdTest(testSpec: FlickerTestParameter) :
-    OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppColdTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
             super.transition(this)
             setup {
                 removeAllTasksButHome()
-                this.setRotation(testSpec.startRotation)
+                this.setRotation(flicker.scenario.startRotation)
             }
             teardown { testApp.exit(wmHelper) }
             transitions { testApp.launchViaIntent(wmHelper) }
@@ -83,13 +82,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
index 23748be..b234ec7 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLauncherTransition.kt
@@ -17,28 +17,27 @@
 package com.android.server.wm.flicker.launch
 
 import android.platform.test.annotations.Presubmit
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.replacesLayer
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Test
 
 /** Base class for app launch tests */
-abstract class OpenAppFromLauncherTransition(testSpec: FlickerTestParameter) :
-    OpenAppTransition(testSpec) {
+abstract class OpenAppFromLauncherTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
 
-    /** Checks that the focus changes from the [ComponentMatcher.LAUNCHER] to [testApp] */
+    /** Checks that the focus changes from the [ComponentNameMatcher.LAUNCHER] to [testApp] */
     @Presubmit
     @Test
     open fun focusChanges() {
-        testSpec.assertEventLog { this.focusChanges("NexusLauncherActivity", testApp.`package`) }
+        flicker.assertEventLog { this.focusChanges("NexusLauncherActivity", testApp.`package`) }
     }
 
     /**
-     * Checks that [ComponentMatcher.LAUNCHER] layer is visible at the start of the transition, and
-     * is replaced by [testApp], which remains visible until the end
+     * Checks that [ComponentNameMatcher.LAUNCHER] layer is visible at the start of the transition,
+     * and is replaced by [testApp], which remains visible until the end
      */
     open fun appLayerReplacesLauncher() {
-        testSpec.replacesLayer(
+        flicker.replacesLayer(
             ComponentNameMatcher.LAUNCHER,
             testApp,
             ignoreEntriesWithRotationLayer = true,
@@ -48,14 +47,14 @@
     }
 
     /**
-     * Checks that [ComponentMatcher.LAUNCHER] window is the top window at the start of the
-     * transition, and is replaced by a [ComponentMatcher.SNAPSHOT] or
-     * [ComponentMatcher.SPLASH_SCREEN], or [testApp], which remains visible until the end
+     * Checks that [ComponentNameMatcher.LAUNCHER] window is the top window at the start of the
+     * transition, and is replaced by a [ComponentNameMatcher.SNAPSHOT] or
+     * [ComponentNameMatcher.SPLASH_SCREEN], or [testApp], which remains visible until the end
      */
     @Presubmit
     @Test
     open fun appWindowReplacesLauncherAsTopWindow() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isAppWindowOnTop(
@@ -68,6 +67,6 @@
     @Presubmit
     @Test
     open fun appWindowAsTopWindowAtEnd() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp) }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 0edbc86..f5f7190 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -20,10 +20,10 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
 import org.junit.Ignore
@@ -44,8 +44,8 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Postsubmit
-open class OpenAppFromLockNotificationCold(testSpec: FlickerTestParameter) :
-    OpenAppFromNotificationCold(testSpec) {
+open class OpenAppFromLockNotificationCold(flicker: FlickerTest) :
+    OpenAppFromNotificationCold(flicker) {
 
     override val openingNotificationsFromLockScreen = true
 
@@ -93,8 +93,9 @@
      * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
      * transition
      */
-    @Presubmit @Test override fun statusBarLayerPositionAtEnd() =
-        super.statusBarLayerPositionAtEnd()
+    @Presubmit
+    @Test
+    override fun statusBarLayerPositionAtEnd() = super.statusBarLayerPositionAtEnd()
 
     /** {@inheritDoc} */
     @Test
@@ -119,13 +120,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 5a7b8b9..fe49c61 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -19,10 +19,10 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
@@ -43,8 +43,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OpenAppFromLockNotificationWarm(testSpec: FlickerTestParameter) :
-    OpenAppFromNotificationWarm(testSpec) {
+class OpenAppFromLockNotificationWarm(flicker: FlickerTest) : OpenAppFromNotificationWarm(flicker) {
 
     override val openingNotificationsFromLockScreen = true
 
@@ -70,7 +69,7 @@
     @Test
     @Presubmit
     fun appWindowBecomesFirstAndOnlyTopWindow() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.hasNoVisibleAppWindow()
                 .then()
                 .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -85,7 +84,7 @@
     @Test
     @Presubmit
     fun screenLockedStart() {
-        testSpec.assertWmStart { isKeyguardShowing() }
+        flicker.assertWmStart { isKeyguardShowing() }
     }
 
     /** {@inheritDoc} */
@@ -108,7 +107,7 @@
      * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
      * transition
      */
-    @Presubmit @Test fun statusBarLayerPositionAtEnd() = testSpec.statusBarLayerPositionAtEnd()
+    @Presubmit @Test fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd()
 
     /** {@inheritDoc} */
     @Test
@@ -133,13 +132,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 4ee1283..d9a3ad2 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -20,12 +20,12 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.ShowWhenLockedAppHelper
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -44,8 +44,8 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Postsubmit
-class OpenAppFromLockNotificationWithLockOverlayApp(testSpec: FlickerTestParameter) :
-    OpenAppFromLockNotificationCold(testSpec) {
+class OpenAppFromLockNotificationWithLockOverlayApp(flicker: FlickerTest) :
+    OpenAppFromLockNotificationCold(flicker) {
     private val showWhenLockedApp: ShowWhenLockedAppHelper =
         ShowWhenLockedAppHelper(instrumentation)
 
@@ -74,7 +74,7 @@
     @Test
     @FlakyTest(bugId = 227143265)
     fun showWhenLockedAppWindowBecomesVisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.hasNoVisibleAppWindow()
                 .then()
                 .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -86,7 +86,7 @@
     @Test
     @FlakyTest(bugId = 227143265)
     fun showWhenLockedAppLayerBecomesVisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isInvisible(showWhenLockedApp)
                 .then()
                 .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -107,20 +107,19 @@
     /** {@inheritDoc} */
     @FlakyTest(bugId = 209599395)
     @Test
-    override fun navBarLayerIsVisibleAtStartAndEnd() =
-        super.navBarLayerIsVisibleAtStartAndEnd()
+    override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
 
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index 3cc2390..718c6e9 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.navBarLayerPositionAtEnd
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
@@ -28,8 +28,7 @@
 import org.junit.Test
 
 /** Base class for app launch tests from lock screen */
-abstract class OpenAppFromLockTransition(testSpec: FlickerTestParameter) :
-    OpenAppTransition(testSpec) {
+abstract class OpenAppFromLockTransition(flicker: FlickerTest) : OpenAppTransition(flicker) {
 
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit = {
@@ -46,7 +45,7 @@
     @Presubmit
     @Test
     open fun focusChanges() {
-        testSpec.assertEventLog { this.focusChanges("", testApp.`package`) }
+        flicker.assertEventLog { this.focusChanges("", testApp.`package`) }
     }
 
     /**
@@ -56,7 +55,7 @@
     @FlakyTest(bugId = 203538234)
     @Test
     open fun appWindowBecomesFirstAndOnlyTopWindow() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.hasNoVisibleAppWindow()
                 .then()
                 .isAppWindowOnTop(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -71,7 +70,7 @@
     @Presubmit
     @Test
     fun screenLockedStart() {
-        testSpec.assertLayersStart { isEmpty() }
+        flicker.assertLayersStart { isEmpty() }
     }
 
     /** {@inheritDoc} */
@@ -99,16 +98,16 @@
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
     override fun taskBarWindowIsAlwaysVisible() {}
 
-    /** Checks the position of the [ComponentMatcher.NAV_BAR] at the end of the transition */
+    /** Checks the position of the [ComponentNameMatcher.NAV_BAR] at the end of the transition */
     @Presubmit
     @Test
     open fun navBarLayerPositionAtEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerPositionAtEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerPositionAtEnd()
     }
 
-    /** Checks the position of the [ComponentMatcher.STATUS_BAR] at the end of the transition */
-    @Presubmit @Test fun statusBarLayerPositionAtEnd() = testSpec.statusBarLayerPositionAtEnd()
+    /** Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the end of the transition */
+    @Presubmit @Test fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd()
 
     /** {@inheritDoc} */
     @Test
@@ -116,13 +115,13 @@
     override fun statusBarLayerIsVisibleAtStartAndEnd() {}
 
     /**
-     * Checks that the [ComponentMatcher.STATUS_BAR] layer is visible at the end of the trace
+     * Checks that the [ComponentNameMatcher.STATUS_BAR] layer is visible at the end of the trace
      *
      * It is not possible to check at the start because the screen is off
      */
     @Presubmit
     @Test
     fun statusBarLayerIsVisibleAtEnd() {
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index 8dd94cd..240e90b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -19,10 +19,10 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.statusBarLayerPositionAtEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
@@ -44,8 +44,8 @@
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 @Postsubmit
-open class OpenAppFromNotificationCold(testSpec: FlickerTestParameter) :
-    OpenAppFromNotificationWarm(testSpec) {
+open class OpenAppFromNotificationCold(flicker: FlickerTest) :
+    OpenAppFromNotificationWarm(flicker) {
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -61,13 +61,9 @@
             }
         }
 
-    @Postsubmit
-    @Test
-    override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
+    @Postsubmit @Test override fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
 
-    @Postsubmit
-    @Test
-    override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
+    @Postsubmit @Test override fun appLayerBecomesVisible() = appLayerBecomesVisible_coldStart()
 
     /** {@inheritDoc} */
     @Test
@@ -89,9 +85,7 @@
      * Checks the position of the [ComponentNameMatcher.STATUS_BAR] at the start and end of the
      * transition
      */
-    @Presubmit
-    @Test
-    open fun statusBarLayerPositionAtEnd() = testSpec.statusBarLayerPositionAtEnd()
+    @Presubmit @Test open fun statusBarLayerPositionAtEnd() = flicker.statusBarLayerPositionAtEnd()
 
     /** {@inheritDoc} */
     @Test
@@ -107,13 +101,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index db48b3f..6388a5a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -24,13 +24,13 @@
 import android.view.WindowManager
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.Until
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.NotificationAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarLayerIsVisibleAtEnd
 import com.android.server.wm.flicker.navBarLayerPositionAtEnd
 import com.android.server.wm.flicker.navBarWindowIsVisibleAtEnd
@@ -56,8 +56,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromNotificationWarm(testSpec: FlickerTestParameter) :
-    OpenAppTransition(testSpec) {
+open class OpenAppFromNotificationWarm(flicker: FlickerTest) : OpenAppTransition(flicker) {
     override val testApp: NotificationAppHelper = NotificationAppHelper(instrumentation)
 
     open val openingNotificationsFromLockScreen = false
@@ -67,7 +66,7 @@
         get() = {
             setup {
                 device.wakeUpAndGoToHomeScreen()
-                this.setRotation(testSpec.startRotation)
+                this.setRotation(flicker.scenario.startRotation)
                 testApp.launchViaIntent(wmHelper)
                 wmHelper.StateSyncBuilder().withFullScreenApp(testApp).waitForAndVerify()
                 testApp.postNotification(wmHelper)
@@ -120,19 +119,19 @@
     @Presubmit
     @Test
     open fun notificationAppWindowVisibleAtEnd() {
-        testSpec.assertWmEnd { this.isAppWindowVisible(testApp) }
+        flicker.assertWmEnd { this.isAppWindowVisible(testApp) }
     }
 
     @Presubmit
     @Test
     open fun notificationAppWindowOnTopAtEnd() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp) }
     }
 
     @Presubmit
     @Test
     open fun notificationAppLayerVisibleAtEnd() {
-        testSpec.assertLayersEnd { this.isVisible(testApp) }
+        flicker.assertLayersEnd { this.isVisible(testApp) }
     }
 
     /**
@@ -144,8 +143,8 @@
     @Presubmit
     @Test
     open fun taskBarWindowIsVisibleAtEnd() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarWindowIsVisibleAtEnd()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarWindowIsVisibleAtEnd()
     }
 
     /**
@@ -156,31 +155,31 @@
     @Presubmit
     @Test
     open fun taskBarLayerIsVisibleAtEnd() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.taskBarLayerIsVisibleAtEnd()
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.taskBarLayerIsVisibleAtEnd()
     }
 
     /** Checks the position of the [ComponentNameMatcher.NAV_BAR] at the end of the transition */
     @Presubmit
     @Test
     open fun navBarLayerPositionAtEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerPositionAtEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerPositionAtEnd()
     }
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
     open fun navBarLayerIsVisibleAtEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarLayerIsVisibleAtEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarLayerIsVisibleAtEnd()
     }
 
     @Presubmit
     @Test
     open fun navBarWindowIsVisibleAtEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsVisibleAtEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsVisibleAtEnd()
     }
 
     /** {@inheritDoc} */
@@ -203,13 +202,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index fd8a38c..9106835 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -19,13 +19,13 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
-import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -59,8 +59,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) :
-    OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppFromOverviewTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
 
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
@@ -72,14 +71,14 @@
                 tapl.goHome()
                 wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
                 // By default, launcher doesn't rotate on phones, but rotates on tablets
-                if (testSpec.isTablet) {
-                    tapl.setExpectedRotation(testSpec.startRotation)
+                if (flicker.scenario.isTablet) {
+                    tapl.setExpectedRotation(flicker.scenario.startRotation.value)
                 } else {
-                    tapl.setExpectedRotation(Surface.ROTATION_0)
+                    tapl.setExpectedRotation(PlatformConsts.Rotation.ROTATION_0.value)
                 }
                 tapl.workspace.switchToOverview()
                 wmHelper.StateSyncBuilder().withRecentsActivityVisible().waitForAndVerify()
-                this.setRotation(testSpec.startRotation)
+                this.setRotation(flicker.scenario.startRotation)
             }
             transitions {
                 tapl.overview.currentTask.open()
@@ -109,13 +108,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 1ecde46..f295ce3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -20,14 +20,13 @@
 import android.platform.test.annotations.Postsubmit
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Ignore
@@ -63,8 +62,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) :
-    OpenAppFromLockTransition(testSpec) {
+open class OpenAppNonResizeableTest(flicker: FlickerTest) : OpenAppFromLockTransition(flicker) {
     override val testApp = NonResizeableAppHelper(instrumentation)
 
     /**
@@ -74,8 +72,8 @@
     @FlakyTest(bugId = 227083463)
     @Test
     fun navBarLayerVisibilityChanges() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.assertLayers {
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.assertLayers {
             this.isInvisible(ComponentNameMatcher.NAV_BAR)
                 .then()
                 .isVisible(ComponentNameMatcher.NAV_BAR)
@@ -86,7 +84,7 @@
     @Presubmit
     @Test
     fun appWindowBecomesVisibleAtEnd() {
-        testSpec.assertWmEnd { this.isAppWindowVisible(testApp) }
+        flicker.assertWmEnd { this.isAppWindowVisible(testApp) }
     }
 
     /**
@@ -96,8 +94,8 @@
     @Presubmit
     @Test
     fun navBarWindowsVisibilityChanges() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.assertWm {
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.assertWm {
             this.isNonAppWindowInvisible(ComponentNameMatcher.NAV_BAR)
                 .then()
                 .isAboveAppWindowVisible(ComponentNameMatcher.NAV_BAR)
@@ -111,8 +109,8 @@
     @Presubmit
     @Test
     fun taskBarLayerIsVisibleAtEnd() {
-        Assume.assumeTrue(testSpec.isTablet)
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.TASK_BAR) }
+        Assume.assumeTrue(flicker.scenario.isTablet)
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.TASK_BAR) }
     }
 
     /**
@@ -123,45 +121,40 @@
     @Presubmit
     @Test
     override fun statusBarLayerIsVisibleAtStartAndEnd() {
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.STATUS_BAR) }
     }
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
-    override fun taskBarLayerIsVisibleAtStartAndEnd() {
-    }
+    override fun taskBarLayerIsVisibleAtStartAndEnd() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
-    override fun navBarLayerIsVisibleAtStartAndEnd() {
-    }
+    override fun navBarLayerIsVisibleAtStartAndEnd() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
-    override fun taskBarWindowIsAlwaysVisible() {
-    }
+    override fun taskBarWindowIsAlwaysVisible() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
-    override fun navBarWindowIsAlwaysVisible() {
-    }
+    override fun navBarWindowIsAlwaysVisible() {}
 
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. Display starts off and app is full screen at the end")
-    override fun statusBarWindowIsAlwaysVisible() {
-    }
+    override fun statusBarWindowIsAlwaysVisible() {}
 
     /** Checks the [ComponentNameMatcher.NAV_BAR] is visible at the end of the transition */
     @Postsubmit
     @Test
     fun navBarLayerIsVisibleAtEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.assertLayersEnd { this.isVisible(ComponentNameMatcher.NAV_BAR) }
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.assertLayersEnd { this.isVisible(ComponentNameMatcher.NAV_BAR) }
     }
 
     /** {@inheritDoc} */
@@ -174,7 +167,7 @@
     @Presubmit
     @Test
     override fun appLayerBecomesVisible() {
-        Assume.assumeFalse(testSpec.isTablet)
+        Assume.assumeFalse(flicker.scenario.isTablet)
         super.appLayerBecomesVisible()
     }
 
@@ -182,14 +175,12 @@
     @FlakyTest(bugId = 227143265)
     @Test
     fun appLayerBecomesVisibleTablet() {
-        Assume.assumeTrue(testSpec.isTablet)
+        Assume.assumeTrue(flicker.scenario.isTablet)
         super.appLayerBecomesVisible()
     }
 
     /** {@inheritDoc} */
-    @FlakyTest
-    @Test
-    override fun entireScreenCovered() = super.entireScreenCovered()
+    @FlakyTest @Test override fun entireScreenCovered() = super.entireScreenCovered()
 
     @FlakyTest(bugId = 218470989)
     @Test
@@ -210,18 +201,16 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL),
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 4fd251a..2adb0b4 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -18,8 +18,8 @@
 
 import android.platform.test.annotations.Presubmit
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
@@ -28,15 +28,15 @@
 import org.junit.Test
 
 /** Base class for app launch tests */
-abstract class OpenAppTransition(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class OpenAppTransition(flicker: FlickerTest) : BaseTest(flicker) {
     protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
             device.wakeUpAndGoToHomeScreen()
-            this.setRotation(testSpec.startRotation)
+            this.setRotation(flicker.scenario.startRotation)
         }
         teardown { testApp.exit(wmHelper) }
     }
@@ -52,7 +52,7 @@
     }
 
     protected fun appLayerBecomesVisible_coldStart() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.notContains(testApp)
                 .then()
                 .isInvisible(testApp, isOptional = true)
@@ -66,7 +66,7 @@
     }
 
     protected fun appLayerBecomesVisible_warmStart() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isInvisible(testApp)
                 .then()
                 .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -87,7 +87,7 @@
     @Presubmit @Test open fun appWindowBecomesVisible() = appWindowBecomesVisible_coldStart()
 
     protected fun appWindowBecomesVisible_coldStart() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.notContains(testApp)
                 .then()
                 .isAppWindowInvisible(testApp, isOptional = true)
@@ -97,7 +97,7 @@
     }
 
     protected fun appWindowBecomesVisible_warmStart() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowInvisible(testApp)
                 .then()
                 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -115,7 +115,7 @@
     @Presubmit
     @Test
     open fun appWindowBecomesTopWindow() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowNotOnTop(testApp)
                 .then()
                 .isAppWindowOnTop(
@@ -131,6 +131,6 @@
     @Presubmit
     @Test
     open fun appWindowIsTopWindowAtEnd() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp) }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 03741c8..62d7cc0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -19,12 +19,12 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.annotation.FlickerServiceCompatible
-import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.setRotation
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import org.junit.FixMethodOrder
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -57,8 +57,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class OpenAppWarmTest(testSpec: FlickerTestParameter) :
-    OpenAppFromLauncherTransition(testSpec) {
+open class OpenAppWarmTest(flicker: FlickerTest) : OpenAppFromLauncherTransition(flicker) {
     /** Defines the transition used to run the test */
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -68,7 +67,7 @@
                 testApp.launchViaIntent(wmHelper)
                 tapl.goHome()
                 wmHelper.StateSyncBuilder().withHomeActivityVisible().waitForAndVerify()
-                this.setRotation(testSpec.startRotation)
+                this.setRotation(flicker.scenario.startRotation)
             }
             teardown { testApp.exit(wmHelper) }
             transitions { testApp.launchViaIntent(wmHelper) }
@@ -96,13 +95,13 @@
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.nonRotationTests] for configuring screen orientation and
+         * navigation modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
index e1fd5a7..b9594a1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OverrideTaskTransitionTest.kt
@@ -22,16 +22,16 @@
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
 import androidx.test.platform.app.InstrumentationRegistry
-import com.android.server.wm.flicker.FlickerBuilderProvider
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.R
-import com.android.server.wm.flicker.dsl.FlickerBuilder
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
+import com.android.server.wm.flicker.junit.FlickerBuilderProvider
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.WindowManagerConditionsFactory
@@ -55,7 +55,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class OverrideTaskTransitionTest(val testSpec: FlickerTestParameter) {
+class OverrideTaskTransitionTest(val flicker: FlickerTest) {
 
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     private val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
@@ -66,7 +66,7 @@
             setup {
                 device.wakeUpAndGoToHomeScreen()
                 RemoveAllTasksButHomeRule.removeAllTasksButHome()
-                setRotation(testSpec.startRotation)
+                setRotation(flicker.scenario.startRotation)
             }
             transitions {
                 instrumentation.context.startActivity(
@@ -87,24 +87,24 @@
     @Presubmit
     @Test
     fun testSimpleActivityIsShownDirectly() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             // Before the app launches, only the launcher is visible.
             isVisible(ComponentNameMatcher.LAUNCHER)
-                    .isInvisible(testApp)
-                    .then()
-                    // Animation starts, but the app may not be drawn yet which means the Splash
-                    // may be visible.
-                    .isInvisible(testApp, isOptional = true)
-                    .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
-                    .then()
-                    // App shows up with the custom animation starting at alpha=1.
-                    .isVisible(testApp)
-                    .then()
-                    // App custom animation continues to alpha=0 (invisible).
-                    .isInvisible(testApp)
-                    .then()
-                    // App custom animation ends with it being visible.
-                    .isVisible(testApp)
+                .isInvisible(testApp)
+                .then()
+                // Animation starts, but the app may not be drawn yet which means the Splash
+                // may be visible.
+                .isInvisible(testApp, isOptional = true)
+                .isVisible(ComponentNameMatcher.SPLASH_SCREEN, isOptional = true)
+                .then()
+                // App shows up with the custom animation starting at alpha=1.
+                .isVisible(testApp)
+                .then()
+                // App custom animation continues to alpha=0 (invisible).
+                .isInvisible(testApp)
+                .then()
+                // App custom animation ends with it being visible.
+                .isVisible(testApp)
         }
     }
 
@@ -123,8 +123,8 @@
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
index 08624ee..4e7ab7a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/TaskTransitionTest.kt
@@ -22,13 +22,13 @@
 import android.platform.test.annotations.Postsubmit
 import androidx.test.filters.RequiresDevice
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.NewTasksAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.SPLASH_SCREEN
 import com.android.server.wm.traces.common.ComponentNameMatcher.Companion.WALLPAPER_BBQ_WRAPPER
@@ -56,7 +56,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class TaskTransitionTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class TaskTransitionTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = NewTasksAppHelper(instrumentation)
     private val simpleApp = SimpleAppHelper(instrumentation)
     private val wallpaper by lazy {
@@ -81,7 +81,7 @@
     @FlakyTest(bugId = 253617416)
     @Test
     fun wallpaperWindowIsNeverVisible() {
-        testSpec.assertWm { this.isNonAppWindowInvisible(wallpaper) }
+        flicker.assertWm { this.isNonAppWindowInvisible(wallpaper) }
     }
 
     /**
@@ -91,7 +91,7 @@
     @FlakyTest(bugId = 253617416)
     @Test
     fun wallpaperLayerIsNeverVisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isInvisible(wallpaper)
             this.isInvisible(WALLPAPER_BBQ_WRAPPER)
         }
@@ -104,7 +104,7 @@
     @Postsubmit
     @Test
     fun launcherWindowIsNeverVisible() {
-        testSpec.assertWm { this.isAppWindowInvisible(ComponentNameMatcher.LAUNCHER) }
+        flicker.assertWm { this.isAppWindowInvisible(ComponentNameMatcher.LAUNCHER) }
     }
 
     /**
@@ -114,7 +114,7 @@
     @Postsubmit
     @Test
     fun launcherLayerIsNeverVisible() {
-        testSpec.assertLayers { this.isInvisible(ComponentNameMatcher.LAUNCHER) }
+        flicker.assertLayers { this.isInvisible(ComponentNameMatcher.LAUNCHER) }
     }
 
     /** Checks that a color background is visible while the task transition is occurring. */
@@ -122,9 +122,9 @@
     @Test
     fun colorLayerIsVisibleDuringTransition() {
         val bgColorLayer = ComponentNameMatcher("", "colorBackgroundLayer")
-        val displayBounds = WindowUtils.getDisplayBounds(testSpec.startRotation)
+        val displayBounds = WindowUtils.getDisplayBounds(flicker.scenario.startRotation)
 
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.invoke("LAUNCH_NEW_TASK_ACTIVITY coversExactly displayBounds") {
                     it.visibleRegion(testApp.componentMatcher).coversExactly(displayBounds)
                 }
@@ -157,7 +157,7 @@
     @Postsubmit
     @Test
     fun newTaskOpensOnTopAndThenCloses() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowOnTop(testApp.componentMatcher)
                 .then()
                 .isAppWindowOnTop(SPLASH_SCREEN, isOptional = true)
@@ -235,8 +235,8 @@
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
index bc1f0d1..b4a67ef 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -18,18 +18,17 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -54,7 +53,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsBackTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+open class QuickSwitchBetweenTwoAppsBackTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp1 = SimpleAppHelper(instrumentation)
     private val testApp2 = NonResizeableAppHelper(instrumentation)
 
@@ -66,7 +65,7 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
             tapl.setIgnoreTaskbarVisibility(true)
             testApp1.launchViaIntent(wmHelper)
             testApp2.launchViaIntent(wmHelper)
@@ -96,7 +95,7 @@
     @Presubmit
     @Test
     open fun startsWithApp2WindowsCoverFullScreen() {
-        testSpec.assertWmStart { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
+        flicker.assertWmStart { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -106,16 +105,14 @@
     @Presubmit
     @Test
     open fun startsWithApp2LayersCoverFullScreen() {
-        testSpec.assertLayersStart {
-            this.visibleRegion(testApp2).coversExactly(startDisplayBounds)
-        }
+        flicker.assertLayersStart { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
     }
 
     /** Checks that the transition starts with [testApp2] being the top window. */
     @Presubmit
     @Test
     open fun startsWithApp2WindowBeingOnTop() {
-        testSpec.assertWmStart { this.isAppWindowOnTop(testApp2) }
+        flicker.assertWmStart { this.isAppWindowOnTop(testApp2) }
     }
 
     /**
@@ -125,7 +122,7 @@
     @Presubmit
     @Test
     open fun endsWithApp1WindowsCoveringFullScreen() {
-        testSpec.assertWmEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) }
+        flicker.assertWmEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -135,7 +132,7 @@
     @Presubmit
     @Test
     fun endsWithApp1LayersCoveringFullScreen() {
-        testSpec.assertLayersEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) }
+        flicker.assertLayersEnd { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -145,7 +142,7 @@
     @Presubmit
     @Test
     open fun endsWithApp1BeingOnTop() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp1) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp1) }
     }
 
     /**
@@ -155,7 +152,7 @@
     @Presubmit
     @Test
     open fun app1WindowBecomesAndStaysVisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowInvisible(testApp1)
                 .then()
                 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -171,7 +168,7 @@
     @Presubmit
     @Test
     open fun app1LayerBecomesAndStaysVisible() {
-        testSpec.assertLayers { this.isInvisible(testApp1).then().isVisible(testApp1) }
+        flicker.assertLayers { this.isInvisible(testApp1).then().isVisible(testApp1) }
     }
 
     /**
@@ -181,9 +178,7 @@
     @Presubmit
     @Test
     open fun app2WindowBecomesAndStaysInvisible() {
-        testSpec.assertWm {
-            this.isAppWindowVisible(testApp2).then().isAppWindowInvisible(testApp2)
-        }
+        flicker.assertWm { this.isAppWindowVisible(testApp2).then().isAppWindowInvisible(testApp2) }
     }
 
     /**
@@ -193,7 +188,7 @@
     @Presubmit
     @Test
     open fun app2LayerBecomesAndStaysInvisible() {
-        testSpec.assertLayers { this.isVisible(testApp2).then().isInvisible(testApp2) }
+        flicker.assertLayers { this.isVisible(testApp2).then().isInvisible(testApp2) }
     }
 
     /**
@@ -204,7 +199,7 @@
     @Presubmit
     @Test
     open fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowVisible(testApp2)
                 .then()
                 // TODO: Do we actually want to test this? Seems too implementation specific...
@@ -224,7 +219,7 @@
     @Presubmit
     @Test
     open fun app1LayerIsVisibleOnceApp2LayerIsInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(testApp2)
                 .then()
                 .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
@@ -240,13 +235,10 @@
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
-                    supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
index f988bb2..ec4e35c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest_ShellTransit.kt
@@ -19,9 +19,9 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Assume
@@ -49,8 +49,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(testSpec: FlickerTestParameter) :
-    QuickSwitchBetweenTwoAppsBackTest(testSpec) {
+open class QuickSwitchBetweenTwoAppsBackTest_ShellTransit(flicker: FlickerTest) :
+    QuickSwitchBetweenTwoAppsBackTest(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
@@ -62,21 +62,20 @@
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /**
-     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at
-     * the start and end of the WM trace
+     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
+     * start and end of the WM trace
      */
     @Presubmit
     @Test
     fun navBarWindowIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsVisibleAtStartAndEnd()
     }
 
     /** {@inheritDoc} */
     @FlakyTest(bugId = 250520840)
     @Test
-    override fun startsWithApp2LayersCoverFullScreen() =
-        super.startsWithApp2LayersCoverFullScreen()
+    override fun startsWithApp2LayersCoverFullScreen() = super.startsWithApp2LayersCoverFullScreen()
 
     @FlakyTest(bugId = 246284708)
     @Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
index 7e4504b..593481c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest.kt
@@ -18,18 +18,17 @@
 
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.Before
 import org.junit.FixMethodOrder
@@ -55,8 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsForwardTest(testSpec: FlickerTestParameter) :
-    BaseTest(testSpec) {
+open class QuickSwitchBetweenTwoAppsForwardTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp1 = SimpleAppHelper(instrumentation)
     private val testApp2 = NonResizeableAppHelper(instrumentation)
 
@@ -68,7 +66,7 @@
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
         setup {
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
 
             testApp1.launchViaIntent(wmHelper)
             testApp2.launchViaIntent(wmHelper)
@@ -105,7 +103,7 @@
     @Presubmit
     @Test
     open fun startsWithApp1WindowsCoverFullScreen() {
-        testSpec.assertWmStart {
+        flicker.assertWmStart {
             this.visibleRegion(testApp1.or(ComponentNameMatcher.LETTERBOX))
                 .coversExactly(startDisplayBounds)
         }
@@ -118,16 +116,14 @@
     @Presubmit
     @Test
     open fun startsWithApp1LayersCoverFullScreen() {
-        testSpec.assertLayersStart {
-            this.visibleRegion(testApp1).coversExactly(startDisplayBounds)
-        }
+        flicker.assertLayersStart { this.visibleRegion(testApp1).coversExactly(startDisplayBounds) }
     }
 
     /** Checks that the transition starts with [testApp1] being the top window. */
     @Presubmit
     @Test
     open fun startsWithApp1WindowBeingOnTop() {
-        testSpec.assertWmStart { this.isAppWindowOnTop(testApp1) }
+        flicker.assertWmStart { this.isAppWindowOnTop(testApp1) }
     }
 
     /**
@@ -137,7 +133,7 @@
     @Presubmit
     @Test
     open fun endsWithApp2WindowsCoveringFullScreen() {
-        testSpec.assertWmEnd { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
+        flicker.assertWmEnd { this.visibleRegion(testApp2).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -147,7 +143,7 @@
     @Presubmit
     @Test
     open fun endsWithApp2LayersCoveringFullScreen() {
-        testSpec.assertLayersEnd {
+        flicker.assertLayersEnd {
             this.visibleRegion(testApp2.or(ComponentNameMatcher.LETTERBOX))
                 .coversExactly(startDisplayBounds)
         }
@@ -160,7 +156,7 @@
     @Presubmit
     @Test
     open fun endsWithApp2BeingOnTop() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp2) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp2) }
     }
 
     /**
@@ -170,7 +166,7 @@
     @Presubmit
     @Test
     open fun app2WindowBecomesAndStaysVisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowInvisible(testApp2)
                 .then()
                 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -186,7 +182,7 @@
     @Presubmit
     @Test
     open fun app2LayerBecomesAndStaysVisible() {
-        testSpec.assertLayers { this.isInvisible(testApp2).then().isVisible(testApp2) }
+        flicker.assertLayers { this.isInvisible(testApp2).then().isVisible(testApp2) }
     }
 
     /**
@@ -196,9 +192,7 @@
     @Presubmit
     @Test
     open fun app1WindowBecomesAndStaysInvisible() {
-        testSpec.assertWm {
-            this.isAppWindowVisible(testApp1).then().isAppWindowInvisible(testApp1)
-        }
+        flicker.assertWm { this.isAppWindowVisible(testApp1).then().isAppWindowInvisible(testApp1) }
     }
 
     /**
@@ -208,7 +202,7 @@
     @Presubmit
     @Test
     open fun app1LayerBecomesAndStaysInvisible() {
-        testSpec.assertLayers { this.isVisible(testApp1).then().isInvisible(testApp1) }
+        flicker.assertLayers { this.isVisible(testApp1).then().isInvisible(testApp1) }
     }
 
     /**
@@ -219,7 +213,7 @@
     @Presubmit
     @Test
     open fun app2WindowIsVisibleOnceApp1WindowIsInvisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowVisible(testApp1)
                 .then()
                 .isAppWindowVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
@@ -238,7 +232,7 @@
     @Presubmit
     @Test
     open fun app2LayerIsVisibleOnceApp1LayerIsInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(testApp1)
                 .then()
                 .isVisible(ComponentNameMatcher.LAUNCHER, isOptional = true)
@@ -259,13 +253,10 @@
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
-                    supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
index cc954ab..477b419 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsForwardTest_ShellTransit.kt
@@ -19,9 +19,9 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Assume
@@ -50,8 +50,8 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class QuickSwitchBetweenTwoAppsForwardTest_ShellTransit(testSpec: FlickerTestParameter) :
-    QuickSwitchBetweenTwoAppsForwardTest(testSpec) {
+open class QuickSwitchBetweenTwoAppsForwardTest_ShellTransit(flicker: FlickerTest) :
+    QuickSwitchBetweenTwoAppsForwardTest(flicker) {
     @Before
     override fun before() {
         Assume.assumeTrue(isShellTransitionsEnabled)
@@ -63,14 +63,14 @@
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /**
-     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at
-     * the start and end of the WM trace
+     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
+     * start and end of the WM trace
      */
     @Presubmit
     @Test
     fun navBarWindowIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsVisibleAtStartAndEnd()
     }
 
     @FlakyTest(bugId = 246284708)
@@ -84,6 +84,5 @@
 
     @FlakyTest(bugId = 250522691)
     @Test
-    override fun startsWithApp1LayersCoverFullScreen() =
-        super.startsWithApp1LayersCoverFullScreen()
+    override fun startsWithApp1LayersCoverFullScreen() = super.startsWithApp1LayersCoverFullScreen()
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
index 3cb985a..8c8220f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -19,18 +19,17 @@
 import android.platform.test.annotations.FlakyTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
-import android.view.Surface
-import android.view.WindowManagerPolicyConstants
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.navBarWindowIsVisibleAtStartAndEnd
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import com.android.server.wm.traces.common.Rect
+import com.android.server.wm.traces.common.service.PlatformConsts
 import org.junit.Assume
 import org.junit.FixMethodOrder
 import org.junit.Ignore
@@ -55,7 +54,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class QuickSwitchFromLauncherTest(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+class QuickSwitchFromLauncherTest(flicker: FlickerTest) : BaseTest(flicker) {
     private val testApp = SimpleAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -63,7 +62,7 @@
         setup {
             tapl.setExpectedRotationCheckEnabled(false)
 
-            tapl.setExpectedRotation(testSpec.startRotation)
+            tapl.setExpectedRotation(flicker.scenario.startRotation.value)
 
             testApp.launchViaIntent(wmHelper)
             tapl.goHome()
@@ -95,7 +94,7 @@
     @Presubmit
     @Test
     fun endsWithAppWindowsCoveringFullScreen() {
-        testSpec.assertWmEnd { this.visibleRegion(testApp).coversExactly(startDisplayBounds) }
+        flicker.assertWmEnd { this.visibleRegion(testApp).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -105,7 +104,7 @@
     @Presubmit
     @Test
     fun endsWithAppLayersCoveringFullScreen() {
-        testSpec.assertLayersEnd { this.visibleRegion(testApp).coversExactly(startDisplayBounds) }
+        flicker.assertLayersEnd { this.visibleRegion(testApp).coversExactly(startDisplayBounds) }
     }
 
     /**
@@ -115,47 +114,48 @@
     @Presubmit
     @Test
     fun endsWithAppBeingOnTop() {
-        testSpec.assertWmEnd { this.isAppWindowOnTop(testApp) }
+        flicker.assertWmEnd { this.isAppWindowOnTop(testApp) }
     }
 
     /** Checks that the transition starts with the home activity being tagged as visible. */
     @Presubmit
     @Test
     fun startsWithHomeActivityFlaggedVisible() {
-        testSpec.assertWmStart { this.isHomeActivityVisible() }
+        flicker.assertWmStart { this.isHomeActivityVisible() }
     }
 
     /**
-     * Checks that the transition starts with the [ComponentMatcher.LAUNCHER] windows
+     * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] windows
      * filling/covering exactly display size
      */
     @Presubmit
     @Test
     fun startsWithLauncherWindowsCoverFullScreen() {
-        testSpec.assertWmStart {
+        flicker.assertWmStart {
             this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds)
         }
     }
 
     /**
-     * Checks that the transition starts with the [ComponentMatcher.LAUNCHER] layers
+     * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] layers
      * filling/covering exactly the display size.
      */
     @Presubmit
     @Test
     fun startsWithLauncherLayersCoverFullScreen() {
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             this.visibleRegion(ComponentNameMatcher.LAUNCHER).coversExactly(startDisplayBounds)
         }
     }
 
     /**
-     * Checks that the transition starts with the [ComponentMatcher.LAUNCHER] being the top window.
+     * Checks that the transition starts with the [ComponentNameMatcher.LAUNCHER] being the top
+     * window.
      */
     @Presubmit
     @Test
     fun startsWithLauncherBeingOnTop() {
-        testSpec.assertWmStart { this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) }
+        flicker.assertWmStart { this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER) }
     }
 
     /**
@@ -165,7 +165,7 @@
     @Presubmit
     @Test
     fun endsWithHomeActivityFlaggedInvisible() {
-        testSpec.assertWmEnd { this.isHomeActivityInvisible() }
+        flicker.assertWmEnd { this.isHomeActivityInvisible() }
     }
 
     /**
@@ -175,7 +175,7 @@
     @Presubmit
     @Test
     fun appWindowBecomesAndStaysVisible() {
-        testSpec.assertWm { this.isAppWindowInvisible(testApp).then().isAppWindowVisible(testApp) }
+        flicker.assertWm { this.isAppWindowInvisible(testApp).then().isAppWindowVisible(testApp) }
     }
 
     /**
@@ -185,18 +185,18 @@
     @Presubmit
     @Test
     fun appLayerBecomesAndStaysVisible() {
-        testSpec.assertLayers { this.isInvisible(testApp).then().isVisible(testApp) }
+        flicker.assertLayers { this.isInvisible(testApp).then().isVisible(testApp) }
     }
 
     /**
-     * Checks that the [ComponentMatcher.LAUNCHER] window starts off visible and becomes invisible
-     * at some point before the end of the transition and then stays invisible until the end of the
-     * transition.
+     * Checks that the [ComponentNameMatcher.LAUNCHER] window starts off visible and becomes
+     * invisible at some point before the end of the transition and then stays invisible until the
+     * end of the transition.
      */
     @Presubmit
     @Test
     fun launcherWindowBecomesAndStaysInvisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isAppWindowNotOnTop(ComponentNameMatcher.LAUNCHER)
@@ -204,14 +204,14 @@
     }
 
     /**
-     * Checks that the [ComponentMatcher.LAUNCHER] layer starts off visible and becomes invisible at
-     * some point before the end of the transition and then stays invisible until the end of the
-     * transition.
+     * Checks that the [ComponentNameMatcher.LAUNCHER] layer starts off visible and becomes
+     * invisible at some point before the end of the transition and then stays invisible until the
+     * end of the transition.
      */
     @Presubmit
     @Test
     fun launcherLayerBecomesAndStaysInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isInvisible(ComponentNameMatcher.LAUNCHER)
@@ -219,14 +219,14 @@
     }
 
     /**
-     * Checks that the [ComponentMatcher.LAUNCHER] window is visible at least until the app window
-     * is visible. Ensures that at any point, either the launcher or [testApp] windows are at least
-     * partially visible.
+     * Checks that the [ComponentNameMatcher.LAUNCHER] window is visible at least until the app
+     * window is visible. Ensures that at any point, either the launcher or [testApp] windows are at
+     * least partially visible.
      */
     @Presubmit
     @Test
     fun appWindowIsVisibleOnceLauncherWindowIsInvisible() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.isAppWindowOnTop(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isAppWindowVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -236,14 +236,14 @@
     }
 
     /**
-     * Checks that the [ComponentMatcher.LAUNCHER] layer is visible at least until the app layer is
-     * visible. Ensures that at any point, either the launcher or [testApp] layers are at least
+     * Checks that the [ComponentNameMatcher.LAUNCHER] layer is visible at least until the app layer
+     * is visible. Ensures that at any point, either the launcher or [testApp] layers are at least
      * partially visible.
      */
     @Presubmit
     @Test
     fun appLayerIsVisibleOnceLauncherLayerIsInvisible() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(ComponentNameMatcher.LAUNCHER)
                 .then()
                 .isVisible(ComponentNameMatcher.SNAPSHOT, isOptional = true)
@@ -263,14 +263,14 @@
     override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
 
     /**
-     * Checks that [ComponentMatcher.NAV_BAR] window is visible and above the app windows at the
+     * Checks that [ComponentNameMatcher.NAV_BAR] window is visible and above the app windows at the
      * start and end of the WM trace
      */
     @Presubmit
     @Test
     fun navBarWindowIsVisibleAtStartAndEnd() {
-        Assume.assumeFalse(testSpec.isTablet)
-        testSpec.navBarWindowIsVisibleAtStartAndEnd()
+        Assume.assumeFalse(flicker.scenario.isTablet)
+        flicker.navBarWindowIsVisibleAtStartAndEnd()
     }
 
     @Presubmit
@@ -293,14 +293,12 @@
 
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance()
-                .getConfigNonRotationTests(
-                    supportedNavigationModes =
-                        listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
-                    // TODO: Test with 90 rotation
-                    supportedRotations = listOf(Surface.ROTATION_0)
-                )
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.nonRotationTests(
+                supportedNavigationModes = listOf(PlatformConsts.NavBar.MODE_GESTURAL),
+                // TODO: Test with 90 rotation
+                supportedRotations = listOf(PlatformConsts.Rotation.ROTATION_0)
+            )
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 1973ec0..5b52c75 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -17,13 +17,14 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
 import org.junit.Test
@@ -77,7 +78,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-class ChangeAppRotationTest(testSpec: FlickerTestParameter) : RotationTransition(testSpec) {
+class ChangeAppRotationTest(flicker: FlickerTest) : RotationTransition(flicker) {
     override val testApp = SimpleAppHelper(instrumentation)
     override val transition: FlickerBuilder.() -> Unit
         get() = {
@@ -92,15 +93,15 @@
     @Presubmit
     @Test
     fun focusChanges() {
-        testSpec.assertEventLog { this.focusChanges(testApp.`package`) }
+        flicker.assertEventLog { this.focusChanges(testApp.`package`) }
     }
 
     /**
-     * Checks that the [ComponentMatcher.ROTATION] layer appears during the transition, doesn't
+     * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
      * flicker, and disappears before the transition is complete
      */
     fun rotationLayerAppearsAndVanishesAssertion() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.isVisible(testApp)
                 .then()
                 .isVisible(ComponentNameMatcher.ROTATION)
@@ -111,7 +112,7 @@
     }
 
     /**
-     * Checks that the [ComponentMatcher.ROTATION] layer appears during the transition, doesn't
+     * Checks that the [ComponentNameMatcher.ROTATION] layer appears during the transition, doesn't
      * flicker, and disappears before the transition is complete
      */
     @Presubmit
@@ -125,17 +126,25 @@
     @Test
     override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        super.cujCompleted()
+        focusChanges()
+        rotationLayerAppearsAndVanishes()
+    }
+
     companion object {
         /**
          * Creates the test configurations.
          *
-         * See [FlickerTestParameterFactory.getConfigRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
+         * See [FlickerTestFactory.rotationTests] for configuring screen orientation and navigation
+         * modes.
          */
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigRotationTests()
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.rotationTests()
         }
     }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 4faeb24..4ef9eaf 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -18,29 +18,29 @@
 
 import android.platform.test.annotations.Presubmit
 import com.android.server.wm.flicker.BaseTest
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
 import com.android.server.wm.flicker.helpers.StandardAppHelper
 import com.android.server.wm.flicker.helpers.setRotation
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.Test
 
 /** Base class for app rotation tests */
-abstract class RotationTransition(testSpec: FlickerTestParameter) : BaseTest(testSpec) {
+abstract class RotationTransition(flicker: FlickerTest) : BaseTest(flicker) {
     protected abstract val testApp: StandardAppHelper
 
     /** {@inheritDoc} */
     override val transition: FlickerBuilder.() -> Unit = {
-        setup { this.setRotation(testSpec.startRotation) }
+        setup { this.setRotation(flicker.scenario.startRotation) }
         teardown { testApp.exit(wmHelper) }
-        transitions { this.setRotation(testSpec.endRotation) }
+        transitions { this.setRotation(flicker.scenario.endRotation) }
     }
 
     /** {@inheritDoc} */
     @Presubmit
     @Test
     override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.visibleLayersShownMoreThanOneConsecutiveEntry(
                 ignoreLayers =
                     listOf(
@@ -56,7 +56,7 @@
     @Presubmit
     @Test
     open fun appLayerRotates_StartingPos() {
-        testSpec.assertLayersStart {
+        flicker.assertLayersStart {
             this.entry.displays.map { display ->
                 this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
             }
@@ -67,10 +67,16 @@
     @Presubmit
     @Test
     open fun appLayerRotates_EndingPos() {
-        testSpec.assertLayersEnd {
+        flicker.assertLayersEnd {
             this.entry.displays.map { display ->
                 this.visibleRegion(testApp).coversExactly(display.layerStackSpace)
             }
         }
     }
+
+    override fun cujCompleted() {
+        super.cujCompleted()
+        appLayerRotates_StartingPos()
+        appLayerRotates_EndingPos()
+    }
 }
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index a08db29..54f38c3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -17,14 +17,16 @@
 package com.android.server.wm.flicker.rotation
 
 import android.platform.test.annotations.FlakyTest
+import android.platform.test.annotations.IwTest
 import android.platform.test.annotations.Presubmit
 import android.platform.test.annotations.RequiresDevice
 import android.view.WindowManager
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.FlickerTestParameterFactory
-import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.FlickerBuilder
+import com.android.server.wm.flicker.FlickerTest
+import com.android.server.wm.flicker.FlickerTestFactory
+import com.android.server.wm.flicker.ScenarioBuilder
 import com.android.server.wm.flicker.helpers.SeamlessRotationAppHelper
+import com.android.server.wm.flicker.junit.FlickerParametersRunnerFactory
 import com.android.server.wm.flicker.testapp.ActivityOptions
 import com.android.server.wm.traces.common.ComponentNameMatcher
 import org.junit.FixMethodOrder
@@ -37,7 +39,7 @@
 /**
  * Test opening an app and cycling through app rotations using seamless rotations
  *
- * Currently runs:
+ * Currently, runs:
  * ```
  *      0 -> 90 degrees
  *      0 -> 90 degrees (with starved UI thread)
@@ -82,7 +84,7 @@
 @RunWith(Parameterized::class)
 @Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
-open class SeamlessAppRotationTest(testSpec: FlickerTestParameter) : RotationTransition(testSpec) {
+open class SeamlessAppRotationTest(flicker: FlickerTest) : RotationTransition(flicker) {
     override val testApp = SeamlessRotationAppHelper(instrumentation)
 
     /** {@inheritDoc} */
@@ -95,7 +97,7 @@
                     stringExtras =
                         mapOf(
                             ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD to
-                                testSpec.starveUiThread.toString()
+                                flicker.starveUiThread.toString()
                         )
                 )
             }
@@ -105,7 +107,7 @@
     @Presubmit
     @Test
     fun appWindowFullScreen() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.invoke("isFullScreen") {
                 val appWindow = it.windowState(testApp.`package`)
                 val flags = appWindow.windowState?.attributes?.flags ?: 0
@@ -121,7 +123,7 @@
     @Presubmit
     @Test
     fun appWindowSeamlessRotation() {
-        testSpec.assertWm {
+        flicker.assertWm {
             this.invoke("isRotationSeamless") {
                 val appWindow = it.windowState(testApp.`package`)
                 val rotationAnimation = appWindow.windowState?.attributes?.rotationAnimation ?: 0
@@ -141,14 +143,14 @@
     @Presubmit
     @Test
     fun appLayerAlwaysVisible() {
-        testSpec.assertLayers { isVisible(testApp) }
+        flicker.assertLayers { isVisible(testApp) }
     }
 
     /** Checks that [testApp] layer covers the entire screen during the whole transition */
     @Presubmit
     @Test
     fun appLayerRotates() {
-        testSpec.assertLayers {
+        flicker.assertLayers {
             this.invoke("entireScreenCovered") { entry ->
                 entry.entry.displays.map { display ->
                     entry.visibleRegion(testApp).coversExactly(display.layerStackSpace)
@@ -179,7 +181,7 @@
     @Presubmit
     @Test
     fun statusBarWindowIsAlwaysInvisible() {
-        testSpec.assertWm { this.isAboveAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertWm { this.isAboveAppWindowInvisible(ComponentNameMatcher.STATUS_BAR) }
     }
 
     /**
@@ -189,14 +191,14 @@
     @Presubmit
     @Test
     fun statusBarLayerIsAlwaysInvisible() {
-        testSpec.assertLayers { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
+        flicker.assertLayers { this.isInvisible(ComponentNameMatcher.STATUS_BAR) }
     }
 
     /** Checks that the focus doesn't change during animation */
     @Presubmit
     @Test
     fun focusDoesNotChange() {
-        testSpec.assertEventLog { this.focusDoesNotChange() }
+        flicker.assertEventLog { this.focusDoesNotChange() }
     }
 
     /** {@inheritDoc} */
@@ -204,50 +206,65 @@
     @Test
     override fun navBarLayerPositionAtStartAndEnd() = super.navBarLayerPositionAtStartAndEnd()
 
-    companion object {
-        private val FlickerTestParameter.starveUiThread
-            get() =
-                config.getOrDefault(ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD, false)
-                    as Boolean
+    @Test
+    @IwTest(focusArea = "ime")
+    override fun cujCompleted() {
+        if (!flicker.scenario.isTablet) {
+            // not yet tablet compatible
+            appLayerRotates()
+            appLayerAlwaysVisible()
+        }
 
-        private fun createConfig(
-            sourceConfig: FlickerTestParameter,
-            starveUiThread: Boolean
-        ): FlickerTestParameter {
-            val newConfig =
-                sourceConfig.config.toMutableMap().also {
-                    it[ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD] = starveUiThread
-                }
+        appWindowFullScreen()
+        appWindowSeamlessRotation()
+        focusDoesNotChange()
+        statusBarLayerIsAlwaysInvisible()
+        statusBarWindowIsAlwaysInvisible()
+        appLayerRotates_StartingPos()
+        appLayerRotates_EndingPos()
+        entireScreenCovered()
+        navBarLayerIsVisibleAtStartAndEnd()
+        navBarWindowIsAlwaysVisible()
+        taskBarLayerIsVisibleAtStartAndEnd()
+        taskBarWindowIsAlwaysVisible()
+        visibleLayersShownMoreThanOneConsecutiveEntry()
+        visibleWindowsShownMoreThanOneConsecutiveEntry()
+    }
+
+    companion object {
+        private val FlickerTest.starveUiThread
+            get() =
+                getConfigValue<Boolean>(ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD)
+                    ?: false
+
+        private fun createConfig(sourceConfig: FlickerTest, starveUiThread: Boolean): FlickerTest {
+            val originalScenario = sourceConfig.initialize("createConfig")
             val nameExt = if (starveUiThread) "_BUSY_UI_THREAD" else ""
-            return FlickerTestParameter(newConfig, nameOverride = "$sourceConfig$nameExt")
+            val newConfig =
+                ScenarioBuilder()
+                    .fromScenario(originalScenario)
+                    .withExtraConfig(
+                        ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD,
+                        starveUiThread
+                    )
+                    .withDescriptionOverride("${originalScenario.description}$nameExt")
+            return FlickerTest(newConfig)
         }
 
         /**
          * Creates the test configurations for seamless rotation based on the default rotation tests
-         * from [FlickerTestParameterFactory.getConfigRotationTests], but adding an additional flag
-         * ([ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD]) to indicate if the app should
+         * from [FlickerTestFactory.rotationTests], but adding a flag (
+         * [ActivityOptions.SeamlessRotation.EXTRA_STARVE_UI_THREAD]) to indicate if the app should
          * starve the UI thread of not
-         */
+        */
+        @Parameterized.Parameters(name = "{0}")
         @JvmStatic
-        private fun getConfigurations(): List<FlickerTestParameter> {
-            return FlickerTestParameterFactory.getInstance().getConfigRotationTests().flatMap {
-                sourceConfig ->
+        fun getParams(): Collection<FlickerTest> {
+            return FlickerTestFactory.rotationTests().flatMap { sourceConfig ->
                 val defaultRun = createConfig(sourceConfig, starveUiThread = false)
                 val busyUiRun = createConfig(sourceConfig, starveUiThread = true)
                 listOf(defaultRun, busyUiRun)
             }
         }
-
-        /**
-         * Creates the test configurations.
-         *
-         * See [FlickerTestParameterFactory.getConfigRotationTests] for configuring repetitions,
-         * screen orientation and navigation modes.
-         */
-        @Parameterized.Parameters(name = "{0}")
-        @JvmStatic
-        fun getParams(): Collection<FlickerTestParameter> {
-            return getConfigurations()
-        }
     }
 }
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 939c7de..7383d6a 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -1146,5 +1146,13 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="MeshActivity"
+                  android:label="Mesh/SimpleMesh"
+                  android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="com.android.test.hwui.TEST"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java
new file mode 100644
index 0000000..efe242c
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MeshActivity.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.BlendMode;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Mesh;
+import android.graphics.MeshSpecification;
+import android.graphics.MeshSpecification.Attribute;
+import android.graphics.MeshSpecification.Varying;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+
+public class MeshActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(new MeshView(this));
+    }
+
+    static class MeshView extends View {
+        MeshView(Context c) {
+            super(c);
+            this.setOnTouchListener((v, event) -> {
+                invalidate();
+                return true;
+            });
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            MeshSpecification meshSpec = createMeshSpecification();
+            FloatBuffer vertexBuffer = FloatBuffer.allocate(6);
+            vertexBuffer.put(0, 100.0f);
+            vertexBuffer.put(1, 100.0f);
+            vertexBuffer.put(2, 400.0f);
+            vertexBuffer.put(3, 0.0f);
+            vertexBuffer.put(4, 0.0f);
+            vertexBuffer.put(5, 400.0f);
+            vertexBuffer.rewind();
+            Mesh mesh = Mesh.make(
+                    meshSpec, Mesh.Mode.Triangles, vertexBuffer, 3, new Rect(0, 0, 1000, 1000));
+
+            int numTriangles = 100;
+            // number of triangles plus first 2 vertices
+            FloatBuffer iVertexBuffer = FloatBuffer.allocate(numTriangles * 2 + 4);
+            ShortBuffer indexBuffer = ShortBuffer.allocate(300);
+
+            int radius = 200;
+            // origin
+            iVertexBuffer.put(0, 500.0f);
+            iVertexBuffer.put(1, 500.0f);
+
+            // first point
+            iVertexBuffer.put(2, 500.0f + radius);
+            iVertexBuffer.put(3, 500.0f);
+            int nVert = 2;
+            int nInd = 0;
+            for (int i = 1; i <= numTriangles; i++) {
+                double angle = (Math.PI * i) / numTriangles;
+                double x = radius * Math.cos(angle);
+                double y = radius * Math.sin(angle);
+                iVertexBuffer.put((i + 1) * 2, 500 + (float) x);
+                iVertexBuffer.put((i + 1) * 2 + 1, 500 + (float) y);
+
+                indexBuffer.put(nInd++, (short) 0);
+                indexBuffer.put(nInd++, (short) (nVert - 1));
+                indexBuffer.put(nInd++, (short) nVert);
+                nVert++;
+            }
+            iVertexBuffer.rewind();
+            indexBuffer.rewind();
+            Mesh mesh2 = Mesh.makeIndexed(meshSpec, Mesh.Mode.Triangles, iVertexBuffer, 102,
+                    indexBuffer, new Rect(0, 0, 1000, 1000));
+
+            Paint paint = new Paint();
+            paint.setColor(Color.RED);
+            canvas.drawMesh(mesh, BlendMode.COLOR, new Paint());
+            canvas.drawMesh(mesh2, BlendMode.COLOR, paint);
+        }
+
+        private MeshSpecification createMeshSpecification() {
+            String vs = "Varyings main(const Attributes attributes) { "
+                    + "     Varyings varyings;"
+                    + "     varyings.position = attributes.position;"
+                    + "     return varyings;"
+                    + "}";
+            String fs = "float2 main(const Varyings varyings, out float4 color) {\n"
+                    + "      color = vec4(1.0, 0.0, 0.0, 1.0);"
+                    + "      return varyings.position;\n"
+                    + "}";
+            Attribute[] attList =
+                    new Attribute[] {new Attribute(MeshSpecification.FLOAT2, 0, "position")};
+            Varying[] varyList =
+                    new MeshSpecification.Varying[] {};
+            return MeshSpecification.make(attList, 8, varyList, vs, fs);
+        }
+    }
+}
diff --git a/tests/TelephonyCommonTests/Android.bp b/tests/TelephonyCommonTests/Android.bp
index a9fbfd9..81ec265 100644
--- a/tests/TelephonyCommonTests/Android.bp
+++ b/tests/TelephonyCommonTests/Android.bp
@@ -47,7 +47,7 @@
 
     // Uncomment this and comment out the jarjar rule if you want to attach a debugger and step
     // through the renamed classes.
-    // platform_apis: true,
+    platform_apis: true,
 
     libs: [
         "android.test.runner",
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
index 7a2af72..adefac6 100644
--- a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/SmsApplicationTest.java
@@ -44,6 +44,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
@@ -75,9 +76,12 @@
 public class SmsApplicationTest {
     private static final ComponentName TEST_COMPONENT_NAME =
             ComponentName.unflattenFromString("com.android.test/.TestSmsApp");
+    public static final String BLUETOOTH_PACKAGE_NAME = "com.android.bluetooth.services";
     private static final String MMS_RECEIVER_NAME = "TestMmsReceiver";
     private static final String RESPOND_VIA_SMS_NAME = "TestRespondViaSmsHandler";
     private static final String SEND_TO_NAME = "TestSendTo";
+    private static final String EXTERNAL_PROVIDER_CHANGE_NAME = "TestExternalProviderChangeHandler";
+    private static final String SIM_FULL_NAME = "TestSimFullHandler";
     private static final int SMS_APP_UID = 10001;
 
     private static final int FAKE_PHONE_UID = 10002;
@@ -102,6 +106,7 @@
     }).collect(Collectors.toSet());
 
     @Mock private Context mContext;
+    @Mock private Resources mResources;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private RoleManager mRoleManager;
     @Mock private PackageManager mPackageManager;
@@ -118,6 +123,9 @@
         when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
         when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOpsManager);
         when(mContext.createContextAsUser(isNotNull(), anyInt())).thenReturn(mContext);
+        when(mContext.getResources()).thenReturn(mResources);
+        when(mResources.getString(eq(com.android.internal.R.string.config_systemBluetoothStack)))
+                .thenReturn(BLUETOOTH_PACKAGE_NAME);
 
         doAnswer(invocation -> getResolveInfosForIntent(invocation.getArgument(0)))
                 .when(mPackageManager)
@@ -146,24 +154,46 @@
         }
     }
 
+
     @Test
-    public void testGetDefaultSmsApplication() {
+    public void testGetDefaultSmsApplicationAsUser() {
         assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultSmsApplicationAsUser(mContext, false, 0));
+                SmsApplication.getDefaultSmsApplicationAsUser(mContext, false,
+                        UserHandle.SYSTEM));
+    }
+
+
+    @Test
+    public void testGetDefaultMmsApplicationAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultMmsApplicationAsUser(mContext,
+                        false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(MMS_RECEIVER_NAME, componentName.getClassName());
     }
 
     @Test
-    public void testGetDefaultMmsApplication() {
-        assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultMmsApplicationAsUser(mContext, false,
-                        UserHandle.USER_SYSTEM));
+    public void testGetDefaultExternalTelephonyProviderChangedApplicationAsUser() {
+        ComponentName componentName = SmsApplication
+                .getDefaultExternalTelephonyProviderChangedApplicationAsUser(mContext,
+                        false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(EXTERNAL_PROVIDER_CHANGE_NAME, componentName.getClassName());
     }
 
     @Test
-    public void testGetDefaultExternalTelephonyProviderChangedApplication() {
-        assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultExternalTelephonyProviderChangedApplicationAsUser(mContext,
-                        false, UserHandle.USER_SYSTEM));
+    public void testGetDefaultRespondViaMessageApplicationAsUserAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultRespondViaMessageApplicationAsUser(
+                mContext, false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(RESPOND_VIA_SMS_NAME, componentName.getClassName());
+    }
+
+    @Test
+    public void testGetDefaultSimFullApplicationAsUser() {
+        ComponentName componentName = SmsApplication.getDefaultSimFullApplicationAsUser(mContext,
+                false, UserHandle.SYSTEM);
+        assertEquals(TEST_COMPONENT_NAME.getPackageName(), componentName.getPackageName());
+        assertEquals(SIM_FULL_NAME, componentName.getClassName());
     }
 
     @Test
@@ -174,7 +204,8 @@
         setupPackageInfosForCoreApps();
 
         assertEquals(TEST_COMPONENT_NAME,
-                SmsApplication.getDefaultSmsApplicationAsUser(mContext, true, 0));
+                SmsApplication.getDefaultSmsApplicationAsUser(mContext, true,
+                        UserHandle.SYSTEM));
         verify(mAppOpsManager, atLeastOnce()).setUidMode(AppOpsManager.OPSTR_READ_SMS, SMS_APP_UID,
                 AppOpsManager.MODE_ALLOWED);
     }
@@ -251,6 +282,10 @@
                 return Collections.singletonList(makeRespondViaMessageResolveInfo());
             case Intent.ACTION_SENDTO:
                 return Collections.singletonList(makeSendToResolveInfo());
+            case Telephony.Sms.Intents.ACTION_EXTERNAL_PROVIDER_CHANGE:
+                return Collections.singletonList(makeExternalProviderChangeResolveInfo());
+            case Telephony.Sms.Intents.SIM_FULL_ACTION:
+                return Collections.singletonList(makeSimFullResolveInfo());
         }
         return Collections.emptyList();
     }
@@ -308,4 +343,26 @@
         info.activityInfo = activityInfo;
         return info;
     }
+
+    private ResolveInfo makeExternalProviderChangeResolveInfo() {
+        ResolveInfo info = new ResolveInfo();
+        ActivityInfo activityInfo = new ActivityInfo();
+
+        activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+        activityInfo.name = EXTERNAL_PROVIDER_CHANGE_NAME;
+
+        info.activityInfo = activityInfo;
+        return info;
+    }
+
+    private ResolveInfo makeSimFullResolveInfo() {
+        ResolveInfo info = new ResolveInfo();
+        ActivityInfo activityInfo = new ActivityInfo();
+
+        activityInfo.packageName = TEST_COMPONENT_NAME.getPackageName();
+        activityInfo.name = SIM_FULL_NAME;
+
+        info.activityInfo = activityInfo;
+        return info;
+    }
 }
diff --git a/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
new file mode 100644
index 0000000..a62103e
--- /dev/null
+++ b/tests/TelephonyCommonTests/src/com/android/internal/telephony/tests/TelephonyUtilsTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.telephony.tests;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.telephony.SubscriptionManager;
+
+import com.android.internal.telephony.util.TelephonyUtils;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+
+public class TelephonyUtilsTest {
+    @Rule
+    public final MockitoRule mockito = MockitoJUnit.rule();
+
+    // Mocked classes
+    @Mock
+    private Context mContext;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
+
+    @Before
+    public void setup() {
+        doReturn(mSubscriptionManager).when(mContext)
+                .getSystemService(eq(SubscriptionManager.class));
+    }
+
+
+    @Test
+    public void getSubscriptionUserHandle_subId_invalid() {
+        int invalidSubId = -10;
+        doReturn(false).when(mSubscriptionManager).isActiveSubscriptionId(eq(invalidSubId));
+
+        TelephonyUtils.getSubscriptionUserHandle(mContext, invalidSubId);
+
+        // getSubscriptionUserHandle should not be called if subID is inactive.
+        verify(mSubscriptionManager, never()).getSubscriptionUserHandle(eq(invalidSubId));
+    }
+
+    @Test
+    public void getSubscriptionUserHandle_subId_valid() {
+        int activeSubId = 1;
+        doReturn(true).when(mSubscriptionManager).isActiveSubscriptionId(eq(activeSubId));
+
+        TelephonyUtils.getSubscriptionUserHandle(mContext, activeSubId);
+
+        // getSubscriptionUserHandle should be called if subID is active.
+        verify(mSubscriptionManager, times(1)).getSubscriptionUserHandle(eq(activeSubId));
+    }
+}
+
+
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index d133f6f..e2099e6 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -24,12 +24,15 @@
 
 import android.content.Context;
 import android.hardware.usb.UsbManager;
+import android.os.Binder;
 import android.os.RemoteException;
 import android.util.Log;
 
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * Unit tests lib for {@link android.hardware.usb.UsbManager}.
  */
@@ -42,6 +45,11 @@
     private UsbManager mUsbManagerMock;
     @Mock private android.hardware.usb.IUsbManager mMockUsbService;
 
+    /**
+     * Counter for tracking UsbOperation operations.
+     */
+    private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
     public UsbManagerTestLib(Context context) {
         MockitoAnnotations.initMocks(this);
         mContext = context;
@@ -82,10 +90,11 @@
     }
 
     private void testSetCurrentFunctionsMock_Matched(long functions) {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         try {
             setCurrentFunctions(functions);
 
-            verify(mMockUsbService).setCurrentFunctions(eq(functions));
+            verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
         } catch (RemoteException remEx) {
             Log.w(TAG, "RemoteException");
         }
@@ -106,9 +115,10 @@
     }
 
     public void testSetCurrentFunctionsEx(long functions) throws Exception {
+        int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
         setCurrentFunctions(functions);
 
-        verify(mMockUsbService).setCurrentFunctions(eq(functions));
+        verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
     }
 
     public void testGetCurrentFunctions_shouldMatched() {
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 86bcb72..4103ca7 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -98,7 +98,7 @@
         }
 
         @Override
-        protected void setEnabledFunctions(long functions, boolean force) {
+        protected void setEnabledFunctions(long functions, boolean force, int operationId) {
             mCurrentFunctions = functions;
         }
 
@@ -134,6 +134,20 @@
         protected void sendStickyBroadcast(Intent intent) {
             mBroadcastedIntent = intent;
         }
+
+        @Override
+        public void handlerInitDone(int operationId) {
+        }
+
+        @Override
+        public void setCurrentUsbFunctionsCb(long functions,
+                    int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+        }
+
+        @Override
+        public void getUsbSpeedCb(int speed){
+        }
+
     }
 
     @Before
diff --git a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
index e6b60cf..167d560 100644
--- a/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
+++ b/tests/WindowInsetsTests/src/com/google/android/test/windowinsetstests/ControllerActivity.java
@@ -88,46 +88,7 @@
     }
 
     private static String insetsTypesToString(int types) {
-        if (types == 0) {
-            return "none";
-        }
-        final StringBuilder sb = new StringBuilder();
-        if ((types & Type.statusBars()) != 0) {
-            types &= ~Type.statusBars();
-            sb.append("statusBars ");
-        }
-        if ((types & Type.navigationBars()) != 0) {
-            types &= ~Type.navigationBars();
-            sb.append("navigationBars ");
-        }
-        if ((types & Type.captionBar()) != 0) {
-            types &= ~Type.captionBar();
-            sb.append("captionBar ");
-        }
-        if ((types & Type.ime()) != 0) {
-            types &= ~Type.ime();
-            sb.append("ime ");
-        }
-        if ((types & Type.systemGestures()) != 0) {
-            types &= ~Type.systemGestures();
-            sb.append("systemGestures ");
-        }
-        if ((types & Type.mandatorySystemGestures()) != 0) {
-            types &= ~Type.mandatorySystemGestures();
-            sb.append("mandatorySystemGestures ");
-        }
-        if ((types & Type.tappableElement()) != 0) {
-            types &= ~Type.tappableElement();
-            sb.append("tappableElement ");
-        }
-        if ((types & Type.displayCutout()) != 0) {
-            types &= ~Type.displayCutout();
-            sb.append("displayCutout ");
-        }
-        if (types != 0) {
-            sb.append("unknownTypes:").append(types);
-        }
-        return sb.toString();
+        return types == 0 ? "none" : WindowInsets.Type.toString(types);
     }
 
     @Override
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index 15a6afc..7c5dcf8 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -50,6 +50,7 @@
             "android.app.servertransaction.", // all tests under the package.
             "android.view.CutoutSpecificationTest",
             "android.view.DisplayCutoutTest",
+            "android.view.DisplayShapeTest",
             "android.view.InsetsAnimationControlImplTest",
             "android.view.InsetsControllerTest",
             "android.view.InsetsFlagsTest",
diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index 9b9cde2..6b1fd9f 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -72,7 +72,7 @@
   }
 }
 
-std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path,
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(StringPiece path,
                                                       android::IDiagnostics* diag) {
   android::Source source(path);
   std::string error;
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index a4aff3f..4cd7eae 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -45,7 +45,7 @@
   virtual ~LoadedApk() = default;
 
   // Loads both binary and proto APKs from disk.
-  static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
+  static std::unique_ptr<LoadedApk> LoadApkFromPath(android::StringPiece path,
                                                     android::IDiagnostics* diag);
 
   // Loads a proto APK from the given file collection.
diff --git a/tools/aapt2/NameMangler.h b/tools/aapt2/NameMangler.h
index 0b49052..0b08c32 100644
--- a/tools/aapt2/NameMangler.h
+++ b/tools/aapt2/NameMangler.h
@@ -36,7 +36,7 @@
    * We must know which references to mangle, and which to keep (android vs.
    * com.android.support).
    */
-  std::set<std::string> packages_to_mangle;
+  std::set<std::string, std::less<>> packages_to_mangle;
 };
 
 class NameMangler {
@@ -54,7 +54,7 @@
                         mangled_entry_name);
   }
 
-  bool ShouldMangle(const std::string& package) const {
+  bool ShouldMangle(std::string_view package) const {
     if (package.empty() || policy_.target_package_name == package) {
       return false;
     }
@@ -68,8 +68,8 @@
    * The mangled name should contain symbols that are illegal to define in XML,
    * so that there will never be name mangling collisions.
    */
-  static std::string MangleEntry(const std::string& package, const std::string& name) {
-    return package + "$" + name;
+  static std::string MangleEntry(std::string_view package, std::string_view name) {
+    return (std::string(package) += '$') += name;
   }
 
   /**
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index df8c3b9..cfcb2bb 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -138,11 +138,11 @@
   return {to_string(t), t};
 }
 
-std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s) {
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(android::StringPiece s) {
   auto dot = std::find(s.begin(), s.end(), '.');
   const ResourceType* parsedType;
   if (dot != s.end() && dot != std::prev(s.end())) {
-    parsedType = ParseResourceType(s.substr(s.begin(), dot));
+    parsedType = ParseResourceType(android::StringPiece(s.begin(), dot - s.begin()));
   } else {
     parsedType = ParseResourceType(s);
   }
@@ -152,7 +152,7 @@
   return ResourceNamedTypeRef(s, *parsedType);
 }
 
-const ResourceType* ParseResourceType(const StringPiece& str) {
+const ResourceType* ParseResourceType(StringPiece str) {
   auto iter = sResourceTypeMap.find(str);
   if (iter == std::end(sResourceTypeMap)) {
     return nullptr;
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 9cfaf47..7ba3277 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -74,7 +74,7 @@
 /**
  * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
  */
-const ResourceType* ParseResourceType(const android::StringPiece& str);
+const ResourceType* ParseResourceType(android::StringPiece str);
 
 /**
  * Pair of type name as in ResourceTable and actual resource type.
@@ -87,7 +87,7 @@
   ResourceType type = ResourceType::kRaw;
 
   ResourceNamedType() = default;
-  ResourceNamedType(const android::StringPiece& n, ResourceType t);
+  ResourceNamedType(android::StringPiece n, ResourceType t);
 
   int compare(const ResourceNamedType& other) const;
 
@@ -108,19 +108,19 @@
   ResourceNamedTypeRef(const ResourceNamedTypeRef&) = default;
   ResourceNamedTypeRef(ResourceNamedTypeRef&&) = default;
   ResourceNamedTypeRef(const ResourceNamedType& rhs);  // NOLINT(google-explicit-constructor)
-  ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t);
+  ResourceNamedTypeRef(android::StringPiece n, ResourceType t);
   ResourceNamedTypeRef& operator=(const ResourceNamedTypeRef& rhs) = default;
   ResourceNamedTypeRef& operator=(ResourceNamedTypeRef&& rhs) = default;
   ResourceNamedTypeRef& operator=(const ResourceNamedType& rhs);
 
   ResourceNamedType ToResourceNamedType() const;
 
-  std::string to_string() const;
+  std::string_view to_string() const;
 };
 
 ResourceNamedTypeRef ResourceNamedTypeWithDefaultName(ResourceType t);
 
-std::optional<ResourceNamedTypeRef> ParseResourceNamedType(const android::StringPiece& s);
+std::optional<ResourceNamedTypeRef> ParseResourceNamedType(android::StringPiece s);
 
 /**
  * A resource's name. This can uniquely identify
@@ -132,9 +132,8 @@
   std::string entry;
 
   ResourceName() = default;
-  ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t,
-               const android::StringPiece& e);
-  ResourceName(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
+  ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
+  ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e);
 
   int compare(const ResourceName& other) const;
 
@@ -157,9 +156,8 @@
   ResourceNameRef(const ResourceNameRef&) = default;
   ResourceNameRef(ResourceNameRef&&) = default;
   ResourceNameRef(const ResourceName& rhs);  // NOLINT(google-explicit-constructor)
-  ResourceNameRef(const android::StringPiece& p, const ResourceNamedTypeRef& t,
-                  const android::StringPiece& e);
-  ResourceNameRef(const android::StringPiece& p, ResourceType t, const android::StringPiece& e);
+  ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t, android::StringPiece e);
+  ResourceNameRef(android::StringPiece p, ResourceType t, android::StringPiece e);
   ResourceNameRef& operator=(const ResourceNameRef& rhs) = default;
   ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
   ResourceNameRef& operator=(const ResourceName& rhs);
@@ -346,8 +344,8 @@
 //
 // ResourceNamedType implementation.
 //
-inline ResourceNamedType::ResourceNamedType(const android::StringPiece& n, ResourceType t)
-    : name(n.to_string()), type(t) {
+inline ResourceNamedType::ResourceNamedType(android::StringPiece n, ResourceType t)
+    : name(n), type(t) {
 }
 
 inline int ResourceNamedType::compare(const ResourceNamedType& other) const {
@@ -380,7 +378,7 @@
 //
 // ResourceNamedTypeRef implementation.
 //
-inline ResourceNamedTypeRef::ResourceNamedTypeRef(const android::StringPiece& n, ResourceType t)
+inline ResourceNamedTypeRef::ResourceNamedTypeRef(android::StringPiece n, ResourceType t)
     : name(n), type(t) {
 }
 
@@ -398,8 +396,8 @@
   return ResourceNamedType(name, type);
 }
 
-inline std::string ResourceNamedTypeRef::to_string() const {
-  return name.to_string();
+inline std::string_view ResourceNamedTypeRef::to_string() const {
+  return name;
 }
 
 inline bool operator<(const ResourceNamedTypeRef& lhs, const ResourceNamedTypeRef& rhs) {
@@ -422,13 +420,12 @@
 // ResourceName implementation.
 //
 
-inline ResourceName::ResourceName(const android::StringPiece& p, const ResourceNamedTypeRef& t,
-                                  const android::StringPiece& e)
-    : package(p.to_string()), type(t.ToResourceNamedType()), entry(e.to_string()) {
+inline ResourceName::ResourceName(android::StringPiece p, const ResourceNamedTypeRef& t,
+                                  android::StringPiece e)
+    : package(p), type(t.ToResourceNamedType()), entry(e) {
 }
 
-inline ResourceName::ResourceName(const android::StringPiece& p, ResourceType t,
-                                  const android::StringPiece& e)
+inline ResourceName::ResourceName(android::StringPiece p, ResourceType t, android::StringPiece e)
     : ResourceName(p, ResourceNamedTypeWithDefaultName(t), e) {
 }
 
@@ -471,14 +468,13 @@
 inline ResourceNameRef::ResourceNameRef(const ResourceName& rhs)
     : package(rhs.package), type(rhs.type), entry(rhs.entry) {}
 
-inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p,
-                                        const ResourceNamedTypeRef& t,
-                                        const android::StringPiece& e)
+inline ResourceNameRef::ResourceNameRef(android::StringPiece p, const ResourceNamedTypeRef& t,
+                                        android::StringPiece e)
     : package(p), type(t), entry(e) {
 }
 
-inline ResourceNameRef::ResourceNameRef(const android::StringPiece& p, ResourceType t,
-                                        const android::StringPiece& e)
+inline ResourceNameRef::ResourceNameRef(android::StringPiece p, ResourceType t,
+                                        android::StringPiece e)
     : ResourceNameRef(p, ResourceNamedTypeWithDefaultName(t), e) {
 }
 
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 19fd306..fa9a98f 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -50,11 +50,11 @@
 constexpr const char* sXliffNamespaceUri = "urn:oasis:names:tc:xliff:document:1.2";
 
 // Returns true if the element is <skip> or <eat-comment> and can be safely ignored.
-static bool ShouldIgnoreElement(const StringPiece& ns, const StringPiece& name) {
+static bool ShouldIgnoreElement(StringPiece ns, StringPiece name) {
   return ns.empty() && (name == "skip" || name == "eat-comment");
 }
 
-static uint32_t ParseFormatTypeNoEnumsOrFlags(const StringPiece& piece) {
+static uint32_t ParseFormatTypeNoEnumsOrFlags(StringPiece piece) {
   if (piece == "reference") {
     return android::ResTable_map::TYPE_REFERENCE;
   } else if (piece == "string") {
@@ -75,7 +75,7 @@
   return 0;
 }
 
-static uint32_t ParseFormatType(const StringPiece& piece) {
+static uint32_t ParseFormatType(StringPiece piece) {
   if (piece == "enum") {
     return android::ResTable_map::TYPE_ENUM;
   } else if (piece == "flags") {
@@ -84,9 +84,9 @@
   return ParseFormatTypeNoEnumsOrFlags(piece);
 }
 
-static uint32_t ParseFormatAttribute(const StringPiece& str) {
+static uint32_t ParseFormatAttribute(StringPiece str) {
   uint32_t mask = 0;
-  for (const StringPiece& part : util::Tokenize(str, '|')) {
+  for (StringPiece part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
     uint32_t type = ParseFormatType(trimmed_part);
     if (type == 0) {
@@ -122,7 +122,7 @@
   StringPiece trimmed_comment = util::TrimWhitespace(res->comment);
   if (trimmed_comment.size() != res->comment.size()) {
     // Only if there was a change do we re-assign.
-    res->comment = trimmed_comment.to_string();
+    res->comment = std::string(trimmed_comment);
   }
 
   NewResourceBuilder res_builder(res->name);
@@ -362,7 +362,7 @@
       // Trim leading whitespace.
       StringPiece trimmed = util::TrimLeadingWhitespace(first_segment->data);
       if (trimmed.size() != first_segment->data.size()) {
-        first_segment->data = trimmed.to_string();
+        first_segment->data = std::string(trimmed);
       }
     }
 
@@ -370,7 +370,7 @@
       // Trim trailing whitespace.
       StringPiece trimmed = util::TrimTrailingWhitespace(last_segment->data);
       if (trimmed.size() != last_segment->data.size()) {
-        last_segment->data = trimmed.to_string();
+        last_segment->data = std::string(trimmed);
       }
     }
   }
@@ -466,7 +466,7 @@
 
     // Extract the product name if it exists.
     if (std::optional<StringPiece> maybe_product = xml::FindNonEmptyAttribute(parser, "product")) {
-      parsed_resource.product = maybe_product.value().to_string();
+      parsed_resource.product = std::string(maybe_product.value());
     }
 
     // Parse the resource regardless of product.
@@ -559,7 +559,7 @@
 
     // Items have their type encoded in the type attribute.
     if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
-      resource_type = maybe_type.value().to_string();
+      resource_type = std::string(maybe_type.value());
     } else {
       diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
                    << "<item> must have a 'type' attribute");
@@ -582,7 +582,7 @@
 
     // Bags have their type encoded in the type attribute.
     if (std::optional<StringPiece> maybe_type = xml::FindNonEmptyAttribute(parser, "type")) {
-      resource_type = maybe_type.value().to_string();
+      resource_type = std::string(maybe_type.value());
     } else {
       diag_->Error(android::DiagMessage(source_.WithLine(parser->line_number()))
                    << "<bag> must have a 'type' attribute");
@@ -603,7 +603,7 @@
 
     out_resource->name.type =
         ResourceNamedTypeWithDefaultName(ResourceType::kId).ToResourceNamedType();
-    out_resource->name.entry = maybe_name.value().to_string();
+    out_resource->name.entry = std::string(maybe_name.value());
 
     // Ids either represent a unique resource id or reference another resource id
     auto item = ParseItem(parser, out_resource, resource_format);
@@ -640,7 +640,7 @@
 
     out_resource->name.type =
         ResourceNamedTypeWithDefaultName(ResourceType::kMacro).ToResourceNamedType();
-    out_resource->name.entry = maybe_name.value().to_string();
+    out_resource->name.entry = std::string(maybe_name.value());
     return ParseMacro(parser, out_resource);
   }
 
@@ -657,7 +657,7 @@
 
       out_resource->name.type =
           ResourceNamedTypeWithDefaultName(item_iter->second.type).ToResourceNamedType();
-      out_resource->name.entry = maybe_name.value().to_string();
+      out_resource->name.entry = std::string(maybe_name.value());
 
       // Only use the implied format of the type when there is no explicit format.
       if (resource_format == 0u) {
@@ -684,7 +684,7 @@
           return false;
         }
 
-        out_resource->name.entry = maybe_name.value().to_string();
+        out_resource->name.entry = std::string(maybe_name.value());
       }
 
       // Call the associated parse method. The type will be filled in by the
@@ -708,7 +708,7 @@
       }
 
       out_resource->name.type = parsed_type->ToResourceNamedType();
-      out_resource->name.entry = maybe_name.value().to_string();
+      out_resource->name.entry = std::string(maybe_name.value());
       out_resource->value = ParseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString);
       if (!out_resource->value) {
         diag_->Error(android::DiagMessage(out_resource->source)
@@ -1005,7 +1005,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).to_string();
+      comment = std::string(util::TrimWhitespace(parser->comment()));
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Skip text.
@@ -1045,7 +1045,7 @@
       }
 
       ParsedResource& entry_res = out_resource->child_resources.emplace_back(ParsedResource{
-          .name = ResourceName{{}, parsed_type, maybe_name.value().to_string()},
+          .name = ResourceName{{}, parsed_type, std::string(maybe_name.value())},
           .source = item_source,
           .comment = std::move(comment),
       });
@@ -1231,7 +1231,7 @@
 
       ParsedResource child_resource{};
       child_resource.name.type = type->ToResourceNamedType();
-      child_resource.name.entry = item_name.value().to_string();
+      child_resource.name.entry = std::string(item_name.value());
       child_resource.overlayable_item = overlayable_item;
       out_resource->child_resources.push_back(std::move(child_resource));
 
@@ -1246,7 +1246,7 @@
                      xml::FindNonEmptyAttribute(parser, "type")) {
         // Parse the polices separated by vertical bar characters to allow for specifying multiple
         // policies. Items within the policy tag will have the specified policy.
-        for (const StringPiece& part : util::Tokenize(maybe_type.value(), '|')) {
+        for (StringPiece part : util::Tokenize(maybe_type.value(), '|')) {
           StringPiece trimmed_part = util::TrimWhitespace(part);
           const auto policy = std::find_if(kPolicyStringToFlag.begin(),
                                            kPolicyStringToFlag.end(),
@@ -1377,7 +1377,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).to_string();
+      comment = std::string(util::TrimWhitespace(parser->comment()));
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Skip text.
@@ -1457,7 +1457,7 @@
 }
 
 std::optional<Attribute::Symbol> ResourceParser::ParseEnumOrFlagItem(xml::XmlPullParser* parser,
-                                                                     const StringPiece& tag) {
+                                                                     StringPiece tag) {
   const android::Source source = source_.WithLine(parser->line_number());
 
   std::optional<StringPiece> maybe_name = xml::FindNonEmptyAttribute(parser, "name");
@@ -1764,7 +1764,7 @@
   const size_t depth = parser->depth();
   while (xml::XmlPullParser::NextChildNode(parser, depth)) {
     if (parser->event() == xml::XmlPullParser::Event::kComment) {
-      comment = util::TrimWhitespace(parser->comment()).to_string();
+      comment = std::string(util::TrimWhitespace(parser->comment()));
       continue;
     } else if (parser->event() != xml::XmlPullParser::Event::kStartElement) {
       // Ignore text.
diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h
index 396ce97..012a056 100644
--- a/tools/aapt2/ResourceParser.h
+++ b/tools/aapt2/ResourceParser.h
@@ -122,7 +122,7 @@
   bool ParseAttr(xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseAttrImpl(xml::XmlPullParser* parser, ParsedResource* out_resource, bool weak);
   std::optional<Attribute::Symbol> ParseEnumOrFlagItem(xml::XmlPullParser* parser,
-                                                       const android::StringPiece& tag);
+                                                       android::StringPiece tag);
   bool ParseStyle(ResourceType type, xml::XmlPullParser* parser, ParsedResource* out_resource);
   bool ParseStyleItem(xml::XmlPullParser* parser, Style* style);
   bool ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource);
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index fe7eb96..b59b165 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -65,11 +65,11 @@
     context_ = test::ContextBuilder().Build();
   }
 
-  ::testing::AssertionResult TestParse(const StringPiece& str) {
+  ::testing::AssertionResult TestParse(StringPiece str) {
     return TestParse(str, ConfigDescription{});
   }
 
-  ::testing::AssertionResult TestParse(const StringPiece& str, const ConfigDescription& config) {
+  ::testing::AssertionResult TestParse(StringPiece str, const ConfigDescription& config) {
     ResourceParserOptions parserOptions;
     ResourceParser parser(context_->GetDiagnostics(), &table_, android::Source{"test"}, config,
                           parserOptions);
diff --git a/tools/aapt2/ResourceTable.cpp b/tools/aapt2/ResourceTable.cpp
index cb48114..a3b0b45 100644
--- a/tools/aapt2/ResourceTable.cpp
+++ b/tools/aapt2/ResourceTable.cpp
@@ -49,21 +49,21 @@
 }
 
 template <typename T>
-bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, const StringPiece& rhs) {
+bool less_than_struct_with_name(const std::unique_ptr<T>& lhs, StringPiece rhs) {
   return lhs->name.compare(0, lhs->name.size(), rhs.data(), rhs.size()) < 0;
 }
 
 template <typename T>
-bool greater_than_struct_with_name(const StringPiece& lhs, const std::unique_ptr<T>& rhs) {
+bool greater_than_struct_with_name(StringPiece lhs, const std::unique_ptr<T>& rhs) {
   return rhs->name.compare(0, rhs->name.size(), lhs.data(), lhs.size()) > 0;
 }
 
 template <typename T>
 struct NameEqualRange {
-  bool operator()(const std::unique_ptr<T>& lhs, const StringPiece& rhs) const {
+  bool operator()(const std::unique_ptr<T>& lhs, StringPiece rhs) const {
     return less_than_struct_with_name<T>(lhs, rhs);
   }
-  bool operator()(const StringPiece& lhs, const std::unique_ptr<T>& rhs) const {
+  bool operator()(StringPiece lhs, const std::unique_ptr<T>& rhs) const {
     return greater_than_struct_with_name<T>(lhs, rhs);
   }
 };
@@ -78,7 +78,7 @@
 }
 
 template <typename T, typename Func, typename Elements>
-T* FindElementsRunAction(const android::StringPiece& name, Elements& entries, Func action) {
+T* FindElementsRunAction(android::StringPiece name, Elements& entries, Func action) {
   const auto iter =
       std::lower_bound(entries.begin(), entries.end(), name, less_than_struct_with_name<T>);
   const bool found = iter != entries.end() && name == (*iter)->name;
@@ -87,7 +87,7 @@
 
 struct ConfigKey {
   const ConfigDescription* config;
-  const StringPiece& product;
+  StringPiece product;
 };
 
 template <typename T>
@@ -104,12 +104,12 @@
 ResourceTable::ResourceTable(ResourceTable::Validation validation) : validation_(validation) {
 }
 
-ResourceTablePackage* ResourceTable::FindPackage(const android::StringPiece& name) const {
+ResourceTablePackage* ResourceTable::FindPackage(android::StringPiece name) const {
   return FindElementsRunAction<ResourceTablePackage>(
       name, packages, [&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
 }
 
-ResourceTablePackage* ResourceTable::FindOrCreatePackage(const android::StringPiece& name) {
+ResourceTablePackage* ResourceTable::FindOrCreatePackage(android::StringPiece name) {
   return FindElementsRunAction<ResourceTablePackage>(name, packages, [&](bool found, auto& iter) {
     return found ? iter->get() : packages.emplace(iter, new ResourceTablePackage(name))->get();
   });
@@ -139,18 +139,18 @@
   });
 }
 
-ResourceEntry* ResourceTableType::CreateEntry(const android::StringPiece& name) {
+ResourceEntry* ResourceTableType::CreateEntry(android::StringPiece name) {
   return FindElementsRunAction<ResourceEntry>(name, entries, [&](bool found, auto& iter) {
     return entries.emplace(iter, new ResourceEntry(name))->get();
   });
 }
 
-ResourceEntry* ResourceTableType::FindEntry(const android::StringPiece& name) const {
+ResourceEntry* ResourceTableType::FindEntry(android::StringPiece name) const {
   return FindElementsRunAction<ResourceEntry>(
       name, entries, [&](bool found, auto& iter) { return found ? iter->get() : nullptr; });
 }
 
-ResourceEntry* ResourceTableType::FindOrCreateEntry(const android::StringPiece& name) {
+ResourceEntry* ResourceTableType::FindOrCreateEntry(android::StringPiece name) {
   return FindElementsRunAction<ResourceEntry>(name, entries, [&](bool found, auto& iter) {
     return found ? iter->get() : entries.emplace(iter, new ResourceEntry(name))->get();
   });
@@ -183,7 +183,7 @@
 }
 
 ResourceConfigValue* ResourceEntry::FindOrCreateValue(const ConfigDescription& config,
-                                                      const StringPiece& product) {
+                                                      StringPiece product) {
   auto iter = std::lower_bound(values.begin(), values.end(), ConfigKey{&config, product},
                                lt_config_key_ref<std::unique_ptr<ResourceConfigValue>>);
   if (iter != values.end()) {
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index f49ce81..bb286a8 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -71,12 +71,11 @@
 
 struct Overlayable {
   Overlayable() = default;
-   Overlayable(const android::StringPiece& name, const android::StringPiece& actor)
-       : name(name.to_string()), actor(actor.to_string()) {}
-   Overlayable(const android::StringPiece& name, const android::StringPiece& actor,
-               const android::Source& source)
-       : name(name.to_string()), actor(actor.to_string()), source(source) {
-   }
+  Overlayable(android::StringPiece name, android::StringPiece actor) : name(name), actor(actor) {
+  }
+  Overlayable(android::StringPiece name, android::StringPiece actor, const android::Source& source)
+      : name(name), actor(actor), source(source) {
+  }
 
   static const char* kActorScheme;
   std::string name;
@@ -105,8 +104,9 @@
   // The actual Value.
   std::unique_ptr<Value> value;
 
-  ResourceConfigValue(const android::ConfigDescription& config, const android::StringPiece& product)
-      : config(config), product(product.to_string()) {}
+  ResourceConfigValue(const android::ConfigDescription& config, android::StringPiece product)
+      : config(config), product(product) {
+  }
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
@@ -136,7 +136,8 @@
   // The resource's values for each configuration.
   std::vector<std::unique_ptr<ResourceConfigValue>> values;
 
-  explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
+  explicit ResourceEntry(android::StringPiece name) : name(name) {
+  }
 
   ResourceConfigValue* FindValue(const android::ConfigDescription& config,
                                  android::StringPiece product = {});
@@ -144,7 +145,7 @@
                                        android::StringPiece product = {}) const;
 
   ResourceConfigValue* FindOrCreateValue(const android::ConfigDescription& config,
-                                         const android::StringPiece& product);
+                                         android::StringPiece product);
   std::vector<ResourceConfigValue*> FindAllValues(const android::ConfigDescription& config);
 
   template <typename Func>
@@ -180,9 +181,9 @@
       : named_type(type.ToResourceNamedType()) {
   }
 
-  ResourceEntry* CreateEntry(const android::StringPiece& name);
-  ResourceEntry* FindEntry(const android::StringPiece& name) const;
-  ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
+  ResourceEntry* CreateEntry(android::StringPiece name);
+  ResourceEntry* FindEntry(android::StringPiece name) const;
+  ResourceEntry* FindOrCreateEntry(android::StringPiece name);
 
  private:
   DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
@@ -194,7 +195,7 @@
 
   std::vector<std::unique_ptr<ResourceTableType>> types;
 
-  explicit ResourceTablePackage(const android::StringPiece& name) : name(name.to_string()) {
+  explicit ResourceTablePackage(android::StringPiece name) : name(name) {
   }
 
   ResourceTablePackage() = default;
@@ -319,8 +320,8 @@
   // Returns the package struct with the given name, or nullptr if such a package does not
   // exist. The empty string is a valid package and typically is used to represent the
   // 'current' package before it is known to the ResourceTable.
-  ResourceTablePackage* FindPackage(const android::StringPiece& name) const;
-  ResourceTablePackage* FindOrCreatePackage(const android::StringPiece& name);
+  ResourceTablePackage* FindPackage(android::StringPiece name) const;
+  ResourceTablePackage* FindOrCreatePackage(android::StringPiece name);
 
   std::unique_ptr<ResourceTable> Clone() const;
 
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index 0cf8473..54b98d1 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -187,7 +187,7 @@
 static ::testing::AssertionResult VisibilityOfResource(const ResourceTable& table,
                                                        const ResourceNameRef& name,
                                                        Visibility::Level level,
-                                                       const StringPiece& comment) {
+                                                       StringPiece comment) {
   std::optional<ResourceTable::SearchResult> result = table.FindResource(name);
   if (!result) {
     return ::testing::AssertionFailure() << "no resource '" << name << "' found in table";
diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp
index 41c7435..5a118a9 100644
--- a/tools/aapt2/ResourceUtils.cpp
+++ b/tools/aapt2/ResourceUtils.cpp
@@ -109,8 +109,7 @@
   return name_out;
 }
 
-bool ParseResourceName(const StringPiece& str, ResourceNameRef* out_ref,
-                       bool* out_private) {
+bool ParseResourceName(StringPiece str, ResourceNameRef* out_ref, bool* out_private) {
   if (str.empty()) {
     return false;
   }
@@ -151,8 +150,8 @@
   return true;
 }
 
-bool ParseReference(const StringPiece& str, ResourceNameRef* out_ref,
-                    bool* out_create, bool* out_private) {
+bool ParseReference(StringPiece str, ResourceNameRef* out_ref, bool* out_create,
+                    bool* out_private) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
   if (trimmed_str.empty()) {
     return false;
@@ -198,11 +197,11 @@
   return false;
 }
 
-bool IsReference(const StringPiece& str) {
+bool IsReference(StringPiece str) {
   return ParseReference(str, nullptr, nullptr, nullptr);
 }
 
-bool ParseAttributeReference(const StringPiece& str, ResourceNameRef* out_ref) {
+bool ParseAttributeReference(StringPiece str, ResourceNameRef* out_ref) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
   if (trimmed_str.empty()) {
     return false;
@@ -235,7 +234,7 @@
   return false;
 }
 
-bool IsAttributeReference(const StringPiece& str) {
+bool IsAttributeReference(StringPiece str) {
   return ParseAttributeReference(str, nullptr);
 }
 
@@ -247,7 +246,7 @@
  * <[*]package>:[style/]<entry>
  * [[*]package:style/]<entry>
  */
-std::optional<Reference> ParseStyleParentReference(const StringPiece& str, std::string* out_error) {
+std::optional<Reference> ParseStyleParentReference(StringPiece str, std::string* out_error) {
   if (str.empty()) {
     return {};
   }
@@ -296,7 +295,7 @@
   return result;
 }
 
-std::optional<Reference> ParseXmlAttributeName(const StringPiece& str) {
+std::optional<Reference> ParseXmlAttributeName(StringPiece str) {
   StringPiece trimmed_str = util::TrimWhitespace(str);
   const char* start = trimmed_str.data();
   const char* const end = start + trimmed_str.size();
@@ -325,8 +324,7 @@
   return std::optional<Reference>(std::move(ref));
 }
 
-std::unique_ptr<Reference> TryParseReference(const StringPiece& str,
-                                             bool* out_create) {
+std::unique_ptr<Reference> TryParseReference(StringPiece str, bool* out_create) {
   ResourceNameRef ref;
   bool private_ref = false;
   if (ParseReference(str, &ref, out_create, &private_ref)) {
@@ -344,7 +342,7 @@
   return {};
 }
 
-std::unique_ptr<Item> TryParseNullOrEmpty(const StringPiece& str) {
+std::unique_ptr<Item> TryParseNullOrEmpty(StringPiece str) {
   const StringPiece trimmed_str(util::TrimWhitespace(str));
   if (trimmed_str == "@null") {
     return MakeNull();
@@ -365,8 +363,7 @@
                                             android::Res_value::DATA_NULL_EMPTY);
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
-                                                    const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr, StringPiece str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
   for (const Attribute::Symbol& symbol : enum_attr->symbols) {
     // Enum symbols are stored as @package:id/symbol resources,
@@ -382,8 +379,7 @@
   return {};
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr,
-                                                    const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* flag_attr, StringPiece str) {
   android::Res_value flags = {};
   flags.dataType = android::Res_value::TYPE_INT_HEX;
   flags.data = 0u;
@@ -393,7 +389,7 @@
     return util::make_unique<BinaryPrimitive>(flags);
   }
 
-  for (const StringPiece& part : util::Tokenize(str, '|')) {
+  for (StringPiece part : util::Tokenize(str, '|')) {
     StringPiece trimmed_part = util::TrimWhitespace(part);
 
     bool flag_set = false;
@@ -429,7 +425,7 @@
   }
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseColor(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseColor(StringPiece str) {
   StringPiece color_str(util::TrimWhitespace(str));
   const char* start = color_str.data();
   const size_t len = color_str.size();
@@ -484,7 +480,7 @@
                : util::make_unique<BinaryPrimitive>(value);
 }
 
-std::optional<bool> ParseBool(const StringPiece& str) {
+std::optional<bool> ParseBool(StringPiece str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
   if (trimmed_str == "true" || trimmed_str == "TRUE" || trimmed_str == "True") {
     return std::optional<bool>(true);
@@ -495,7 +491,7 @@
   return {};
 }
 
-std::optional<uint32_t> ParseInt(const StringPiece& str) {
+std::optional<uint32_t> ParseInt(StringPiece str) {
   std::u16string str16 = android::util::Utf8ToUtf16(str);
   android::Res_value value;
   if (android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
@@ -504,7 +500,7 @@
   return {};
 }
 
-std::optional<ResourceId> ParseResourceId(const StringPiece& str) {
+std::optional<ResourceId> ParseResourceId(StringPiece str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
 
   std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
@@ -520,7 +516,7 @@
   return {};
 }
 
-std::optional<int> ParseSdkVersion(const StringPiece& str) {
+std::optional<int> ParseSdkVersion(StringPiece str) {
   StringPiece trimmed_str(util::TrimWhitespace(str));
 
   std::u16string str16 = android::util::Utf8ToUtf16(trimmed_str);
@@ -539,14 +535,14 @@
   const StringPiece::const_iterator begin = std::begin(trimmed_str);
   const StringPiece::const_iterator end = std::end(trimmed_str);
   const StringPiece::const_iterator codename_end = std::find(begin, end, '.');
-  entry = GetDevelopmentSdkCodeNameVersion(trimmed_str.substr(begin, codename_end));
+  entry = GetDevelopmentSdkCodeNameVersion(StringPiece(begin, codename_end - begin));
   if (entry) {
     return entry.value();
   }
   return {};
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseBool(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseBool(StringPiece str) {
   if (std::optional<bool> maybe_result = ParseBool(str)) {
     const uint32_t data = maybe_result.value() ? 0xffffffffu : 0u;
     return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_BOOLEAN, data);
@@ -559,7 +555,7 @@
                                             val ? 0xffffffffu : 0u);
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseInt(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseInt(StringPiece str) {
   std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
   android::Res_value value;
   if (!android::ResTable::stringToInt(str16.data(), str16.size(), &value)) {
@@ -572,7 +568,7 @@
   return util::make_unique<BinaryPrimitive>(android::Res_value::TYPE_INT_DEC, val);
 }
 
-std::unique_ptr<BinaryPrimitive> TryParseFloat(const StringPiece& str) {
+std::unique_ptr<BinaryPrimitive> TryParseFloat(StringPiece str) {
   std::u16string str16 = android::util::Utf8ToUtf16(util::TrimWhitespace(str));
   android::Res_value value;
   if (!android::ResTable::stringToFloat(str16.data(), str16.size(), &value)) {
@@ -623,7 +619,7 @@
 }
 
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const StringPiece& value, uint32_t type_mask,
+    StringPiece value, uint32_t type_mask,
     const std::function<bool(const ResourceName&)>& on_create_reference) {
   using android::ResTable_map;
 
@@ -687,7 +683,7 @@
  * allows.
  */
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const StringPiece& str, const Attribute* attr,
+    StringPiece str, const Attribute* attr,
     const std::function<bool(const ResourceName&)>& on_create_reference) {
   using android::ResTable_map;
 
diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h
index 22cf345..f30f4ac 100644
--- a/tools/aapt2/ResourceUtils.h
+++ b/tools/aapt2/ResourceUtils.h
@@ -38,7 +38,7 @@
  * `out_resource` set to the parsed resource name and `out_private` set to true
  * if a '*' prefix was present.
  */
-bool ParseResourceName(const android::StringPiece& str, ResourceNameRef* out_resource,
+bool ParseResourceName(android::StringPiece str, ResourceNameRef* out_resource,
                        bool* out_private = nullptr);
 
 /*
@@ -49,27 +49,27 @@
  * If '+' was present in the reference, `out_create` is set to true.
  * If '*' was present in the reference, `out_private` is set to true.
  */
-bool ParseReference(const android::StringPiece& str, ResourceNameRef* out_reference,
+bool ParseReference(android::StringPiece str, ResourceNameRef* out_reference,
                     bool* out_create = nullptr, bool* out_private = nullptr);
 
 /*
  * Returns true if the string is in the form of a resource reference
  * (@[+][package:]type/name).
  */
-bool IsReference(const android::StringPiece& str);
+bool IsReference(android::StringPiece str);
 
 /*
  * Returns true if the string was parsed as an attribute reference
  * (?[package:][type/]name),
  * with `out_reference` set to the parsed reference.
  */
-bool ParseAttributeReference(const android::StringPiece& str, ResourceNameRef* out_reference);
+bool ParseAttributeReference(android::StringPiece str, ResourceNameRef* out_reference);
 
 /**
  * Returns true if the string is in the form of an attribute
  * reference(?[package:][type/]name).
  */
-bool IsAttributeReference(const android::StringPiece& str);
+bool IsAttributeReference(android::StringPiece str);
 
 /**
  * Convert an android::ResTable::resource_name to an aapt::ResourceName struct.
@@ -85,22 +85,22 @@
  * Returns a boolean value if the string is equal to TRUE, true, True, FALSE,
  * false, or False.
  */
-std::optional<bool> ParseBool(const android::StringPiece& str);
+std::optional<bool> ParseBool(android::StringPiece str);
 
 /**
  * Returns a uint32_t if the string is an integer.
  */
-std::optional<uint32_t> ParseInt(const android::StringPiece& str);
+std::optional<uint32_t> ParseInt(android::StringPiece str);
 
 /**
  * Returns an ID if it the string represented a valid ID.
  */
-std::optional<ResourceId> ParseResourceId(const android::StringPiece& str);
+std::optional<ResourceId> ParseResourceId(android::StringPiece str);
 
 /**
  * Parses an SDK version, which can be an integer, or a letter from A-Z.
  */
-std::optional<int> ParseSdkVersion(const android::StringPiece& str);
+std::optional<int> ParseSdkVersion(android::StringPiece str);
 
 /*
  * Returns a Reference, or None Maybe instance if the string `str` was parsed as
@@ -113,7 +113,7 @@
  * ?[package:]style/<entry> or
  * <package>:[style/]<entry>
  */
-std::optional<Reference> ParseStyleParentReference(const android::StringPiece& str,
+std::optional<Reference> ParseStyleParentReference(android::StringPiece str,
                                                    std::string* out_error);
 
 /*
@@ -123,7 +123,7 @@
  *
  * package:entry
  */
-std::optional<Reference> ParseXmlAttributeName(const android::StringPiece& str);
+std::optional<Reference> ParseXmlAttributeName(android::StringPiece str);
 
 /*
  * Returns a Reference object if the string was parsed as a resource or
@@ -132,14 +132,13 @@
  * if
  * the '+' was present in the string.
  */
-std::unique_ptr<Reference> TryParseReference(const android::StringPiece& str,
-                                             bool* out_create = nullptr);
+std::unique_ptr<Reference> TryParseReference(android::StringPiece str, bool* out_create = nullptr);
 
 /*
  * Returns a BinaryPrimitve object representing @null or @empty if the string
  * was parsed as one.
  */
-std::unique_ptr<Item> TryParseNullOrEmpty(const android::StringPiece& str);
+std::unique_ptr<Item> TryParseNullOrEmpty(android::StringPiece str);
 
 // Returns a Reference representing @null.
 // Due to runtime compatibility issues, this is encoded as a reference with ID 0.
@@ -154,13 +153,13 @@
  * Returns a BinaryPrimitve object representing a color if the string was parsed
  * as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseColor(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseColor(android::StringPiece str);
 
 /*
  * Returns a BinaryPrimitve object representing a boolean if the string was
  * parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseBool(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseBool(android::StringPiece str);
 
 // Returns a boolean BinaryPrimitive.
 std::unique_ptr<BinaryPrimitive> MakeBool(bool val);
@@ -169,7 +168,7 @@
  * Returns a BinaryPrimitve object representing an integer if the string was
  * parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseInt(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseInt(android::StringPiece str);
 
 // Returns an integer BinaryPrimitive.
 std::unique_ptr<BinaryPrimitive> MakeInt(uint32_t value);
@@ -178,21 +177,21 @@
  * Returns a BinaryPrimitve object representing a floating point number
  * (float, dimension, etc) if the string was parsed as one.
  */
-std::unique_ptr<BinaryPrimitive> TryParseFloat(const android::StringPiece& str);
+std::unique_ptr<BinaryPrimitive> TryParseFloat(android::StringPiece str);
 
 /*
  * Returns a BinaryPrimitve object representing an enum symbol if the string was
  * parsed as one.
  */
 std::unique_ptr<BinaryPrimitive> TryParseEnumSymbol(const Attribute* enum_attr,
-                                                    const android::StringPiece& str);
+                                                    android::StringPiece str);
 
 /*
  * Returns a BinaryPrimitve object representing a flag symbol if the string was
  * parsed as one.
  */
 std::unique_ptr<BinaryPrimitive> TryParseFlagSymbol(const Attribute* enum_attr,
-                                                    const android::StringPiece& str);
+                                                    android::StringPiece str);
 /*
  * Try to convert a string to an Item for the given attribute. The attribute
  * will
@@ -201,11 +200,11 @@
  * reference to an ID that must be created (@+id/foo).
  */
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const android::StringPiece& value, const Attribute* attr,
+    android::StringPiece value, const Attribute* attr,
     const std::function<bool(const ResourceName&)>& on_create_reference = {});
 
 std::unique_ptr<Item> TryParseItemForAttribute(
-    const android::StringPiece& value, uint32_t type_mask,
+    android::StringPiece value, uint32_t type_mask,
     const std::function<bool(const ResourceName&)>& on_create_reference = {});
 
 uint32_t AndroidTypeToAttributeTypeMask(uint16_t type);
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index c4d54be..a5754e0 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -206,7 +206,7 @@
   PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
 }
 
-void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const {
+void Reference::PrettyPrint(StringPiece package, Printer* printer) const {
   const bool print_package = name ? package != name.value().package : true;
   PrettyPrintReferenceImpl(*this, print_package, printer);
 }
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index f5167a1..6f9dccb 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -83,8 +83,8 @@
     return comment_;
   }
 
-  void SetComment(const android::StringPiece& str) {
-    comment_ = str.to_string();
+  void SetComment(android::StringPiece str) {
+    comment_.assign(str);
   }
 
   void SetComment(std::string&& str) {
@@ -176,7 +176,7 @@
   void PrettyPrint(text::Printer* printer) const override;
 
   // Prints the reference without a package name if the package name matches the one given.
-  void PrettyPrint(const android::StringPiece& package, text::Printer* printer) const;
+  void PrettyPrint(android::StringPiece package, text::Printer* printer) const;
 };
 
 bool operator<(const Reference&, const Reference&);
diff --git a/tools/aapt2/SdkConstants.cpp b/tools/aapt2/SdkConstants.cpp
index 34e8edb..a7c5479 100644
--- a/tools/aapt2/SdkConstants.cpp
+++ b/tools/aapt2/SdkConstants.cpp
@@ -77,7 +77,7 @@
   return iter->second;
 }
 
-std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const StringPiece& code_name) {
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(StringPiece code_name) {
   return (sDevelopmentSdkCodeNames.find(code_name) == sDevelopmentSdkCodeNames.end())
              ? std::optional<ApiVersion>()
              : sDevelopmentSdkLevel;
diff --git a/tools/aapt2/SdkConstants.h b/tools/aapt2/SdkConstants.h
index 0bd61c0..40bcef7 100644
--- a/tools/aapt2/SdkConstants.h
+++ b/tools/aapt2/SdkConstants.h
@@ -63,7 +63,7 @@
 };
 
 ApiVersion FindAttributeSdkLevel(const ResourceId& id);
-std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(const android::StringPiece& code_name);
+std::optional<ApiVersion> GetDevelopmentSdkCodeNameVersion(android::StringPiece code_name);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/cmd/ApkInfo.cpp b/tools/aapt2/cmd/ApkInfo.cpp
index 697b110..3c0831c 100644
--- a/tools/aapt2/cmd/ApkInfo.cpp
+++ b/tools/aapt2/cmd/ApkInfo.cpp
@@ -64,7 +64,7 @@
     Usage(&std::cerr);
     return 1;
   }
-  const StringPiece& path = args[0];
+  StringPiece path = args[0];
   std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, diag_);
   if (!apk) {
     return 1;
diff --git a/tools/aapt2/cmd/Command.cpp b/tools/aapt2/cmd/Command.cpp
index b1452fa..514651e 100644
--- a/tools/aapt2/cmd/Command.cpp
+++ b/tools/aapt2/cmd/Command.cpp
@@ -33,7 +33,7 @@
 
 namespace aapt {
 
-std::string GetSafePath(const StringPiece& arg) {
+std::string GetSafePath(StringPiece arg) {
 #ifdef _WIN32
   // If the path exceeds the maximum path length for Windows, encode the path using the
   // extended-length prefix
@@ -47,63 +47,62 @@
 
   return path8;
 #else
-  return arg.to_string();
+  return std::string(arg);
 #endif
 }
 
-void Command::AddRequiredFlag(const StringPiece& name, const StringPiece& description,
-                              std::string* value, uint32_t flags) {
-  auto func = [value, flags](const StringPiece& arg) -> bool {
-    *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
+void Command::AddRequiredFlag(StringPiece name, StringPiece description, std::string* value,
+                              uint32_t flags) {
+  auto func = [value, flags](StringPiece arg) -> bool {
+    *value = (flags & Command::kPath) ? GetSafePath(arg) : std::string(arg);
     return true;
   };
 
   flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
 }
 
-void Command::AddRequiredFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddRequiredFlagList(StringPiece name, StringPiece description,
                                   std::vector<std::string>* value, uint32_t flags) {
-  auto func = [value, flags](const StringPiece& arg) -> bool {
-    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
+  auto func = [value, flags](StringPiece arg) -> bool {
+    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : std::string(arg));
     return true;
   };
 
   flags_.emplace_back(Flag(name, description, /* required */ true, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlag(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlag(StringPiece name, StringPiece description,
                               std::optional<std::string>* value, uint32_t flags) {
-  auto func = [value, flags](const StringPiece& arg) -> bool {
-    *value = (flags & Command::kPath) ? GetSafePath(arg) : arg.to_string();
+  auto func = [value, flags](StringPiece arg) -> bool {
+    *value = (flags & Command::kPath) ? GetSafePath(arg) : std::string(arg);
     return true;
   };
 
   flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlagList(StringPiece name, StringPiece description,
                                   std::vector<std::string>* value, uint32_t flags) {
-  auto func = [value, flags](const StringPiece& arg) -> bool {
-    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : arg.to_string());
+  auto func = [value, flags](StringPiece arg) -> bool {
+    value->push_back((flags & Command::kPath) ? GetSafePath(arg) : std::string(arg));
     return true;
   };
 
   flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalFlagList(const StringPiece& name, const StringPiece& description,
+void Command::AddOptionalFlagList(StringPiece name, StringPiece description,
                                   std::unordered_set<std::string>* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
-    value->insert(arg.to_string());
+  auto func = [value](StringPiece arg) -> bool {
+    value->emplace(arg);
     return true;
   };
 
   flags_.emplace_back(Flag(name, description, /* required */ false, /* num_args */ 1, func));
 }
 
-void Command::AddOptionalSwitch(const StringPiece& name, const StringPiece& description,
-                                bool* value) {
-  auto func = [value](const StringPiece& arg) -> bool {
+void Command::AddOptionalSwitch(StringPiece name, StringPiece description, bool* value) {
+  auto func = [value](StringPiece arg) -> bool {
     *value = true;
     return true;
   };
@@ -120,8 +119,8 @@
   }
 }
 
-void Command::SetDescription(const StringPiece& description) {
-  description_ = description.to_string();
+void Command::SetDescription(StringPiece description) {
+  description_ = std::string(description);
 }
 
 void Command::Usage(std::ostream* out) {
@@ -183,7 +182,7 @@
   std::vector<std::string> file_args;
 
   for (size_t i = 0; i < args.size(); i++) {
-    const StringPiece& arg = args[i];
+    StringPiece arg = args[i];
     if (*(arg.data()) != '-') {
       // Continue parsing as the subcommand if the first argument matches one of the subcommands
       if (i == 0) {
diff --git a/tools/aapt2/cmd/Command.h b/tools/aapt2/cmd/Command.h
index 8678cda..1416e98 100644
--- a/tools/aapt2/cmd/Command.h
+++ b/tools/aapt2/cmd/Command.h
@@ -30,13 +30,10 @@
 
 class Command {
  public:
-  explicit Command(const android::StringPiece& name)
-      : name_(name.to_string()), full_subcommand_name_(name.to_string()){};
+  explicit Command(android::StringPiece name) : name_(name), full_subcommand_name_(name){};
 
-  explicit Command(const android::StringPiece& name, const android::StringPiece& short_name)
-      : name_(name.to_string()),
-        short_name_(short_name.to_string()),
-        full_subcommand_name_(name.to_string()){};
+  explicit Command(android::StringPiece name, android::StringPiece short_name)
+      : name_(name), short_name_(short_name), full_subcommand_name_(name){};
 
   Command(Command&&) = default;
   Command& operator=(Command&&) = default;
@@ -52,30 +49,26 @@
     kPath = 1 << 0,
   };
 
-  void AddRequiredFlag(const android::StringPiece& name, const android::StringPiece& description,
+  void AddRequiredFlag(android::StringPiece name, android::StringPiece description,
                        std::string* value, uint32_t flags = 0);
 
-  void AddRequiredFlagList(const android::StringPiece& name,
-                           const android::StringPiece& description, std::vector<std::string>* value,
-                           uint32_t flags = 0);
+  void AddRequiredFlagList(android::StringPiece name, android::StringPiece description,
+                           std::vector<std::string>* value, uint32_t flags = 0);
 
-  void AddOptionalFlag(const android::StringPiece& name, const android::StringPiece& description,
+  void AddOptionalFlag(android::StringPiece name, android::StringPiece description,
                        std::optional<std::string>* value, uint32_t flags = 0);
 
-  void AddOptionalFlagList(const android::StringPiece& name,
-                           const android::StringPiece& description, std::vector<std::string>* value,
-                           uint32_t flags = 0);
+  void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
+                           std::vector<std::string>* value, uint32_t flags = 0);
 
-  void AddOptionalFlagList(const android::StringPiece& name,
-                           const android::StringPiece& description,
+  void AddOptionalFlagList(android::StringPiece name, android::StringPiece description,
                            std::unordered_set<std::string>* value);
 
-  void AddOptionalSwitch(const android::StringPiece& name, const android::StringPiece& description,
-                         bool* value);
+  void AddOptionalSwitch(android::StringPiece name, android::StringPiece description, bool* value);
 
   void AddOptionalSubcommand(std::unique_ptr<Command>&& subcommand, bool experimental = false);
 
-  void SetDescription(const android::StringPiece& name);
+  void SetDescription(android::StringPiece name);
 
   // Prints the help menu of the command.
   void Usage(std::ostream* out);
@@ -90,17 +83,21 @@
 
  private:
   struct Flag {
-    explicit Flag(const android::StringPiece& name, const android::StringPiece& description,
+    explicit Flag(android::StringPiece name, android::StringPiece description,
                   const bool is_required, const size_t num_args,
-                  std::function<bool(const android::StringPiece& value)>&& action)
-        : name(name.to_string()), description(description.to_string()), is_required(is_required),
-          num_args(num_args), action(std::move(action)) {}
+                  std::function<bool(android::StringPiece value)>&& action)
+        : name(name),
+          description(description),
+          is_required(is_required),
+          num_args(num_args),
+          action(std::move(action)) {
+    }
 
     const std::string name;
     const std::string description;
     const bool is_required;
     const size_t num_args;
-    const std::function<bool(const android::StringPiece& value)> action;
+    const std::function<bool(android::StringPiece value)> action;
     bool found = false;
   };
 
diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 0409f73..03f9715 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -125,8 +125,12 @@
   const android::Source res_path =
       options.source_path ? StringPiece(options.source_path.value()) : StringPiece(path);
 
-  return ResourcePathData{res_path, dir_str.to_string(), name.to_string(),
-                          extension.to_string(), config_str.to_string(), config};
+  return ResourcePathData{res_path,
+                          std::string(dir_str),
+                          std::string(name),
+                          std::string(extension),
+                          std::string(config_str),
+                          config};
 }
 
 static std::string BuildIntermediateContainerFilename(const ResourcePathData& data) {
@@ -279,7 +283,7 @@
   return true;
 }
 
-static bool WriteHeaderAndDataToWriter(const StringPiece& output_path, const ResourceFile& file,
+static bool WriteHeaderAndDataToWriter(StringPiece output_path, const ResourceFile& file,
                                        io::KnownSizeInputStream* in, IArchiveWriter* writer,
                                        android::IDiagnostics* diag) {
   TRACE_CALL();
@@ -311,7 +315,7 @@
   return true;
 }
 
-static bool FlattenXmlToOutStream(const StringPiece& output_path, const xml::XmlResource& xmlres,
+static bool FlattenXmlToOutStream(StringPiece output_path, const xml::XmlResource& xmlres,
                                   ContainerWriter* container_writer, android::IDiagnostics* diag) {
   pb::internal::CompiledFile pb_compiled_file;
   SerializeCompiledFileToPb(xmlres.file, &pb_compiled_file);
@@ -538,7 +542,7 @@
     if (context->IsVerbose()) {
       // For debugging only, use the legacy PNG cruncher and compare the resulting file sizes.
       // This will help catch exotic cases where the new code may generate larger PNGs.
-      std::stringstream legacy_stream(content.to_string());
+      std::stringstream legacy_stream{std::string(content)};
       android::BigBuffer legacy_buffer(4096);
       Png png(context->GetDiagnostics());
       if (!png.process(path_data.source, &legacy_stream, &legacy_buffer, {})) {
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
index 52e113e..612e3a6 100644
--- a/tools/aapt2/cmd/Convert.cpp
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -387,7 +387,7 @@
   }
 
   Context context;
-  const StringPiece& path = args[0];
+  StringPiece path = args[0];
   unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
   if (apk == nullptr) {
     context.GetDiagnostics()->Error(android::DiagMessage(path) << "failed to load APK");
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 423e939..5bfc732 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -78,7 +78,7 @@
   SymbolTable symbol_table_;
 };
 
-static void EmitDiffLine(const android::Source& source, const StringPiece& message) {
+static void EmitDiffLine(const android::Source& source, StringPiece message) {
   std::cerr << source << ": " << message << "\n";
 }
 
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index a8d2299..97404fc 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -126,8 +126,8 @@
     return compilation_package_;
   }
 
-  void SetCompilationPackage(const StringPiece& package_name) {
-    compilation_package_ = package_name.to_string();
+  void SetCompilationPackage(StringPiece package_name) {
+    compilation_package_ = std::string(package_name);
   }
 
   uint8_t GetPackageId() override {
@@ -240,9 +240,9 @@
   IAaptContext* context_;
 };
 
-static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res,
-                       const StringPiece& path, bool keep_raw_values, bool utf16,
-                       OutputFormat format, IArchiveWriter* writer) {
+static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml_res, StringPiece path,
+                       bool keep_raw_values, bool utf16, OutputFormat format,
+                       IArchiveWriter* writer) {
   TRACE_CALL();
   if (context->IsVerbose()) {
     context->GetDiagnostics()->Note(android::DiagMessage(path)
@@ -262,8 +262,8 @@
       }
 
       io::BigBufferInputStream input_stream(&buffer);
-      return io::CopyInputStreamToArchive(context, &input_stream, path.to_string(),
-                                          ArchiveEntry::kCompress, writer);
+      return io::CopyInputStreamToArchive(context, &input_stream, path, ArchiveEntry::kCompress,
+                                          writer);
     } break;
 
     case OutputFormat::kProto: {
@@ -272,8 +272,7 @@
       SerializeXmlOptions options;
       options.remove_empty_text_nodes = (path == kAndroidManifestPath);
       SerializeXmlResourceToPb(xml_res, &pb_node);
-      return io::CopyProtoToArchive(context, &pb_node, path.to_string(), ArchiveEntry::kCompress,
-                                    writer);
+      return io::CopyProtoToArchive(context, &pb_node, path, ArchiveEntry::kCompress, writer);
     } break;
   }
   return false;
@@ -329,13 +328,13 @@
 };
 
 template <typename T>
-uint32_t GetCompressionFlags(const StringPiece& str, T options) {
+uint32_t GetCompressionFlags(StringPiece str, T options) {
   if (options.do_not_compress_anything) {
     return 0;
   }
 
-  if (options.regex_to_not_compress
-      && std::regex_search(str.to_string(), options.regex_to_not_compress.value())) {
+  if (options.regex_to_not_compress &&
+      std::regex_search(str.begin(), str.end(), options.regex_to_not_compress.value())) {
     return 0;
   }
 
@@ -1176,7 +1175,7 @@
     return bcp47tag;
   }
 
-  std::unique_ptr<IArchiveWriter> MakeArchiveWriter(const StringPiece& out) {
+  std::unique_ptr<IArchiveWriter> MakeArchiveWriter(StringPiece out) {
     if (options_.output_to_directory) {
       return CreateDirectoryArchiveWriter(context_->GetDiagnostics(), out);
     } else {
@@ -1212,8 +1211,8 @@
     return false;
   }
 
-  bool WriteJavaFile(ResourceTable* table, const StringPiece& package_name_to_generate,
-                     const StringPiece& out_package, const JavaClassGeneratorOptions& java_options,
+  bool WriteJavaFile(ResourceTable* table, StringPiece package_name_to_generate,
+                     StringPiece out_package, const JavaClassGeneratorOptions& java_options,
                      const std::optional<std::string>& out_text_symbols_path = {}) {
     if (!options_.generate_java_class_path && !out_text_symbols_path) {
       return true;
@@ -2473,14 +2472,14 @@
   for (std::string& extra_package : extra_java_packages_) {
     // A given package can actually be a colon separated list of packages.
     for (StringPiece package : util::Split(extra_package, ':')) {
-      options_.extra_java_packages.insert(package.to_string());
+      options_.extra_java_packages.emplace(package);
     }
   }
 
   if (product_list_) {
     for (StringPiece product : util::Tokenize(product_list_.value(), ',')) {
       if (product != "" && product != "default") {
-        options_.products.insert(product.to_string());
+        options_.products.emplace(product);
       }
     }
   }
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 042926c..d7a39bf 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -154,13 +154,22 @@
       return 1;
     }
 
-    if (options_.shorten_resource_paths) {
-      Obfuscator obfuscator(options_.table_flattener_options.shortened_path_map);
+    Obfuscator obfuscator(options_);
+    if (obfuscator.IsEnabled()) {
       if (!obfuscator.Consume(context_, apk->GetResourceTable())) {
         context_->GetDiagnostics()->Error(android::DiagMessage()
                                           << "failed shortening resource paths");
         return 1;
       }
+
+      if (options_.obfuscation_map_path &&
+          !obfuscator.WriteObfuscationMap(options_.obfuscation_map_path.value())) {
+        context_->GetDiagnostics()->Error(android::DiagMessage()
+                                          << "failed to write the obfuscation map to file");
+        return 1;
+      }
+
+      // TODO(b/246489170): keep the old option and format until transform to the new one
       if (options_.shortened_paths_map_path
           && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map,
                                       options_.shortened_paths_map_path.value())) {
@@ -292,6 +301,7 @@
                                         ArchiveEntry::kAlign, writer);
   }
 
+  // TODO(b/246489170): keep the old option and format until transform to the new one
   bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map,
                                const std::string &file_path) {
     std::stringstream ss;
@@ -370,8 +380,8 @@
 
     if (!kept_artifacts_.empty()) {
       for (const std::string& artifact_str : kept_artifacts_) {
-        for (const StringPiece& artifact : util::Tokenize(artifact_str, ',')) {
-          options_.kept_artifacts.insert(artifact.to_string());
+        for (StringPiece artifact : util::Tokenize(artifact_str, ',')) {
+          options_.kept_artifacts.emplace(artifact);
         }
       }
     }
@@ -403,7 +413,7 @@
 
   if (target_densities_) {
     // Parse the target screen densities.
-    for (const StringPiece& config_str : util::Tokenize(target_densities_.value(), ',')) {
+    for (StringPiece config_str : util::Tokenize(target_densities_.value(), ',')) {
       std::optional<uint16_t> target_density = ParseTargetDensityParameter(config_str, diag);
       if (!target_density) {
         return 1;
diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h
index 794a87b..1879f25 100644
--- a/tools/aapt2/cmd/Optimize.h
+++ b/tools/aapt2/cmd/Optimize.h
@@ -58,6 +58,7 @@
   bool shorten_resource_paths = false;
 
   // Path to the output map of original resource paths to shortened paths.
+  // TODO(b/246489170): keep the old option and format until transform to the new one
   std::optional<std::string> shortened_paths_map_path;
 
   // Whether sparse encoding should be used for O+ resources.
@@ -65,6 +66,9 @@
 
   // Whether sparse encoding should be used for all resources.
   bool force_sparse_encoding = false;
+
+  // Path to the output map of original resource paths/names to obfuscated paths/names.
+  std::optional<std::string> obfuscation_map_path;
 };
 
 class OptimizeCommand : public Command {
@@ -120,9 +124,13 @@
     AddOptionalSwitch("--shorten-resource-paths",
         "Shortens the paths of resources inside the APK.",
         &options_.shorten_resource_paths);
+    // TODO(b/246489170): keep the old option and format until transform to the new one
     AddOptionalFlag("--resource-path-shortening-map",
-        "Path to output the map of old resource paths to shortened paths.",
-        &options_.shortened_paths_map_path);
+                    "[Deprecated]Path to output the map of old resource paths to shortened paths.",
+                    &options_.shortened_paths_map_path);
+    AddOptionalFlag("--save-obfuscation-map",
+                    "Path to output the map of original paths/names to obfuscated paths/names.",
+                    &options_.obfuscation_map_path);
     AddOptionalSwitch(
         "--deduplicate-entry-values",
         "Whether to deduplicate pairs of resource entry and value for simple resources.\n"
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 56e2f52..92849cf 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -34,8 +34,7 @@
 
 namespace aapt {
 
-std::optional<uint16_t> ParseTargetDensityParameter(const StringPiece& arg,
-                                                    android::IDiagnostics* diag) {
+std::optional<uint16_t> ParseTargetDensityParameter(StringPiece arg, android::IDiagnostics* diag) {
   ConfigDescription preferred_density_config;
   if (!ConfigDescription::Parse(arg, &preferred_density_config)) {
     diag->Error(android::DiagMessage()
@@ -55,7 +54,7 @@
   return preferred_density_config.density;
 }
 
-bool ParseSplitParameter(const StringPiece& arg, android::IDiagnostics* diag, std::string* out_path,
+bool ParseSplitParameter(StringPiece arg, android::IDiagnostics* diag, std::string* out_path,
                          SplitConstraints* out_split) {
   CHECK(diag != nullptr);
   CHECK(out_path != nullptr);
@@ -77,7 +76,7 @@
 
   *out_path = parts[0];
   out_split->name = parts[1];
-  for (const StringPiece& config_str : util::Tokenize(parts[1], ',')) {
+  for (StringPiece config_str : util::Tokenize(parts[1], ',')) {
     ConfigDescription config;
     if (!ConfigDescription::Parse(config_str, &config)) {
       diag->Error(android::DiagMessage()
@@ -93,7 +92,7 @@
                                                            android::IDiagnostics* diag) {
   std::unique_ptr<AxisConfigFilter> filter = util::make_unique<AxisConfigFilter>();
   for (const std::string& config_arg : args) {
-    for (const StringPiece& config_str : util::Tokenize(config_arg, ',')) {
+    for (StringPiece config_str : util::Tokenize(config_arg, ',')) {
       ConfigDescription config;
       LocaleValue lv;
       if (lv.InitFromFilterString(config_str)) {
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index 3d4ca24..169d5f9 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -34,13 +34,13 @@
 
 // Parses a configuration density (ex. hdpi, xxhdpi, 234dpi, anydpi, etc).
 // Returns Nothing and logs a human friendly error message if the string was not legal.
-std::optional<uint16_t> ParseTargetDensityParameter(const android::StringPiece& arg,
+std::optional<uint16_t> ParseTargetDensityParameter(android::StringPiece arg,
                                                     android::IDiagnostics* diag);
 
 // Parses a string of the form 'path/to/output.apk:<config>[,<config>...]' and fills in
 // `out_path` with the path and `out_split` with the set of ConfigDescriptions.
 // Returns false and logs a human friendly error message if the string was not legal.
-bool ParseSplitParameter(const android::StringPiece& arg, android::IDiagnostics* diag,
+bool ParseSplitParameter(android::StringPiece arg, android::IDiagnostics* diag,
                          std::string* out_path, SplitConstraints* out_split);
 
 // Parses a set of config filter strings of the form 'en,fr-rFR' and returns an IConfigFilter.
diff --git a/tools/aapt2/compile/NinePatch.cpp b/tools/aapt2/compile/NinePatch.cpp
index c931da4..4538ecc 100644
--- a/tools/aapt2/compile/NinePatch.cpp
+++ b/tools/aapt2/compile/NinePatch.cpp
@@ -218,11 +218,9 @@
 
 static bool PopulateBounds(const std::vector<Range>& padding,
                            const std::vector<Range>& layout_bounds,
-                           const std::vector<Range>& stretch_regions,
-                           const int32_t length, int32_t* padding_start,
-                           int32_t* padding_end, int32_t* layout_start,
-                           int32_t* layout_end, const StringPiece& edge_name,
-                           std::string* out_err) {
+                           const std::vector<Range>& stretch_regions, const int32_t length,
+                           int32_t* padding_start, int32_t* padding_end, int32_t* layout_start,
+                           int32_t* layout_end, StringPiece edge_name, std::string* out_err) {
   if (padding.size() > 1) {
     std::stringstream err_stream;
     err_stream << "too many padding sections on " << edge_name << " border";
diff --git a/tools/aapt2/compile/Png.h b/tools/aapt2/compile/Png.h
index 7f8d923..a8b7dd1 100644
--- a/tools/aapt2/compile/Png.h
+++ b/tools/aapt2/compile/Png.h
@@ -59,7 +59,7 @@
  */
 class PngChunkFilter : public io::InputStream {
  public:
-  explicit PngChunkFilter(const android::StringPiece& data);
+  explicit PngChunkFilter(android::StringPiece data);
   virtual ~PngChunkFilter() = default;
 
   bool Next(const void** buffer, size_t* len) override;
diff --git a/tools/aapt2/compile/PngChunkFilter.cpp b/tools/aapt2/compile/PngChunkFilter.cpp
index 4db2392..2e55d0c 100644
--- a/tools/aapt2/compile/PngChunkFilter.cpp
+++ b/tools/aapt2/compile/PngChunkFilter.cpp
@@ -70,7 +70,7 @@
   }
 }
 
-PngChunkFilter::PngChunkFilter(const StringPiece& data) : data_(data) {
+PngChunkFilter::PngChunkFilter(StringPiece data) : data_(data) {
   if (util::StartsWith(data_, kPngSignature)) {
     window_start_ = 0;
     window_end_ = kPngSignatureSize;
diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp
index 3a515fa..463ce78 100644
--- a/tools/aapt2/compile/Pseudolocalizer.cpp
+++ b/tools/aapt2/compile/Pseudolocalizer.cpp
@@ -20,36 +20,42 @@
 
 using android::StringPiece;
 
+using namespace std::literals;
+
 namespace aapt {
 
 // String basis to generate expansion
-static const std::string kExpansionString =
+static constexpr auto kExpansionString =
     "one two three "
     "four five six seven eight nine ten eleven twelve thirteen "
-    "fourteen fiveteen sixteen seventeen nineteen twenty";
+    "fourteen fiveteen sixteen seventeen nineteen twenty"sv;
 
 // Special unicode characters to override directionality of the words
-static const std::string kRlm = "\u200f";
-static const std::string kRlo = "\u202e";
-static const std::string kPdf = "\u202c";
+static constexpr auto kRlm = "\u200f"sv;
+static constexpr auto kRlo = "\u202e"sv;
+static constexpr auto kPdf = "\u202c"sv;
 
 // Placeholder marks
-static const std::string kPlaceholderOpen = "\u00bb";
-static const std::string kPlaceholderClose = "\u00ab";
+static constexpr auto kPlaceholderOpen = "\u00bb"sv;
+static constexpr auto kPlaceholderClose = "\u00ab"sv;
 
 static const char kArgStart = '{';
 static const char kArgEnd = '}';
 
 class PseudoMethodNone : public PseudoMethodImpl {
  public:
-  std::string Text(const StringPiece& text) override { return text.to_string(); }
-  std::string Placeholder(const StringPiece& text) override { return text.to_string(); }
+  std::string Text(StringPiece text) override {
+    return std::string(text);
+  }
+  std::string Placeholder(StringPiece text) override {
+    return std::string(text);
+  }
 };
 
 class PseudoMethodBidi : public PseudoMethodImpl {
  public:
-  std::string Text(const StringPiece& text) override;
-  std::string Placeholder(const StringPiece& text) override;
+  std::string Text(StringPiece text) override;
+  std::string Placeholder(StringPiece text) override;
 };
 
 class PseudoMethodAccent : public PseudoMethodImpl {
@@ -57,8 +63,8 @@
   PseudoMethodAccent() : depth_(0), word_count_(0), length_(0) {}
   std::string Start() override;
   std::string End() override;
-  std::string Text(const StringPiece& text) override;
-  std::string Placeholder(const StringPiece& text) override;
+  std::string Text(StringPiece text) override;
+  std::string Placeholder(StringPiece text) override;
 
  private:
   size_t depth_;
@@ -84,7 +90,7 @@
   }
 }
 
-std::string Pseudolocalizer::Text(const StringPiece& text) {
+std::string Pseudolocalizer::Text(StringPiece text) {
   std::string out;
   size_t depth = last_depth_;
   size_t lastpos, pos;
@@ -116,7 +122,7 @@
       }
       size_t size = nextpos - lastpos;
       if (size) {
-        std::string chunk = text.substr(lastpos, size).to_string();
+        std::string chunk(text.substr(lastpos, size));
         if (pseudo) {
           chunk = impl_->Text(chunk);
         } else if (str[lastpos] == kArgStart && str[nextpos - 1] == kArgEnd) {
@@ -301,21 +307,23 @@
 }
 
 static std::string PseudoGenerateExpansion(const unsigned int length) {
-  std::string result = kExpansionString;
-  const char* s = result.data();
+  std::string result(kExpansionString);
   if (result.size() < length) {
     result += " ";
     result += PseudoGenerateExpansion(length - result.size());
   } else {
     int ext = 0;
     // Should contain only whole words, so looking for a space
-    for (unsigned int i = length + 1; i < result.size(); ++i) {
-      ++ext;
-      if (s[i] == ' ') {
-        break;
+    {
+      const char* const s = result.data();
+      for (unsigned int i = length + 1; i < result.size(); ++i) {
+        ++ext;
+        if (s[i] == ' ') {
+          break;
+        }
       }
     }
-    result = result.substr(0, length + ext);
+    result.resize(length + ext);
   }
   return result;
 }
@@ -349,7 +357,7 @@
  *
  * Note: This leaves placeholder syntax untouched.
  */
-std::string PseudoMethodAccent::Text(const StringPiece& source) {
+std::string PseudoMethodAccent::Text(StringPiece source) {
   const char* s = source.data();
   std::string result;
   const size_t I = source.size();
@@ -435,12 +443,12 @@
   return result;
 }
 
-std::string PseudoMethodAccent::Placeholder(const StringPiece& source) {
+std::string PseudoMethodAccent::Placeholder(StringPiece source) {
   // Surround a placeholder with brackets
-  return kPlaceholderOpen + source.to_string() + kPlaceholderClose;
+  return (std::string(kPlaceholderOpen) += source) += kPlaceholderClose;
 }
 
-std::string PseudoMethodBidi::Text(const StringPiece& source) {
+std::string PseudoMethodBidi::Text(StringPiece source) {
   const char* s = source.data();
   std::string result;
   bool lastspace = true;
@@ -456,10 +464,10 @@
     space = (!escape && isspace(c)) || (escape && (c == 'n' || c == 't'));
     if (lastspace && !space) {
       // Word start
-      result += kRlm + kRlo;
+      (result += kRlm) += kRlo;
     } else if (!lastspace && space) {
       // Word end
-      result += kPdf + kRlm;
+      (result += kPdf) += kRlm;
     }
     lastspace = space;
     if (escape) {
@@ -470,14 +478,14 @@
   }
   if (!lastspace) {
     // End of last word
-    result += kPdf + kRlm;
+    (result += kPdf) += kRlm;
   }
   return result;
 }
 
-std::string PseudoMethodBidi::Placeholder(const StringPiece& source) {
+std::string PseudoMethodBidi::Placeholder(StringPiece source) {
   // Surround a placeholder with directionality change sequence
-  return kRlm + kRlo + source.to_string() + kPdf + kRlm;
+  return (((std::string(kRlm) += kRlo) += source) += kPdf) += kRlm;
 }
 
 }  // namespace aapt
diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h
index 4dedc70..2b94bcc 100644
--- a/tools/aapt2/compile/Pseudolocalizer.h
+++ b/tools/aapt2/compile/Pseudolocalizer.h
@@ -31,8 +31,8 @@
   virtual ~PseudoMethodImpl() {}
   virtual std::string Start() { return {}; }
   virtual std::string End() { return {}; }
-  virtual std::string Text(const android::StringPiece& text) = 0;
-  virtual std::string Placeholder(const android::StringPiece& text) = 0;
+  virtual std::string Text(android::StringPiece text) = 0;
+  virtual std::string Placeholder(android::StringPiece text) = 0;
 };
 
 class Pseudolocalizer {
@@ -47,7 +47,7 @@
   void SetMethod(Method method);
   std::string Start() { return impl_->Start(); }
   std::string End() { return impl_->End(); }
-  std::string Text(const android::StringPiece& text);
+  std::string Text(android::StringPiece text);
 
  private:
   std::unique_ptr<PseudoMethodImpl> impl_;
diff --git a/tools/aapt2/configuration/ConfigurationParser.cpp b/tools/aapt2/configuration/ConfigurationParser.cpp
index 6bba11e..1b03253 100644
--- a/tools/aapt2/configuration/ConfigurationParser.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser.cpp
@@ -152,7 +152,7 @@
  * success, or false if the either the placeholder is not found in the name, or the value is not
  * present and the placeholder was.
  */
-bool ReplacePlaceholder(const StringPiece& placeholder, const std::optional<StringPiece>& value,
+bool ReplacePlaceholder(StringPiece placeholder, const std::optional<StringPiece>& value,
                         std::string* name, android::IDiagnostics* diag) {
   size_t offset = name->find(placeholder.data());
   bool found = (offset != std::string::npos);
@@ -338,17 +338,17 @@
   return {config};
 }
 
-const StringPiece& AbiToString(Abi abi) {
+StringPiece AbiToString(Abi abi) {
   return kAbiToStringMap.at(static_cast<size_t>(abi));
 }
 
 /**
  * Returns the common artifact base name from a template string.
  */
-std::optional<std::string> ToBaseName(std::string result, const StringPiece& apk_name,
+std::optional<std::string> ToBaseName(std::string result, StringPiece apk_name,
                                       android::IDiagnostics* diag) {
   const StringPiece ext = file::GetExtension(apk_name);
-  size_t end_index = apk_name.to_string().rfind(ext.to_string());
+  size_t end_index = apk_name.rfind(ext);
   const std::string base_name =
       (end_index != std::string::npos) ? std::string{apk_name.begin(), end_index} : "";
 
@@ -371,17 +371,17 @@
     // If no extension is specified, and the name template does not end in the current extension,
     // add the existing extension.
     if (!util::EndsWith(result, ext)) {
-      result.append(ext.to_string());
+      result.append(ext);
     }
   }
 
   return result;
 }
 
-std::optional<std::string> ConfiguredArtifact::ToArtifactName(const StringPiece& format,
-                                                              const StringPiece& apk_name,
+std::optional<std::string> ConfiguredArtifact::ToArtifactName(StringPiece format,
+                                                              StringPiece apk_name,
                                                               android::IDiagnostics* diag) const {
-  std::optional<std::string> base = ToBaseName(format.to_string(), apk_name, diag);
+  std::optional<std::string> base = ToBaseName(std::string(format), apk_name, diag);
   if (!base) {
     return {};
   }
@@ -414,7 +414,7 @@
   return result;
 }
 
-std::optional<std::string> ConfiguredArtifact::Name(const StringPiece& apk_name,
+std::optional<std::string> ConfiguredArtifact::Name(StringPiece apk_name,
                                                     android::IDiagnostics* diag) const {
   if (!name) {
     return {};
@@ -439,7 +439,7 @@
 }
 
 std::optional<std::vector<OutputArtifact>> ConfigurationParser::Parse(
-    const android::StringPiece& apk_path) {
+    android::StringPiece apk_path) {
   std::optional<PostProcessingConfiguration> maybe_config =
       ExtractConfiguration(contents_, config_path_, diag_);
   if (!maybe_config) {
@@ -447,7 +447,7 @@
   }
 
   // Convert from a parsed configuration to a list of artifacts for processing.
-  const std::string& apk_name = file::GetFilename(apk_path).to_string();
+  const std::string apk_name(file::GetFilename(apk_path));
   std::vector<OutputArtifact> output_artifacts;
 
   PostProcessingConfiguration& config = maybe_config.value();
@@ -519,7 +519,7 @@
   for (auto& node : root_element->children) {
     xml::Text* t;
     if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
-      config->artifact_format = TrimWhitespace(t->text).to_string();
+      config->artifact_format.emplace(TrimWhitespace(t->text));
       break;
     }
   }
@@ -561,7 +561,7 @@
       for (auto& node : child->children) {
         xml::Text* t;
         if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
-          auto abi = kStringToAbiMap.find(TrimWhitespace(t->text).to_string());
+          auto abi = kStringToAbiMap.find(TrimWhitespace(t->text));
           if (abi != kStringToAbiMap.end()) {
             group.push_back(abi->second);
           } else {
@@ -622,7 +622,7 @@
         xml::Text* t;
         if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
           ConfigDescription config_descriptor;
-          const android::StringPiece& text = TrimWhitespace(t->text);
+          android::StringPiece text = TrimWhitespace(t->text);
           bool parsed = ConfigDescription::Parse(text, &config_descriptor);
           if (parsed &&
               (config_descriptor.CopyWithoutSdkVersion().diff(ConfigDescription::DefaultConfig()) ==
@@ -688,7 +688,7 @@
         xml::Text* t;
         if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
           ConfigDescription config_descriptor;
-          const android::StringPiece& text = TrimWhitespace(t->text);
+          android::StringPiece text = TrimWhitespace(t->text);
           bool parsed = ConfigDescription::Parse(text, &config_descriptor);
           if (parsed &&
               (config_descriptor.CopyWithoutSdkVersion().diff(ConfigDescription::DefaultConfig()) ==
@@ -806,7 +806,7 @@
         for (auto& node : element->children) {
           xml::Text* t;
           if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
-            result.texture_paths.push_back(TrimWhitespace(t->text).to_string());
+            result.texture_paths.emplace_back(TrimWhitespace(t->text));
           }
         }
       }
@@ -843,7 +843,7 @@
       for (auto& node : child->children) {
         xml::Text* t;
         if ((t = NodeCast<xml::Text>(node.get())) != nullptr) {
-          group.push_back(TrimWhitespace(t->text).to_string());
+          group.emplace_back(TrimWhitespace(t->text));
           break;
         }
       }
diff --git a/tools/aapt2/configuration/ConfigurationParser.h b/tools/aapt2/configuration/ConfigurationParser.h
index 2c8221d..d66f4ab 100644
--- a/tools/aapt2/configuration/ConfigurationParser.h
+++ b/tools/aapt2/configuration/ConfigurationParser.h
@@ -43,7 +43,7 @@
 };
 
 /** Helper method to convert an ABI to a string representing the path within the APK. */
-const android::StringPiece& AbiToString(Abi abi);
+android::StringPiece AbiToString(Abi abi);
 
 /**
  * Represents an individual locale. When a locale is included, it must be
@@ -150,8 +150,7 @@
    * Parses the configuration file and returns the results. If the configuration could not be parsed
    * the result is empty and any errors will be displayed with the provided diagnostics context.
    */
-  std::optional<std::vector<configuration::OutputArtifact>> Parse(
-      const android::StringPiece& apk_path);
+  std::optional<std::vector<configuration::OutputArtifact>> Parse(android::StringPiece apk_path);
 
  protected:
   /**
diff --git a/tools/aapt2/configuration/ConfigurationParser.internal.h b/tools/aapt2/configuration/ConfigurationParser.internal.h
index 3028c3f..198f730 100644
--- a/tools/aapt2/configuration/ConfigurationParser.internal.h
+++ b/tools/aapt2/configuration/ConfigurationParser.internal.h
@@ -138,13 +138,12 @@
   std::optional<std::string> gl_texture_group;
 
   /** Convert an artifact name template into a name string based on configuration contents. */
-  std::optional<std::string> ToArtifactName(const android::StringPiece& format,
-                                            const android::StringPiece& apk_name,
+  std::optional<std::string> ToArtifactName(android::StringPiece format,
+                                            android::StringPiece apk_name,
                                             android::IDiagnostics* diag) const;
 
   /** Convert an artifact name template into a name string based on configuration contents. */
-  std::optional<std::string> Name(const android::StringPiece& apk_name,
-                                  android::IDiagnostics* diag) const;
+  std::optional<std::string> Name(android::StringPiece apk_name, android::IDiagnostics* diag) const;
 };
 
 /** AAPT2 XML configuration file binary representation. */
diff --git a/tools/aapt2/dump/DumpManifest.cpp b/tools/aapt2/dump/DumpManifest.cpp
index c4c002d..d60869a 100644
--- a/tools/aapt2/dump/DumpManifest.cpp
+++ b/tools/aapt2/dump/DumpManifest.cpp
@@ -1076,7 +1076,7 @@
 
   /** Adds a feature to the feature group. */
   void AddFeature(const std::string& name, bool required = true, int32_t version = -1) {
-    features_.insert(std::make_pair(name, Feature{ required, version }));
+    features_.insert_or_assign(name, Feature{required, version});
     if (required) {
       if (name == "android.hardware.camera.autofocus" ||
           name == "android.hardware.camera.flash") {
@@ -1348,6 +1348,11 @@
   std::string impliedReason;
 
   void Extract(xml::Element* element) override {
+    const auto parent_stack = extractor()->parent_stack();
+    if (!extractor()->options_.only_permissions &&
+        (parent_stack.size() != 1 || !ElementCast<Manifest>(parent_stack[0]))) {
+      return;
+    }
     name = GetAttributeStringDefault(FindAttribute(element, NAME_ATTR), "");
     std::string feature =
         GetAttributeStringDefault(FindAttribute(element, REQUIRED_FEATURE_ATTR), "");
@@ -1472,6 +1477,11 @@
   const int32_t* maxSdkVersion = nullptr;
 
   void Extract(xml::Element* element) override {
+    const auto parent_stack = extractor()->parent_stack();
+    if (!extractor()->options_.only_permissions &&
+        (parent_stack.size() != 1 || !ElementCast<Manifest>(parent_stack[0]))) {
+      return;
+    }
     name = GetAttributeString(FindAttribute(element, NAME_ATTR));
     maxSdkVersion = GetAttributeInteger(FindAttribute(element, MAX_SDK_VERSION_ATTR));
 
diff --git a/tools/aapt2/filter/AbiFilter.cpp b/tools/aapt2/filter/AbiFilter.cpp
index 9ace82a..908b171 100644
--- a/tools/aapt2/filter/AbiFilter.cpp
+++ b/tools/aapt2/filter/AbiFilter.cpp
@@ -23,15 +23,15 @@
 namespace aapt {
 
 std::unique_ptr<AbiFilter> AbiFilter::FromAbiList(const std::vector<configuration::Abi>& abi_list) {
-  std::unordered_set<std::string> abi_set;
+  std::unordered_set<std::string_view> abi_set;
   for (auto& abi : abi_list) {
-    abi_set.insert(configuration::AbiToString(abi).to_string());
+    abi_set.insert(configuration::AbiToString(abi));
   }
   // Make unique by hand as the constructor is private.
-  return std::unique_ptr<AbiFilter>(new AbiFilter(abi_set));
+  return std::unique_ptr<AbiFilter>(new AbiFilter(std::move(abi_set)));
 }
 
-bool AbiFilter::Keep(const std::string& path) {
+bool AbiFilter::Keep(std::string_view path) {
   // We only care about libraries.
   if (!util::StartsWith(path, kLibPrefix)) {
     return true;
@@ -44,7 +44,7 @@
   }
 
   // Strip the lib/ prefix.
-  const std::string& path_abi = path.substr(kLibPrefixLen, abi_end - kLibPrefixLen);
+  const auto path_abi = path.substr(kLibPrefixLen, abi_end - kLibPrefixLen);
   return (abis_.find(path_abi) != abis_.end());
 }
 
diff --git a/tools/aapt2/filter/AbiFilter.h b/tools/aapt2/filter/AbiFilter.h
index 2832711..7380f3f 100644
--- a/tools/aapt2/filter/AbiFilter.h
+++ b/tools/aapt2/filter/AbiFilter.h
@@ -18,7 +18,7 @@
 #define AAPT2_ABISPLITTER_H
 
 #include <memory>
-#include <string>
+#include <string_view>
 #include <unordered_set>
 #include <vector>
 
@@ -39,16 +39,16 @@
   static std::unique_ptr<AbiFilter> FromAbiList(const std::vector<configuration::Abi>& abi_list);
 
   /** Returns true if the path is for a native library in the list of desired ABIs. */
-  bool Keep(const std::string& path) override;
+  bool Keep(std::string_view path) override;
 
  private:
-  explicit AbiFilter(std::unordered_set<std::string> abis) : abis_(std::move(abis)) {
+  explicit AbiFilter(std::unordered_set<std::string_view> abis) : abis_(std::move(abis)) {
   }
 
   /** The path prefix to where all native libs end up inside an APK file. */
   static constexpr const char* kLibPrefix = "lib/";
   static constexpr size_t kLibPrefixLen = 4;
-  const std::unordered_set<std::string> abis_;
+  const std::unordered_set<std::string_view> abis_;
 };
 
 }  // namespace aapt
diff --git a/tools/aapt2/filter/Filter.h b/tools/aapt2/filter/Filter.h
index f932f9c..baf4791 100644
--- a/tools/aapt2/filter/Filter.h
+++ b/tools/aapt2/filter/Filter.h
@@ -18,6 +18,7 @@
 #define AAPT2_FILTER_H
 
 #include <string>
+#include <string_view>
 #include <vector>
 
 #include "util/Util.h"
@@ -30,7 +31,7 @@
   virtual ~IPathFilter() = default;
 
   /** Returns true if the path should be kept. */
-  virtual bool Keep(const std::string& path) = 0;
+  virtual bool Keep(std::string_view path) = 0;
 };
 
 /**
@@ -42,7 +43,7 @@
   }
 
   /** Returns true if the provided path matches the prefix. */
-  bool Keep(const std::string& path) override {
+  bool Keep(std::string_view path) override {
     return util::StartsWith(path, prefix_);
   }
 
@@ -59,7 +60,7 @@
   }
 
   /** Returns true if all filters keep the path. */
-  bool Keep(const std::string& path) override {
+  bool Keep(std::string_view path) override {
     for (auto& filter : filters_) {
       if (!filter->Keep(path)) {
         return false;
diff --git a/tools/aapt2/format/Archive.cpp b/tools/aapt2/format/Archive.cpp
index 80c1618..e9a93d8 100644
--- a/tools/aapt2/format/Archive.cpp
+++ b/tools/aapt2/format/Archive.cpp
@@ -40,8 +40,8 @@
  public:
   DirectoryWriter() = default;
 
-  bool Open(const StringPiece& out_dir) {
-    dir_ = out_dir.to_string();
+  bool Open(StringPiece out_dir) {
+    dir_ = std::string(out_dir);
     file::FileType type = file::GetFileType(dir_);
     if (type == file::FileType::kNonExistant) {
       error_ = "directory does not exist";
@@ -53,14 +53,14 @@
     return true;
   }
 
-  bool StartEntry(const StringPiece& path, uint32_t flags) override {
+  bool StartEntry(StringPiece path, uint32_t flags) override {
     if (file_) {
       return false;
     }
 
     std::string full_path = dir_;
     file::AppendPath(&full_path, path);
-    file::mkdirs(file::GetStem(full_path).to_string());
+    file::mkdirs(std::string(file::GetStem(full_path)));
 
     file_ = {::android::base::utf8::fopen(full_path.c_str(), "wb"), fclose};
     if (!file_) {
@@ -91,7 +91,7 @@
     return true;
   }
 
-  bool WriteFile(const StringPiece& path, uint32_t flags, io::InputStream* in) override {
+  bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
     if (!StartEntry(path, flags)) {
       return false;
     }
@@ -132,8 +132,8 @@
  public:
   ZipFileWriter() = default;
 
-  bool Open(const StringPiece& path) {
-    file_ = {::android::base::utf8::fopen(path.to_string().c_str(), "w+b"), fclose};
+  bool Open(StringPiece path) {
+    file_ = {::android::base::utf8::fopen(path.data(), "w+b"), fclose};
     if (!file_) {
       error_ = SystemErrorCodeToString(errno);
       return false;
@@ -142,7 +142,7 @@
     return true;
   }
 
-  bool StartEntry(const StringPiece& path, uint32_t flags) override {
+  bool StartEntry(StringPiece path, uint32_t flags) override {
     if (!writer_) {
       return false;
     }
@@ -182,7 +182,7 @@
     return true;
   }
 
-  bool WriteFile(const StringPiece& path, uint32_t flags, io::InputStream* in) override {
+  bool WriteFile(StringPiece path, uint32_t flags, io::InputStream* in) override {
     while (true) {
       if (!StartEntry(path, flags)) {
         return false;
@@ -257,7 +257,7 @@
 }  // namespace
 
 std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
-                                                             const StringPiece& path) {
+                                                             StringPiece path) {
   std::unique_ptr<DirectoryWriter> writer = util::make_unique<DirectoryWriter>();
   if (!writer->Open(path)) {
     diag->Error(android::DiagMessage(path) << writer->GetError());
@@ -267,7 +267,7 @@
 }
 
 std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
-                                                           const StringPiece& path) {
+                                                           StringPiece path) {
   std::unique_ptr<ZipFileWriter> writer = util::make_unique<ZipFileWriter>();
   if (!writer->Open(path)) {
     diag->Error(android::DiagMessage(path) << writer->GetError());
diff --git a/tools/aapt2/format/Archive.h b/tools/aapt2/format/Archive.h
index 55b0b2f..6cde753 100644
--- a/tools/aapt2/format/Archive.h
+++ b/tools/aapt2/format/Archive.h
@@ -46,12 +46,12 @@
  public:
   virtual ~IArchiveWriter() = default;
 
-  virtual bool WriteFile(const android::StringPiece& path, uint32_t flags, io::InputStream* in) = 0;
+  virtual bool WriteFile(android::StringPiece path, uint32_t flags, io::InputStream* in) = 0;
 
   // Starts a new entry and allows caller to write bytes to it sequentially.
   // Only use StartEntry if code you do not control needs to write to a CopyingOutputStream.
   // Prefer WriteFile instead of manually calling StartEntry/FinishEntry.
-  virtual bool StartEntry(const android::StringPiece& path, uint32_t flags) = 0;
+  virtual bool StartEntry(android::StringPiece path, uint32_t flags) = 0;
 
   // Called to finish writing an entry previously started by StartEntry.
   // Prefer WriteFile instead of manually calling StartEntry/FinishEntry.
@@ -70,10 +70,10 @@
 };
 
 std::unique_ptr<IArchiveWriter> CreateDirectoryArchiveWriter(android::IDiagnostics* diag,
-                                                             const android::StringPiece& path);
+                                                             android::StringPiece path);
 
 std::unique_ptr<IArchiveWriter> CreateZipFileArchiveWriter(android::IDiagnostics* diag,
-                                                           const android::StringPiece& path);
+                                                           android::StringPiece path);
 
 }  // namespace aapt
 
diff --git a/tools/aapt2/format/Archive_test.cpp b/tools/aapt2/format/Archive_test.cpp
index ceed374..3c44da7 100644
--- a/tools/aapt2/format/Archive_test.cpp
+++ b/tools/aapt2/format/Archive_test.cpp
@@ -50,7 +50,7 @@
 }
 
 std::unique_ptr<IArchiveWriter> MakeZipFileWriter(const std::string& output_path) {
-  file::mkdirs(file::GetStem(output_path).to_string());
+  file::mkdirs(std::string(file::GetStem(output_path)));
   std::remove(output_path.c_str());
 
   StdErrDiagnostics diag;
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 8291862..75dcba5 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -373,7 +373,7 @@
   std::optional<ResourceNamedTypeRef> parsed_type = ParseResourceNamedType(type_str);
   if (!parsed_type) {
     diag_->Warn(android::DiagMessage(source_)
-                << "invalid type name '" << type_str << "' for type with ID " << type->id);
+                << "invalid type name '" << type_str << "' for type with ID " << int(type->id));
     return true;
   }
 
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index f192234..8c594ba 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -32,6 +32,7 @@
 #include "format/binary/ChunkWriter.h"
 #include "format/binary/ResEntryWriter.h"
 #include "format/binary/ResourceTypeExtensions.h"
+#include "optimize/Obfuscator.h"
 #include "trace/TraceBuffer.h"
 
 using namespace android;
@@ -466,9 +467,6 @@
       // table.
       std::map<ConfigDescription, std::vector<FlatEntry>> config_to_entry_list_map;
 
-      // hardcoded string uses characters which make it an invalid resource name
-      const std::string obfuscated_resource_name = "0_resource_name_obfuscated";
-
       for (const ResourceTableEntryView& entry : type.entries) {
         if (entry.staged_id) {
           aliases_.insert(std::make_pair(
@@ -477,30 +475,31 @@
         }
 
         uint32_t local_key_index;
-        ResourceName resource_name({}, type.named_type, entry.name);
-        if (!collapse_key_stringpool_ ||
-            name_collapse_exemptions_.find(resource_name) != name_collapse_exemptions_.end()) {
-          local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
-        } else {
-          // resource isn't exempt from collapse, add it as obfuscated value
-          if (entry.overlayable_item) {
+        auto onObfuscate = [this, &local_key_index, &entry](Obfuscator::Result obfuscatedResult,
+                                                            const ResourceName& resource_name) {
+          if (obfuscatedResult == Obfuscator::Result::Keep_ExemptionList) {
+            local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
+          } else if (obfuscatedResult == Obfuscator::Result::Keep_Overlayable) {
             // if the resource name of the specific entry is obfuscated and this
             // entry is in the overlayable list, the overlay can't work on this
             // overlayable at runtime because the name has been obfuscated in
             // resources.arsc during flatten operation.
             const OverlayableItem& item = entry.overlayable_item.value();
             context_->GetDiagnostics()->Warn(android::DiagMessage(item.overlayable->source)
-                                             << "The resource name of overlayable entry "
-                                             << resource_name.to_string() << "'"
-                                             << " shouldn't be obfuscated in resources.arsc");
+                                             << "The resource name of overlayable entry '"
+                                             << resource_name.to_string()
+                                             << "' shouldn't be obfuscated in resources.arsc");
 
             local_key_index = (uint32_t)key_pool_.MakeRef(entry.name).index();
           } else {
-            // TODO(b/228192695): output the entry.name and Resource id to make
-            //  de-obfuscated possible.
-            local_key_index = (uint32_t)key_pool_.MakeRef(obfuscated_resource_name).index();
+            local_key_index =
+                (uint32_t)key_pool_.MakeRef(Obfuscator::kObfuscatedResourceName).index();
           }
-        }
+        };
+
+        Obfuscator::ObfuscateResourceName(collapse_key_stringpool_, name_collapse_exemptions_,
+                                          type.named_type, entry, onObfuscate);
+
         // Group values by configuration.
         for (auto& config_value : entry.values) {
           config_to_entry_list_map[config_value->config].push_back(
diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h
index 35254ba..60605d2 100644
--- a/tools/aapt2/format/binary/TableFlattener.h
+++ b/tools/aapt2/format/binary/TableFlattener.h
@@ -14,8 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef AAPT_FORMAT_BINARY_TABLEFLATTENER_H
-#define AAPT_FORMAT_BINARY_TABLEFLATTENER_H
+#ifndef TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
+#define TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <unordered_map>
 
 #include "Resource.h"
 #include "ResourceTable.h"
@@ -71,6 +76,9 @@
   //
   // This applies only to simple entries (entry->flags & ResTable_entry::FLAG_COMPLEX == 0).
   bool deduplicate_entry_values = false;
+
+  // Map from original resource ids to obfuscated names.
+  std::unordered_map<uint32_t, std::string> id_resource_map;
 };
 
 class TableFlattener : public IResourceTableConsumer {
@@ -82,12 +90,12 @@
   bool Consume(IAaptContext* context, ResourceTable* table) override;
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(TableFlattener);
-
   TableFlattenerOptions options_;
   android::BigBuffer* buffer_;
+
+  DISALLOW_COPY_AND_ASSIGN(TableFlattener);
 };
 
 }  // namespace aapt
 
-#endif /* AAPT_FORMAT_BINARY_TABLEFLATTENER_H */
+#endif  // TOOLS_AAPT2_FORMAT_BINARY_TABLEFLATTENER_H_
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index d08b4a3..0f11685 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -84,7 +84,7 @@
     return ::testing::AssertionSuccess();
   }
 
-  ::testing::AssertionResult Exists(ResTable* table, const StringPiece& expected_name,
+  ::testing::AssertionResult Exists(ResTable* table, StringPiece expected_name,
                                     const ResourceId& expected_id,
                                     const ConfigDescription& expected_config,
                                     const uint8_t expected_data_type, const uint32_t expected_data,
diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp
index 983e646..05f9751 100644
--- a/tools/aapt2/format/binary/XmlFlattener.cpp
+++ b/tools/aapt2/format/binary/XmlFlattener.cpp
@@ -79,7 +79,7 @@
   }
 
   void Visit(const xml::Text* node) override {
-    std::string text = util::TrimWhitespace(node->text).to_string();
+    std::string text(util::TrimWhitespace(node->text));
 
     // Skip whitespace only text nodes.
     if (text.empty()) {
@@ -88,10 +88,10 @@
 
     // Compact leading and trailing whitespace into a single space
     if (isspace(node->text[0])) {
-      text = ' ' + text;
+      text.insert(text.begin(), ' ');
     }
-    if (isspace(node->text[node->text.length() - 1])) {
-      text = text + ' ';
+    if (isspace(node->text.back())) {
+      text += ' ';
     }
 
     ChunkWriter writer(buffer_);
@@ -165,7 +165,7 @@
   // We are adding strings to a StringPool whose strings will be sorted and merged with other
   // string pools. That means we can't encode the ID of a string directly. Instead, we defer the
   // writing of the ID here, until after the StringPool is merged and sorted.
-  void AddString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest,
+  void AddString(StringPiece str, uint32_t priority, android::ResStringPool_ref* dest,
                  bool treat_empty_string_as_null = false) {
     if (str.empty() && treat_empty_string_as_null) {
       // Some parts of the runtime treat null differently than empty string.
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index a6d58fd..0e40124 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -18,6 +18,7 @@
 
 #include "ValueVisitor.h"
 #include "androidfw/BigBuffer.h"
+#include "optimize/Obfuscator.h"
 
 using android::ConfigDescription;
 
@@ -366,21 +367,21 @@
       }
       pb_type->set_name(type.named_type.to_string());
 
-      // hardcoded string uses characters which make it an invalid resource name
-      static const char* obfuscated_resource_name = "0_resource_name_obfuscated";
       for (const auto& entry : type.entries) {
         pb::Entry* pb_entry = pb_type->add_entry();
         if (entry.id) {
           pb_entry->mutable_entry_id()->set_id(entry.id.value());
         }
-        ResourceName resource_name({}, type.named_type, entry.name);
-        if (options.collapse_key_stringpool &&
-            options.name_collapse_exemptions.find(resource_name) ==
-            options.name_collapse_exemptions.end()) {
-          pb_entry->set_name(obfuscated_resource_name);
-        } else {
-          pb_entry->set_name(entry.name);
-        }
+        auto onObfuscate = [pb_entry, &entry](Obfuscator::Result obfuscatedResult,
+                                              const ResourceName& resource_name) {
+          pb_entry->set_name(obfuscatedResult == Obfuscator::Result::Obfuscated
+                                 ? Obfuscator::kObfuscatedResourceName
+                                 : entry.name);
+        };
+
+        Obfuscator::ObfuscateResourceName(options.collapse_key_stringpool,
+                                          options.name_collapse_exemptions, type.named_type, entry,
+                                          onObfuscate);
 
         // Write the Visibility struct.
         pb::Visibility* pb_visibility = pb_entry->mutable_visibility();
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 5adc5e6..ecfdba8 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -35,7 +35,7 @@
 
 class MockFileCollection : public io::IFileCollection {
  public:
-  MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
+  MOCK_METHOD1(FindFile, io::IFile*(StringPiece path));
   MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
   MOCK_METHOD0(GetDirSeparator, char());
 };
@@ -491,7 +491,7 @@
   EXPECT_THAT(bp->value.data, Eq(ResourceUtils::MakeEmpty()->value.data));
 }
 
-static void ExpectConfigSerializes(const StringPiece& config_str) {
+static void ExpectConfigSerializes(StringPiece config_str) {
   const ConfigDescription expected_config = test::ParseConfigOrDie(config_str);
   pb::Configuration pb_config;
   SerializeConfig(expected_config, &pb_config);
diff --git a/tools/aapt2/io/File.h b/tools/aapt2/io/File.h
index 422658a..08d497d 100644
--- a/tools/aapt2/io/File.h
+++ b/tools/aapt2/io/File.h
@@ -101,7 +101,7 @@
  public:
   virtual ~IFileCollection() = default;
 
-  virtual IFile* FindFile(const android::StringPiece& path) = 0;
+  virtual IFile* FindFile(android::StringPiece path) = 0;
   virtual std::unique_ptr<IFileCollectionIterator> Iterator() = 0;
   virtual char GetDirSeparator() = 0;
 };
diff --git a/tools/aapt2/io/FileSystem.cpp b/tools/aapt2/io/FileSystem.cpp
index 3f071af..a64982a 100644
--- a/tools/aapt2/io/FileSystem.cpp
+++ b/tools/aapt2/io/FileSystem.cpp
@@ -67,8 +67,8 @@
   return result;
 }
 
-std::unique_ptr<FileCollection> FileCollection::Create(const android::StringPiece& root,
-                                                        std::string* outError) {
+std::unique_ptr<FileCollection> FileCollection::Create(android::StringPiece root,
+                                                       std::string* outError) {
   std::unique_ptr<FileCollection> collection =
       std::unique_ptr<FileCollection>(new FileCollection());
 
@@ -80,7 +80,7 @@
 
   std::vector<std::string> sorted_files;
   while (struct dirent *entry = readdir(d.get())) {
-    std::string prefix_path = root.to_string();
+    std::string prefix_path(root);
     file::AppendPath(&prefix_path, entry->d_name);
 
     // The directory to iterate over looking for files
@@ -117,12 +117,19 @@
   return collection;
 }
 
-IFile* FileCollection::InsertFile(const StringPiece& path) {
-  return (files_[path.to_string()] = util::make_unique<RegularFile>(android::Source(path))).get();
+IFile* FileCollection::InsertFile(StringPiece path) {
+  auto file = util::make_unique<RegularFile>(android::Source(path));
+  auto it = files_.lower_bound(path);
+  if (it != files_.end() && it->first == path) {
+    it->second = std::move(file);
+  } else {
+    it = files_.emplace_hint(it, path, std::move(file));
+  }
+  return it->second.get();
 }
 
-IFile* FileCollection::FindFile(const StringPiece& path) {
-  auto iter = files_.find(path.to_string());
+IFile* FileCollection::FindFile(StringPiece path) {
+  auto iter = files_.find(path);
   if (iter != files_.end()) {
     return iter->second.get();
   }
diff --git a/tools/aapt2/io/FileSystem.h b/tools/aapt2/io/FileSystem.h
index bc03b9b..0e798fc 100644
--- a/tools/aapt2/io/FileSystem.h
+++ b/tools/aapt2/io/FileSystem.h
@@ -60,12 +60,11 @@
   FileCollection() = default;
 
   /** Creates a file collection containing all files contained in the specified root directory. */
-  static std::unique_ptr<FileCollection> Create(const android::StringPiece& path,
-                                                std::string* outError);
+  static std::unique_ptr<FileCollection> Create(android::StringPiece path, std::string* outError);
 
   // Adds a file located at path. Returns the IFile representation of that file.
-  IFile* InsertFile(const android::StringPiece& path);
-  IFile* FindFile(const android::StringPiece& path) override;
+  IFile* InsertFile(android::StringPiece path);
+  IFile* FindFile(android::StringPiece path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
   char GetDirSeparator() override;
 
@@ -74,7 +73,7 @@
 
   friend class FileCollectionIterator;
 
-  std::map<std::string, std::unique_ptr<IFile>> files_;
+  std::map<std::string, std::unique_ptr<IFile>, std::less<>> files_;
 };
 
 }  // namespace io
diff --git a/tools/aapt2/io/StringStream.cpp b/tools/aapt2/io/StringStream.cpp
index 4ca04a8..9c49788 100644
--- a/tools/aapt2/io/StringStream.cpp
+++ b/tools/aapt2/io/StringStream.cpp
@@ -21,7 +21,7 @@
 namespace aapt {
 namespace io {
 
-StringInputStream::StringInputStream(const StringPiece& str) : str_(str), offset_(0u) {
+StringInputStream::StringInputStream(StringPiece str) : str_(str), offset_(0u) {
 }
 
 bool StringInputStream::Next(const void** data, size_t* size) {
diff --git a/tools/aapt2/io/StringStream.h b/tools/aapt2/io/StringStream.h
index f29890a..f7bdecca 100644
--- a/tools/aapt2/io/StringStream.h
+++ b/tools/aapt2/io/StringStream.h
@@ -29,7 +29,7 @@
 
 class StringInputStream : public KnownSizeInputStream {
  public:
-  explicit StringInputStream(const android::StringPiece& str);
+  explicit StringInputStream(android::StringPiece str);
 
   bool Next(const void** data, size_t* size) override;
 
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index afe54d4..79d8d52 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -26,7 +26,7 @@
 namespace aapt {
 namespace io {
 
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path,
+bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
                               uint32_t compression_flags, IArchiveWriter* writer) {
   TRACE_CALL();
   if (context->IsVerbose()) {
@@ -43,7 +43,7 @@
   return true;
 }
 
-bool CopyFileToArchive(IAaptContext* context, io::IFile* file, const std::string& out_path,
+bool CopyFileToArchive(IAaptContext* context, io::IFile* file, std::string_view out_path,
                        uint32_t compression_flags, IArchiveWriter* writer) {
   TRACE_CALL();
   std::unique_ptr<io::IData> data = file->OpenAsData();
@@ -56,13 +56,13 @@
 }
 
 bool CopyFileToArchivePreserveCompression(IAaptContext* context, io::IFile* file,
-                                          const std::string& out_path, IArchiveWriter* writer) {
+                                          std::string_view out_path, IArchiveWriter* writer) {
   uint32_t compression_flags = file->WasCompressed() ? ArchiveEntry::kCompress : 0u;
   return CopyFileToArchive(context, file, out_path, compression_flags, writer);
 }
 
 bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* proto_msg,
-                        const std::string& out_path, uint32_t compression_flags,
+                        std::string_view out_path, uint32_t compression_flags,
                         IArchiveWriter* writer) {
   TRACE_CALL();
   if (context->IsVerbose()) {
@@ -110,7 +110,7 @@
   return !in->HadError();
 }
 
-bool Copy(OutputStream* out, const StringPiece& in) {
+bool Copy(OutputStream* out, StringPiece in) {
   const char* in_buffer = in.data();
   size_t in_len = in.size();
   while (in_len != 0) {
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 1b48a28..685f522 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -17,12 +17,11 @@
 #ifndef AAPT_IO_UTIL_H
 #define AAPT_IO_UTIL_H
 
-#include <string>
-
-#include "google/protobuf/message.h"
-#include "google/protobuf/io/coded_stream.h"
+#include <string_view>
 
 #include "format/Archive.h"
+#include "google/protobuf/io/coded_stream.h"
+#include "google/protobuf/message.h"
 #include "io/File.h"
 #include "io/Io.h"
 #include "process/IResourceTableConsumer.h"
@@ -30,23 +29,23 @@
 namespace aapt {
 namespace io {
 
-bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, const std::string& out_path,
+bool CopyInputStreamToArchive(IAaptContext* context, InputStream* in, std::string_view out_path,
                               uint32_t compression_flags, IArchiveWriter* writer);
 
-bool CopyFileToArchive(IAaptContext* context, IFile* file, const std::string& out_path,
+bool CopyFileToArchive(IAaptContext* context, IFile* file, std::string_view out_path,
                        uint32_t compression_flags, IArchiveWriter* writer);
 
 bool CopyFileToArchivePreserveCompression(IAaptContext* context, IFile* file,
-                                          const std::string& out_path, IArchiveWriter* writer);
+                                          std::string_view out_path, IArchiveWriter* writer);
 
 bool CopyProtoToArchive(IAaptContext* context, ::google::protobuf::Message* proto_msg,
-                        const std::string& out_path, uint32_t compression_flags,
+                        std::string_view out_path, uint32_t compression_flags,
                         IArchiveWriter* writer);
 
 // Copies the data from in to out. Returns false if there was an error.
 // If there was an error, check the individual streams' HadError/GetError methods.
 bool Copy(OutputStream* out, InputStream* in);
-bool Copy(OutputStream* out, const ::android::StringPiece& in);
+bool Copy(OutputStream* out, android::StringPiece in);
 bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
 
 class OutputStreamAdaptor : public io::OutputStream {
diff --git a/tools/aapt2/io/ZipArchive.cpp b/tools/aapt2/io/ZipArchive.cpp
index 400269c..4a5385d 100644
--- a/tools/aapt2/io/ZipArchive.cpp
+++ b/tools/aapt2/io/ZipArchive.cpp
@@ -91,8 +91,8 @@
 
 ZipFileCollection::ZipFileCollection() : handle_(nullptr) {}
 
-std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(
-    const StringPiece& path, std::string* out_error) {
+std::unique_ptr<ZipFileCollection> ZipFileCollection::Create(StringPiece path,
+                                                             std::string* out_error) {
   TRACE_CALL();
   constexpr static const int32_t kEmptyArchive = -6;
 
@@ -130,8 +130,8 @@
       continue;
     }
 
-    std::unique_ptr<IFile> file = util::make_unique<ZipFile>(
-        collection->handle_, zip_data, android::Source(zip_entry_path, path.to_string()));
+    std::unique_ptr<IFile> file = util::make_unique<ZipFile>(collection->handle_, zip_data,
+                                                             android::Source(zip_entry_path, path));
     collection->files_by_name_[zip_entry_path] = file.get();
     collection->files_.push_back(std::move(file));
   }
@@ -144,8 +144,8 @@
   return collection;
 }
 
-IFile* ZipFileCollection::FindFile(const StringPiece& path) {
-  auto iter = files_by_name_.find(path.to_string());
+IFile* ZipFileCollection::FindFile(StringPiece path) {
+  auto iter = files_by_name_.find(path);
   if (iter != files_by_name_.end()) {
     return iter->second;
   }
diff --git a/tools/aapt2/io/ZipArchive.h b/tools/aapt2/io/ZipArchive.h
index 78c9c21..c263aa4 100644
--- a/tools/aapt2/io/ZipArchive.h
+++ b/tools/aapt2/io/ZipArchive.h
@@ -61,10 +61,10 @@
 // An IFileCollection that represents a ZIP archive and the entries within it.
 class ZipFileCollection : public IFileCollection {
  public:
-  static std::unique_ptr<ZipFileCollection> Create(const android::StringPiece& path,
+  static std::unique_ptr<ZipFileCollection> Create(android::StringPiece path,
                                                    std::string* outError);
 
-  io::IFile* FindFile(const android::StringPiece& path) override;
+  io::IFile* FindFile(android::StringPiece path) override;
   std::unique_ptr<IFileCollectionIterator> Iterator() override;
   char GetDirSeparator() override;
 
@@ -76,7 +76,7 @@
 
   ZipArchiveHandle handle_;
   std::vector<std::unique_ptr<IFile>> files_;
-  std::map<std::string, IFile*> files_by_name_;
+  std::map<std::string, IFile*, std::less<>> files_by_name_;
 };
 
 }  // namespace io
diff --git a/tools/aapt2/java/AnnotationProcessor.cpp b/tools/aapt2/java/AnnotationProcessor.cpp
index 482d91a..87da09a 100644
--- a/tools/aapt2/java/AnnotationProcessor.cpp
+++ b/tools/aapt2/java/AnnotationProcessor.cpp
@@ -30,7 +30,7 @@
 
 namespace aapt {
 
-StringPiece AnnotationProcessor::ExtractFirstSentence(const StringPiece& comment) {
+StringPiece AnnotationProcessor::ExtractFirstSentence(StringPiece comment) {
   Utf8Iterator iter(comment);
   while (iter.HasNext()) {
     const char32_t codepoint = iter.Next();
@@ -62,7 +62,7 @@
 }};
 
 void AnnotationProcessor::AppendCommentLine(std::string comment) {
-  static const std::string sDeprecated = "@deprecated";
+  static constexpr std::string_view sDeprecated = "@deprecated";
 
   // Treat deprecated specially, since we don't remove it from the source comment.
   if (comment.find(sDeprecated) != std::string::npos) {
@@ -74,7 +74,7 @@
     if (idx != std::string::npos) {
       // Captures all parameters associated with the specified annotation rule
       // by matching the first pair of parantheses after the rule.
-      std::regex re(rule.doc_str.to_string() + "\\s*\\((.+)\\)");
+      std::regex re(std::string(rule.doc_str) += "\\s*\\((.+)\\)");
       std::smatch match_result;
       const bool is_match = std::regex_search(comment, match_result, re);
       // We currently only capture and preserve parameters for SystemApi.
@@ -97,7 +97,7 @@
 
   // If there was trimming to do, copy the string.
   if (trimmed.size() != comment.size()) {
-    comment = trimmed.to_string();
+    comment = std::string(trimmed);
   }
 
   if (!has_comments_) {
@@ -107,12 +107,12 @@
   comment_ << "\n * " << std::move(comment);
 }
 
-void AnnotationProcessor::AppendComment(const StringPiece& comment) {
+void AnnotationProcessor::AppendComment(StringPiece comment) {
   // We need to process line by line to clean-up whitespace and append prefixes.
   for (StringPiece line : util::Tokenize(comment, '\n')) {
     line = util::TrimWhitespace(line);
     if (!line.empty()) {
-      AppendCommentLine(line.to_string());
+      AppendCommentLine(std::string(line));
     }
   }
 }
@@ -126,7 +126,7 @@
 void AnnotationProcessor::Print(Printer* printer, bool strip_api_annotations) const {
   if (has_comments_) {
     std::string result = comment_.str();
-    for (const StringPiece& line : util::Tokenize(result, '\n')) {
+    for (StringPiece line : util::Tokenize(result, '\n')) {
       printer->Println(line);
     }
     printer->Println(" */");
diff --git a/tools/aapt2/java/AnnotationProcessor.h b/tools/aapt2/java/AnnotationProcessor.h
index f217afb..db3437e 100644
--- a/tools/aapt2/java/AnnotationProcessor.h
+++ b/tools/aapt2/java/AnnotationProcessor.h
@@ -56,11 +56,11 @@
   // Extracts the first sentence of a comment. The algorithm selects the substring starting from
   // the beginning of the string, and ending at the first '.' character that is followed by a
   // whitespace character. If these requirements are not met, the whole string is returned.
-  static android::StringPiece ExtractFirstSentence(const android::StringPiece& comment);
+  static android::StringPiece ExtractFirstSentence(android::StringPiece comment);
 
   // Adds more comments. Resources can have value definitions for various configurations, and
   // each of the definitions may have comments that need to be processed.
-  void AppendComment(const android::StringPiece& comment);
+  void AppendComment(android::StringPiece comment);
 
   void AppendNewLine();
 
diff --git a/tools/aapt2/java/ClassDefinition.cpp b/tools/aapt2/java/ClassDefinition.cpp
index 3163497..98f3bd2 100644
--- a/tools/aapt2/java/ClassDefinition.cpp
+++ b/tools/aapt2/java/ClassDefinition.cpp
@@ -27,8 +27,8 @@
   processor_.Print(printer, strip_api_annotations);
 }
 
-void MethodDefinition::AppendStatement(const StringPiece& statement) {
-  statements_.push_back(statement.to_string());
+void MethodDefinition::AppendStatement(StringPiece statement) {
+  statements_.emplace_back(statement);
 }
 
 void MethodDefinition::Print(bool final, Printer* printer, bool) const {
@@ -110,8 +110,8 @@
     " * should not be modified by hand.\n"
     " */\n\n";
 
-void ClassDefinition::WriteJavaFile(const ClassDefinition* def, const StringPiece& package,
-                                    bool final, bool strip_api_annotations, io::OutputStream* out) {
+void ClassDefinition::WriteJavaFile(const ClassDefinition* def, StringPiece package, bool final,
+                                    bool strip_api_annotations, io::OutputStream* out) {
   Printer printer(out);
   printer.Print(sWarningHeader).Print("package ").Print(package).Println(";");
   printer.Println();
diff --git a/tools/aapt2/java/ClassDefinition.h b/tools/aapt2/java/ClassDefinition.h
index 2acdadb..63c9982 100644
--- a/tools/aapt2/java/ClassDefinition.h
+++ b/tools/aapt2/java/ClassDefinition.h
@@ -59,8 +59,8 @@
 template <typename T>
 class PrimitiveMember : public ClassMember {
  public:
-  PrimitiveMember(const android::StringPiece& name, const T& val, bool staged_api = false)
-      : name_(name.to_string()), val_(val), staged_api_(staged_api) {
+  PrimitiveMember(android::StringPiece name, const T& val, bool staged_api = false)
+      : name_(name), val_(val), staged_api_(staged_api) {
   }
 
   bool empty() const override {
@@ -104,8 +104,8 @@
 template <>
 class PrimitiveMember<std::string> : public ClassMember {
  public:
-  PrimitiveMember(const android::StringPiece& name, const std::string& val, bool staged_api = false)
-      : name_(name.to_string()), val_(val) {
+  PrimitiveMember(android::StringPiece name, const std::string& val, bool staged_api = false)
+      : name_(name), val_(val) {
   }
 
   bool empty() const override {
@@ -141,7 +141,8 @@
 template <typename T, typename StringConverter>
 class PrimitiveArrayMember : public ClassMember {
  public:
-  explicit PrimitiveArrayMember(const android::StringPiece& name) : name_(name.to_string()) {}
+  explicit PrimitiveArrayMember(android::StringPiece name) : name_(name) {
+  }
 
   void AddElement(const T& val) {
     elements_.emplace_back(val);
@@ -209,12 +210,12 @@
 class MethodDefinition : public ClassMember {
  public:
   // Expected method signature example: 'public static void onResourcesLoaded(int p)'.
-  explicit MethodDefinition(const android::StringPiece& signature)
-      : signature_(signature.to_string()) {}
+  explicit MethodDefinition(android::StringPiece signature) : signature_(signature) {
+  }
 
   // Appends a single statement to the method. It should include no newlines or else
   // formatting may be broken.
-  void AppendStatement(const android::StringPiece& statement);
+  void AppendStatement(android::StringPiece statement);
 
   // Not quite the same as a name, but good enough.
   const std::string& GetName() const override {
@@ -239,11 +240,12 @@
 
 class ClassDefinition : public ClassMember {
  public:
-  static void WriteJavaFile(const ClassDefinition* def, const android::StringPiece& package,
-                            bool final, bool strip_api_annotations, io::OutputStream* out);
+  static void WriteJavaFile(const ClassDefinition* def, android::StringPiece package, bool final,
+                            bool strip_api_annotations, io::OutputStream* out);
 
-  ClassDefinition(const android::StringPiece& name, ClassQualifier qualifier, bool createIfEmpty)
-      : name_(name.to_string()), qualifier_(qualifier), create_if_empty_(createIfEmpty) {}
+  ClassDefinition(android::StringPiece name, ClassQualifier qualifier, bool createIfEmpty)
+      : name_(name), qualifier_(qualifier), create_if_empty_(createIfEmpty) {
+  }
 
   enum class Result {
     kAdded,
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index a25ca22..7665d0e 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -57,14 +57,14 @@
     "transient",  "try",          "void",      "volatile",   "while",
     "true",       "false",        "null"};
 
-static bool IsValidSymbol(const StringPiece& symbol) {
+static bool IsValidSymbol(StringPiece symbol) {
   return sJavaIdentifiers.find(symbol) == sJavaIdentifiers.end();
 }
 
 // Java symbols can not contain . or -, but those are valid in a resource name.
 // Replace those with '_'.
-std::string JavaClassGenerator::TransformToFieldName(const StringPiece& symbol) {
-  std::string output = symbol.to_string();
+std::string JavaClassGenerator::TransformToFieldName(StringPiece symbol) {
+  std::string output(symbol);
   for (char& c : output) {
     if (c == '.' || c == '-') {
       c = '_';
@@ -84,7 +84,7 @@
 // Foo_bar
 static std::string TransformNestedAttr(const ResourceNameRef& attr_name,
                                        const std::string& styleable_class_name,
-                                       const StringPiece& package_name_to_generate) {
+                                       StringPiece package_name_to_generate) {
   std::string output = styleable_class_name;
 
   // We may reference IDs from other packages, so prefix the entry name with
@@ -226,16 +226,15 @@
 
 static FieldReference GetRFieldReference(const ResourceName& name,
                                          StringPiece fallback_package_name) {
-  const std::string package_name =
-      name.package.empty() ? fallback_package_name.to_string() : name.package;
+  const std::string_view package_name = name.package.empty() ? fallback_package_name : name.package;
   const std::string entry = JavaClassGenerator::TransformToFieldName(name.entry);
-  return FieldReference(StringPrintf("%s.R.%s.%s", package_name.c_str(),
-                                     name.type.to_string().data(), entry.c_str()));
+  return FieldReference(
+      StringPrintf("%s.R.%s.%s", package_name.data(), name.type.to_string().data(), entry.c_str()));
 }
 
 bool JavaClassGenerator::ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
                                           const Styleable& styleable,
-                                          const StringPiece& package_name_to_generate,
+                                          StringPiece package_name_to_generate,
                                           ClassDefinition* out_class_def,
                                           MethodDefinition* out_rewrite_method,
                                           Printer* r_txt_printer) {
@@ -314,7 +313,8 @@
         return true;
       }
       const StringPiece attr_comment_line = entry.symbol.value().attribute->GetComment();
-      return attr_comment_line.contains("@removed") || attr_comment_line.contains("@hide");
+      return attr_comment_line.find("@removed") != std::string::npos ||
+             attr_comment_line.find("@hide") != std::string::npos;
     });
     documentation_attrs.erase(documentation_remove_iter, documentation_attrs.end());
 
@@ -397,7 +397,7 @@
         comment = styleable_attr.symbol.value().attribute->GetComment();
       }
 
-      if (comment.contains("@removed")) {
+      if (comment.find("@removed") != std::string::npos) {
         // Removed attributes are public but hidden from the documentation, so
         // don't emit them as part of the class documentation.
         continue;
@@ -497,7 +497,7 @@
   }
 
   if (out_rewrite_method != nullptr) {
-    const std::string type_str = name.type.to_string();
+    const auto type_str = name.type.to_string();
     out_rewrite_method->AppendStatement(
         StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | packageIdBits;", type_str.data(),
                      field_name.data(), type_str.data(), field_name.data()));
@@ -505,8 +505,7 @@
 }
 
 std::optional<std::string> JavaClassGenerator::UnmangleResource(
-    const StringPiece& package_name, const StringPiece& package_name_to_generate,
-    const ResourceEntry& entry) {
+    StringPiece package_name, StringPiece package_name_to_generate, const ResourceEntry& entry) {
   if (SkipSymbol(entry.visibility.level)) {
     return {};
   }
@@ -528,7 +527,7 @@
   return {std::move(unmangled_name)};
 }
 
-bool JavaClassGenerator::ProcessType(const StringPiece& package_name_to_generate,
+bool JavaClassGenerator::ProcessType(StringPiece package_name_to_generate,
                                      const ResourceTablePackage& package,
                                      const ResourceTableType& type,
                                      ClassDefinition* out_type_class_def,
@@ -577,7 +576,7 @@
   return true;
 }
 
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate, OutputStream* out,
+bool JavaClassGenerator::Generate(StringPiece package_name_to_generate, OutputStream* out,
                                   OutputStream* out_r_txt) {
   return Generate(package_name_to_generate, package_name_to_generate, out, out_r_txt);
 }
@@ -591,8 +590,8 @@
   }
 }
 
-bool JavaClassGenerator::Generate(const StringPiece& package_name_to_generate,
-                                  const StringPiece& out_package_name, OutputStream* out,
+bool JavaClassGenerator::Generate(StringPiece package_name_to_generate,
+                                  StringPiece out_package_name, OutputStream* out,
                                   OutputStream* out_r_txt) {
   ClassDefinition r_class("R", ClassQualifier::kNone, true);
   std::unique_ptr<MethodDefinition> rewrite_method;
diff --git a/tools/aapt2/java/JavaClassGenerator.h b/tools/aapt2/java/JavaClassGenerator.h
index b45a2f1..234df04 100644
--- a/tools/aapt2/java/JavaClassGenerator.h
+++ b/tools/aapt2/java/JavaClassGenerator.h
@@ -70,16 +70,16 @@
   // All symbols technically belong to a single package, but linked libraries will
   // have their names mangled, denoting that they came from a different package.
   // We need to generate these symbols in a separate file. Returns true on success.
-  bool Generate(const android::StringPiece& package_name_to_generate, io::OutputStream* out,
+  bool Generate(android::StringPiece package_name_to_generate, io::OutputStream* out,
                 io::OutputStream* out_r_txt = nullptr);
 
-  bool Generate(const android::StringPiece& package_name_to_generate,
-                const android::StringPiece& output_package_name, io::OutputStream* out,
+  bool Generate(android::StringPiece package_name_to_generate,
+                android::StringPiece output_package_name, io::OutputStream* out,
                 io::OutputStream* out_r_txt = nullptr);
 
   const std::string& GetError() const;
 
-  static std::string TransformToFieldName(const android::StringPiece& symbol);
+  static std::string TransformToFieldName(android::StringPiece symbol);
 
  private:
   bool SkipSymbol(Visibility::Level state);
@@ -87,11 +87,11 @@
 
   // Returns the unmangled resource entry name if the unmangled package is the same as
   // package_name_to_generate. Returns nothing if the resource should be skipped.
-  std::optional<std::string> UnmangleResource(const android::StringPiece& package_name,
-                                              const android::StringPiece& package_name_to_generate,
+  std::optional<std::string> UnmangleResource(android::StringPiece package_name,
+                                              android::StringPiece package_name_to_generate,
                                               const ResourceEntry& entry);
 
-  bool ProcessType(const android::StringPiece& package_name_to_generate,
+  bool ProcessType(android::StringPiece package_name_to_generate,
                    const ResourceTablePackage& package, const ResourceTableType& type,
                    ClassDefinition* out_type_class_def, MethodDefinition* out_rewrite_method_def,
                    text::Printer* r_txt_printer);
@@ -106,8 +106,7 @@
   // its package ID if `out_rewrite_method` is not nullptr.
   // `package_name_to_generate` is the package
   bool ProcessStyleable(const ResourceNameRef& name, const ResourceId& id,
-                        const Styleable& styleable,
-                        const android::StringPiece& package_name_to_generate,
+                        const Styleable& styleable, android::StringPiece package_name_to_generate,
                         ClassDefinition* out_class_def, MethodDefinition* out_rewrite_method,
                         text::Printer* r_txt_printer);
 
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index d0850b8..56d9075 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -646,8 +646,8 @@
   return true;
 }
 
-static void FullyQualifyClassName(const StringPiece& package, const StringPiece& attr_ns,
-                                  const StringPiece& attr_name, xml::Element* el) {
+static void FullyQualifyClassName(StringPiece package, StringPiece attr_ns, StringPiece attr_name,
+                                  xml::Element* el) {
   xml::Attribute* attr = el->FindAttribute(attr_ns, attr_name);
   if (attr != nullptr) {
     if (std::optional<std::string> new_value =
@@ -657,7 +657,7 @@
   }
 }
 
-static bool RenameManifestPackage(const StringPiece& package_override, xml::Element* manifest_el) {
+static bool RenameManifestPackage(StringPiece package_override, xml::Element* manifest_el) {
   xml::Attribute* attr = manifest_el->FindAttribute({}, "package");
 
   // We've already verified that the manifest element is present, with a package
@@ -665,7 +665,7 @@
   CHECK(attr != nullptr);
 
   std::string original_package = std::move(attr->value);
-  attr->value = package_override.to_string();
+  attr->value.assign(package_override);
 
   xml::Element* application_el = manifest_el->FindChild({}, "application");
   if (application_el != nullptr) {
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 8d1a647..7180ae6 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -61,12 +61,12 @@
             .Build();
   }
 
-  std::unique_ptr<xml::XmlResource> Verify(const StringPiece& str) {
+  std::unique_ptr<xml::XmlResource> Verify(StringPiece str) {
     return VerifyWithOptions(str, {});
   }
 
-  std::unique_ptr<xml::XmlResource> VerifyWithOptions(
-      const StringPiece& str, const ManifestFixerOptions& options) {
+  std::unique_ptr<xml::XmlResource> VerifyWithOptions(StringPiece str,
+                                                      const ManifestFixerOptions& options) {
     std::unique_ptr<xml::XmlResource> doc = test::BuildXmlDom(str);
     ManifestFixer fixer(options);
     if (fixer.Consume(mContext.get(), doc.get())) {
diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp
index f2a93a8..9dadfb2 100644
--- a/tools/aapt2/link/ReferenceLinker.cpp
+++ b/tools/aapt2/link/ReferenceLinker.cpp
@@ -189,8 +189,7 @@
  public:
   EmptyDeclStack() = default;
 
-  std::optional<xml::ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias) const override {
+  std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
     if (alias.empty()) {
       return xml::ExtractedPackage{{}, true /*private*/};
     }
@@ -206,8 +205,7 @@
       : alias_namespaces_(std::move(namespaces)) {
   }
 
-  std::optional<xml::ExtractedPackage> TransformPackageAlias(
-      const StringPiece& alias) const override {
+  std::optional<xml::ExtractedPackage> TransformPackageAlias(StringPiece alias) const override {
     if (alias.empty()) {
       return xml::ExtractedPackage{{}, true /*private*/};
     }
diff --git a/tools/aapt2/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index c9f0964..67a4828 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -66,7 +66,7 @@
 
 // This will merge and mangle resources from a static library. It is assumed that all FileReferences
 // have correctly set their io::IFile*.
-bool TableMerger::MergeAndMangle(const android::Source& src, const StringPiece& package_name,
+bool TableMerger::MergeAndMangle(const android::Source& src, StringPiece package_name,
                                  ResourceTable* table) {
   bool error = false;
   for (auto& package : table->packages) {
@@ -326,8 +326,8 @@
     const std::string& package, const FileReference& file_ref) {
   StringPiece prefix, entry, suffix;
   if (util::ExtractResFilePathParts(*file_ref.path, &prefix, &entry, &suffix)) {
-    std::string mangled_entry = NameMangler::MangleEntry(package, entry.to_string());
-    std::string newPath = prefix.to_string() + mangled_entry + suffix.to_string();
+    std::string mangled_entry = NameMangler::MangleEntry(package, entry);
+    std::string newPath = (std::string(prefix) += mangled_entry) += suffix;
     std::unique_ptr<FileReference> new_file_ref =
         util::make_unique<FileReference>(main_table_->string_pool.MakeRef(newPath));
     new_file_ref->SetComment(file_ref.GetComment());
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index 2ba2123..37daf42 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -61,7 +61,7 @@
   // References are made to this ResourceTable for efficiency reasons.
   TableMerger(IAaptContext* context, ResourceTable* out_table, const TableMergerOptions& options);
 
-  inline const std::set<std::string>& merged_packages() const {
+  inline const std::set<std::string, std::less<>>& merged_packages() const {
     return merged_packages_;
   }
 
@@ -71,7 +71,7 @@
 
   // Merges resources from the given package, mangling the name. This is for static libraries.
   // All FileReference values must have their io::IFile set.
-  bool MergeAndMangle(const android::Source& src, const android::StringPiece& package,
+  bool MergeAndMangle(const android::Source& src, android::StringPiece package,
                       ResourceTable* table);
 
   // Merges a compiled file that belongs to this same or empty package.
@@ -84,7 +84,7 @@
   ResourceTable* main_table_;
   TableMergerOptions options_;
   ResourceTablePackage* main_package_;
-  std::set<std::string> merged_packages_;
+  std::set<std::string, std::less<>> merged_packages_;
 
   bool MergeImpl(const android::Source& src, ResourceTable* src_table, bool overlay,
                  bool allow_new);
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index f994e27..f01db3d 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -113,12 +113,12 @@
 };
 
 class SignatureFilter : public IPathFilter {
-  bool Keep(const std::string& path) override {
+  bool Keep(std::string_view path) override {
     static std::regex signature_regex(R"regex(^META-INF/.*\.(RSA|DSA|EC|SF)$)regex");
-    if (std::regex_search(path, signature_regex)) {
+    if (std::regex_search(path.begin(), path.end(), signature_regex)) {
       return false;
     }
-    return !(path == "META-INF/MANIFEST.MF");
+    return path != "META-INF/MANIFEST.MF";
   }
 };
 
diff --git a/tools/aapt2/optimize/Obfuscator.cpp b/tools/aapt2/optimize/Obfuscator.cpp
index f704f26..cc21093 100644
--- a/tools/aapt2/optimize/Obfuscator.cpp
+++ b/tools/aapt2/optimize/Obfuscator.cpp
@@ -16,6 +16,8 @@
 
 #include "optimize/Obfuscator.h"
 
+#include <fstream>
+#include <map>
 #include <set>
 #include <string>
 #include <unordered_set>
@@ -32,10 +34,13 @@
 
 namespace aapt {
 
-Obfuscator::Obfuscator(std::map<std::string, std::string>& path_map_out) : path_map_(path_map_out) {
+Obfuscator::Obfuscator(OptimizeOptions& optimizeOptions)
+    : options_(optimizeOptions.table_flattener_options),
+      shorten_resource_paths_(optimizeOptions.shorten_resource_paths),
+      collapse_key_stringpool_(optimizeOptions.table_flattener_options.collapse_key_stringpool) {
 }
 
-std::string ShortenFileName(const android::StringPiece& file_path, int output_length) {
+std::string ShortenFileName(android::StringPiece file_path, int output_length) {
   std::size_t hash_num = std::hash<android::StringPiece>{}(file_path);
   std::string result = "";
   // Convert to (modified) base64 so that it is a proper file path.
@@ -58,9 +63,9 @@
   }
 }
 
-std::string GetShortenedPath(const android::StringPiece& shortened_filename,
-                             const android::StringPiece& extension, int collision_count) {
-  std::string shortened_path = "res/" + shortened_filename.to_string();
+std::string GetShortenedPath(android::StringPiece shortened_filename,
+                             android::StringPiece extension, int collision_count) {
+  std::string shortened_path = std::string("res/") += shortened_filename;
   if (collision_count > 0) {
     shortened_path += std::to_string(collision_count);
   }
@@ -77,7 +82,8 @@
   }
 };
 
-bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
+static bool HandleShortenFilePaths(ResourceTable* table,
+                                   std::map<std::string, std::string>& shortened_path_map) {
   // used to detect collisions
   std::unordered_set<std::string> shortened_paths;
   std::set<FileReference*, PathComparator> file_refs;
@@ -109,10 +115,117 @@
       shortened_path = GetShortenedPath(shortened_filename, extension, collision_count);
     }
     shortened_paths.insert(shortened_path);
-    path_map_.insert({*file_ref->path, shortened_path});
+    shortened_path_map.insert({*file_ref->path, shortened_path});
     file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext());
   }
   return true;
 }
 
+void Obfuscator::ObfuscateResourceName(
+    const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions,
+    const ResourceNamedType& type_name, const ResourceTableEntryView& entry,
+    const android::base::function_ref<void(Result obfuscatedResult, const ResourceName&)>
+        onObfuscate) {
+  ResourceName resource_name({}, type_name, entry.name);
+  if (!collapse_key_stringpool ||
+      name_collapse_exemptions.find(resource_name) != name_collapse_exemptions.end()) {
+    onObfuscate(Result::Keep_ExemptionList, resource_name);
+  } else {
+    // resource isn't exempt from collapse, add it as obfuscated value
+    if (entry.overlayable_item) {
+      // if the resource name of the specific entry is obfuscated and this
+      // entry is in the overlayable list, the overlay can't work on this
+      // overlayable at runtime because the name has been obfuscated in
+      // resources.arsc during flatten operation.
+      onObfuscate(Result::Keep_Overlayable, resource_name);
+    } else {
+      onObfuscate(Result::Obfuscated, resource_name);
+    }
+  }
+}
+
+static bool HandleCollapseKeyStringPool(
+    const ResourceTable* table, const bool collapse_key_string_pool,
+    const std::set<ResourceName>& name_collapse_exemptions,
+    std::unordered_map<uint32_t, std::string>& id_resource_map) {
+  if (!collapse_key_string_pool) {
+    return true;
+  }
+
+  int entryResId = 0;
+  auto onObfuscate = [&entryResId, &id_resource_map](const Obfuscator::Result obfuscatedResult,
+                                                     const ResourceName& resource_name) {
+    if (obfuscatedResult == Obfuscator::Result::Obfuscated) {
+      id_resource_map.insert({entryResId, resource_name.entry});
+    }
+  };
+
+  for (auto& package : table->packages) {
+    for (auto& type : package->types) {
+      for (auto& entry : type->entries) {
+        if (!entry->id.has_value() || entry->name.empty()) {
+          continue;
+        }
+        entryResId = entry->id->id;
+        ResourceTableEntryView entry_view{
+            .name = entry->name,
+            .id = entry->id ? entry->id.value().entry_id() : (std::optional<uint16_t>)std::nullopt,
+            .visibility = entry->visibility,
+            .allow_new = entry->allow_new,
+            .overlayable_item = entry->overlayable_item,
+            .staged_id = entry->staged_id};
+
+        Obfuscator::ObfuscateResourceName(collapse_key_string_pool, name_collapse_exemptions,
+                                          type->named_type, entry_view, onObfuscate);
+      }
+    }
+  }
+
+  return true;
+}
+
+bool Obfuscator::Consume(IAaptContext* context, ResourceTable* table) {
+  HandleCollapseKeyStringPool(table, options_.collapse_key_stringpool,
+                              options_.name_collapse_exemptions, options_.id_resource_map);
+  if (shorten_resource_paths_) {
+    return HandleShortenFilePaths(table, options_.shortened_path_map);
+  }
+  return true;
+}
+
+bool Obfuscator::WriteObfuscationMap(const std::string& file_path) const {
+  pb::ResourceMappings resourceMappings;
+  for (const auto& [id, name] : options_.id_resource_map) {
+    auto* collapsedNameMapping = resourceMappings.mutable_collapsed_names()->add_resource_names();
+    collapsedNameMapping->set_id(id);
+    collapsedNameMapping->set_name(name);
+  }
+
+  for (const auto& [original_path, shortened_path] : options_.shortened_path_map) {
+    auto* resource_path = resourceMappings.mutable_shortened_paths()->add_resource_paths();
+    resource_path->set_original_path(original_path);
+    resource_path->set_shortened_path(shortened_path);
+  }
+
+  {  // RAII style, output the pb content to file and close fout in destructor
+    std::ofstream fout(file_path, std::ios::out | std::ios::trunc | std::ios::binary);
+    if (!fout.is_open()) {
+      return false;
+    }
+    return resourceMappings.SerializeToOstream(&fout);
+  }
+}
+
+/**
+ * Tell the optimizer whether it's needed to dump information for de-obfuscating.
+ *
+ * There are two conditions need to dump the information for de-obfuscating.
+ * * the option of shortening file paths is enabled.
+ * * the option of collapsing resource names is enabled.
+ * @return true if the information needed for de-obfuscating, otherwise false
+ */
+bool Obfuscator::IsEnabled() const {
+  return shorten_resource_paths_ || collapse_key_stringpool_;
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/optimize/Obfuscator.h b/tools/aapt2/optimize/Obfuscator.h
index 1ea32db..5ccf5438 100644
--- a/tools/aapt2/optimize/Obfuscator.h
+++ b/tools/aapt2/optimize/Obfuscator.h
@@ -17,10 +17,15 @@
 #ifndef TOOLS_AAPT2_OPTIMIZE_OBFUSCATOR_H_
 #define TOOLS_AAPT2_OPTIMIZE_OBFUSCATOR_H_
 
-#include <map>
+#include <set>
 #include <string>
 
+#include "ResourceMetadata.pb.h"
+#include "ResourceTable.h"
+#include "android-base/function_ref.h"
 #include "android-base/macros.h"
+#include "cmd/Optimize.h"
+#include "format/binary/TableFlattener.h"
 #include "process/IResourceTableConsumer.h"
 
 namespace aapt {
@@ -30,12 +35,28 @@
 // Maps resources in the apk to shortened paths.
 class Obfuscator : public IResourceTableConsumer {
  public:
-  explicit Obfuscator(std::map<std::string, std::string>& path_map_out);
+  explicit Obfuscator(OptimizeOptions& optimizeOptions);
 
   bool Consume(IAaptContext* context, ResourceTable* table) override;
 
+  bool WriteObfuscationMap(const std::string& file_path) const;
+
+  bool IsEnabled() const;
+
+  enum class Result { Obfuscated, Keep_ExemptionList, Keep_Overlayable };
+
+  // hardcoded string uses characters which make it an invalid resource name
+  static constexpr char kObfuscatedResourceName[] = "0_resource_name_obfuscated";
+
+  static void ObfuscateResourceName(
+      const bool collapse_key_stringpool, const std::set<ResourceName>& name_collapse_exemptions,
+      const ResourceNamedType& type_name, const ResourceTableEntryView& entry,
+      const android::base::function_ref<void(Result, const ResourceName&)> onObfuscate);
+
  private:
-  std::map<std::string, std::string>& path_map_;
+  TableFlattenerOptions& options_;
+  const bool shorten_resource_paths_;
+  const bool collapse_key_stringpool_;
   DISALLOW_COPY_AND_ASSIGN(Obfuscator);
 };
 
diff --git a/tools/aapt2/optimize/Obfuscator_test.cpp b/tools/aapt2/optimize/Obfuscator_test.cpp
index a3339d4..7f57b71 100644
--- a/tools/aapt2/optimize/Obfuscator_test.cpp
+++ b/tools/aapt2/optimize/Obfuscator_test.cpp
@@ -16,14 +16,19 @@
 
 #include "optimize/Obfuscator.h"
 
+#include <map>
 #include <memory>
 #include <string>
 
 #include "ResourceTable.h"
+#include "android-base/file.h"
 #include "test/Test.h"
 
 using ::aapt::test::GetValue;
+using ::testing::AnyOf;
 using ::testing::Eq;
+using ::testing::HasSubstr;
+using ::testing::IsTrue;
 using ::testing::Not;
 using ::testing::NotNull;
 
@@ -51,8 +56,9 @@
           .AddString("android:string/string", "res/should/still/be/the/same.png")
           .Build();
 
-  std::map<std::string, std::string> path_map;
-  ASSERT_TRUE(Obfuscator(path_map).Consume(context.get(), table.get()));
+  OptimizeOptions options{.shorten_resource_paths = true};
+  std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+  ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
 
   // Expect that the path map is populated
   ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end())));
@@ -87,8 +93,9 @@
                             test::ParseConfigOrDie("mdp-v21"))
           .Build();
 
-  std::map<std::string, std::string> path_map;
-  ASSERT_TRUE(Obfuscator(path_map).Consume(context.get(), table.get()));
+  OptimizeOptions options{.shorten_resource_paths = true};
+  std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+  ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
 
   // Expect that the path map to not contain the ColorStateList
   ASSERT_THAT(path_map.find("res/color/colorlist.xml"), Eq(path_map.end()));
@@ -107,8 +114,9 @@
           .AddFileReference("android:color/pngfile", original_png_path)
           .Build();
 
-  std::map<std::string, std::string> path_map;
-  ASSERT_TRUE(Obfuscator(path_map).Consume(context.get(), table.get()));
+  OptimizeOptions options{.shorten_resource_paths = true};
+  std::map<std::string, std::string>& path_map = options.table_flattener_options.shortened_path_map;
+  ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
 
   // Expect that the path map is populated
   ASSERT_THAT(path_map.find("res/drawable/xmlfile.xml"), Not(Eq(path_map.end())));
@@ -133,8 +141,10 @@
   test::ResourceTableBuilder builder1;
   FillTable(builder1, 0, kNumResources);
   std::unique_ptr<ResourceTable> table1 = builder1.Build();
-  std::map<std::string, std::string> expected_mapping;
-  ASSERT_TRUE(Obfuscator(expected_mapping).Consume(context.get(), table1.get()));
+  OptimizeOptions options{.shorten_resource_paths = true};
+  std::map<std::string, std::string>& expected_mapping =
+      options.table_flattener_options.shortened_path_map;
+  ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table1.get()));
 
   // We are trying to ensure lack of non-determinism, it is not simple to prove
   // a negative, thus we must try the test a few times so that the test itself
@@ -153,8 +163,10 @@
     FillTable(builder2, 0, start_index);
     std::unique_ptr<ResourceTable> table2 = builder2.Build();
 
-    std::map<std::string, std::string> actual_mapping;
-    ASSERT_TRUE(Obfuscator(actual_mapping).Consume(context.get(), table2.get()));
+    OptimizeOptions actualOptimizerOptions{.shorten_resource_paths = true};
+    TableFlattenerOptions& actual_options = actualOptimizerOptions.table_flattener_options;
+    std::map<std::string, std::string>& actual_mapping = actual_options.shortened_path_map;
+    ASSERT_TRUE(Obfuscator(actualOptimizerOptions).Consume(context.get(), table2.get()));
 
     for (auto& item : actual_mapping) {
       ASSERT_THAT(expected_mapping[item.first], Eq(item.second));
@@ -162,4 +174,126 @@
   }
 }
 
+TEST(ObfuscatorTest, DumpIdResourceMap) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
+
+  OverlayableItem overlayable_item(std::make_shared<Overlayable>("TestName", "overlay://theme"));
+  overlayable_item.policies |= PolicyFlags::PRODUCT_PARTITION;
+  overlayable_item.policies |= PolicyFlags::SYSTEM_PARTITION;
+  overlayable_item.policies |= PolicyFlags::VENDOR_PARTITION;
+
+  std::string original_xml_path = "res/drawable/xmlfile.xml";
+  std::string original_png_path = "res/drawable/pngfile.png";
+
+  std::string name = "com.app.test:string/overlayable";
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .AddFileReference("android:color/xmlfile", original_xml_path)
+          .AddFileReference("android:color/pngfile", original_png_path)
+          .AddValue("com.app.test:color/mycolor", aapt::ResourceId(0x7f020000),
+                    aapt::util::make_unique<aapt::BinaryPrimitive>(
+                        uint8_t(android::Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc))
+          .AddString("com.app.test:string/mystring", ResourceId(0x7f030000), "hi")
+          .AddString("com.app.test:string/in_exemption", ResourceId(0x7f030001), "Hi")
+          .AddString(name, ResourceId(0x7f030002), "HI")
+          .SetOverlayable(name, overlayable_item)
+          .Build();
+
+  OptimizeOptions options{.shorten_resource_paths = true};
+  TableFlattenerOptions& flattenerOptions = options.table_flattener_options;
+  flattenerOptions.collapse_key_stringpool = true;
+  flattenerOptions.name_collapse_exemptions.insert(
+      ResourceName({}, ResourceType::kString, "in_exemption"));
+  auto& id_resource_map = flattenerOptions.id_resource_map;
+  ASSERT_TRUE(Obfuscator(options).Consume(context.get(), table.get()));
+
+  // Expect that the id resource name map is populated
+  EXPECT_THAT(id_resource_map.at(0x7f020000), Eq("mycolor"));
+  EXPECT_THAT(id_resource_map.at(0x7f030000), Eq("mystring"));
+  EXPECT_THAT(id_resource_map.find(0x7f030001), Eq(id_resource_map.end()));
+  EXPECT_THAT(id_resource_map.find(0x7f030002), Eq(id_resource_map.end()));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithDefaultOption) {
+  OptimizeOptions options;
+  Obfuscator obfuscatorWithDefaultOption(options);
+  ASSERT_THAT(obfuscatorWithDefaultOption.IsEnabled(), Eq(false));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithShortenPathOption) {
+  OptimizeOptions options{.shorten_resource_paths = true};
+  Obfuscator obfuscatorWithShortenPathOption(options);
+  ASSERT_THAT(obfuscatorWithShortenPathOption.IsEnabled(), Eq(true));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithCollapseStringPoolOption) {
+  OptimizeOptions options;
+  options.table_flattener_options.collapse_key_stringpool = true;
+  Obfuscator obfuscatorWithCollapseStringPoolOption(options);
+  ASSERT_THAT(obfuscatorWithCollapseStringPoolOption.IsEnabled(), Eq(true));
+}
+
+TEST(ObfuscatorTest, IsEnabledWithShortenPathAndCollapseStringPoolOption) {
+  OptimizeOptions options{.shorten_resource_paths = true};
+  options.table_flattener_options.collapse_key_stringpool = true;
+  Obfuscator obfuscatorWithCollapseStringPoolOption(options);
+  ASSERT_THAT(obfuscatorWithCollapseStringPoolOption.IsEnabled(), Eq(true));
+}
+
+static std::unique_ptr<ResourceTable> getProtocolBufferTableUnderTest() {
+  std::string original_xml_path = "res/drawable/xmlfile.xml";
+  std::string original_png_path = "res/drawable/pngfile.png";
+
+  return test::ResourceTableBuilder()
+      .AddFileReference("com.app.test:drawable/xmlfile", original_xml_path)
+      .AddFileReference("com.app.test:drawable/pngfile", original_png_path)
+      .AddValue("com.app.test:color/mycolor", aapt::ResourceId(0x7f020000),
+                aapt::util::make_unique<aapt::BinaryPrimitive>(
+                    uint8_t(android::Res_value::TYPE_INT_COLOR_ARGB8), 0xffaabbcc))
+      .AddString("com.app.test:string/mystring", ResourceId(0x7f030000), "hello world")
+      .Build();
+}
+
+TEST(ObfuscatorTest, WriteObfuscationMapInProtocolBufferFormat) {
+  OptimizeOptions options{.shorten_resource_paths = true};
+  options.table_flattener_options.collapse_key_stringpool = true;
+  Obfuscator obfuscator(options);
+  ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
+                                 getProtocolBufferTableUnderTest().get()));
+
+  obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+
+  std::string pbOut;
+  android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+  EXPECT_THAT(pbOut, HasSubstr("drawable/xmlfile.xml"));
+  EXPECT_THAT(pbOut, HasSubstr("drawable/pngfile.png"));
+  EXPECT_THAT(pbOut, HasSubstr("mycolor"));
+  EXPECT_THAT(pbOut, HasSubstr("mystring"));
+  pb::ResourceMappings resourceMappings;
+  EXPECT_THAT(resourceMappings.ParseFromString(pbOut), IsTrue());
+  EXPECT_THAT(resourceMappings.collapsed_names().resource_names_size(), Eq(2));
+  auto& resource_names = resourceMappings.collapsed_names().resource_names();
+  EXPECT_THAT(resource_names.at(0).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
+  EXPECT_THAT(resource_names.at(1).name(), AnyOf(Eq("mycolor"), Eq("mystring")));
+  auto& shortened_paths = resourceMappings.shortened_paths();
+  EXPECT_THAT(shortened_paths.resource_paths_size(), Eq(2));
+  EXPECT_THAT(shortened_paths.resource_paths(0).original_path(),
+              AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
+  EXPECT_THAT(shortened_paths.resource_paths(1).original_path(),
+              AnyOf(Eq("res/drawable/pngfile.png"), Eq("res/drawable/xmlfile.xml")));
+}
+
+TEST(ObfuscatorTest, WriteObfuscatingMapWithNonEnabledOption) {
+  OptimizeOptions options;
+  Obfuscator obfuscator(options);
+  ASSERT_TRUE(obfuscator.Consume(test::ContextBuilder().Build().get(),
+                                 getProtocolBufferTableUnderTest().get()));
+
+  obfuscator.WriteObfuscationMap("obfuscated_map.pb");
+
+  std::string pbOut;
+  android::base::ReadFileToString("obfuscated_map.pb", &pbOut, false /* follow_symlinks */);
+  ASSERT_THAT(pbOut, Eq(""));
+}
+
 }  // namespace aapt
diff --git a/tools/aapt2/optimize/VersionCollapser_test.cpp b/tools/aapt2/optimize/VersionCollapser_test.cpp
index aa0d0c0..18dcd6b 100644
--- a/tools/aapt2/optimize/VersionCollapser_test.cpp
+++ b/tools/aapt2/optimize/VersionCollapser_test.cpp
@@ -23,7 +23,7 @@
 namespace aapt {
 
 static std::unique_ptr<ResourceTable> BuildTableWithConfigs(
-    const StringPiece& name, std::initializer_list<std::string> list) {
+    StringPiece name, std::initializer_list<std::string> list) {
   test::ResourceTableBuilder builder;
   for (const std::string& item : list) {
     builder.AddSimple(name, test::ParseConfigOrDie(item));
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 92b45c3..bca62da 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -218,7 +218,7 @@
   return symbol;
 }
 
-bool AssetManagerSymbolSource::AddAssetPath(const StringPiece& path) {
+bool AssetManagerSymbolSource::AddAssetPath(StringPiece path) {
   TRACE_CALL();
   if (std::unique_ptr<const ApkAssets> apk = ApkAssets::Load(path.data())) {
     apk_assets_.push_back(std::move(apk));
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index c17837c..b09ff70 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -192,7 +192,7 @@
  public:
   AssetManagerSymbolSource() = default;
 
-  bool AddAssetPath(const android::StringPiece& path);
+  bool AddAssetPath(android::StringPiece path);
   std::map<size_t, std::string> GetAssignedPackageIds() const;
   bool IsPackageDynamic(uint32_t packageId, const std::string& package_name) const;
 
diff --git a/tools/aapt2/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 30336e2..65f63dc 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -34,61 +34,53 @@
 namespace aapt {
 namespace test {
 
-ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name,
-                                                      const ResourceId& id) {
+ResourceTableBuilder& ResourceTableBuilder::AddSimple(StringPiece name, const ResourceId& id) {
   return AddValue(name, id, util::make_unique<Id>());
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddSimple(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddSimple(StringPiece name,
                                                       const ConfigDescription& config,
                                                       const ResourceId& id) {
   return AddValue(name, config, id, util::make_unique<Id>());
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name,
-                                                         const StringPiece& ref) {
+ResourceTableBuilder& ResourceTableBuilder::AddReference(StringPiece name, StringPiece ref) {
   return AddReference(name, {}, ref);
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddReference(const StringPiece& name,
-                                                         const ResourceId& id,
-                                                         const StringPiece& ref) {
+ResourceTableBuilder& ResourceTableBuilder::AddReference(StringPiece name, const ResourceId& id,
+                                                         StringPiece ref) {
   return AddValue(name, id, util::make_unique<Reference>(ParseNameOrDie(ref)));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name,
-                                                      const StringPiece& str) {
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, StringPiece str) {
   return AddString(name, {}, str);
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id,
-                                                      const StringPiece& str) {
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, const ResourceId& id,
+                                                      StringPiece str) {
   return AddValue(name, id, util::make_unique<String>(table_->string_pool.MakeRef(str)));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddString(const StringPiece& name, const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::AddString(StringPiece name, const ResourceId& id,
                                                       const ConfigDescription& config,
-                                                      const StringPiece& str) {
+                                                      StringPiece str) {
   return AddValue(name, config, id, util::make_unique<String>(table_->string_pool.MakeRef(str)));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
-                                                             const StringPiece& path,
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, StringPiece path,
                                                              io::IFile* file) {
   return AddFileReference(name, {}, path, file);
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
-                                                             const ResourceId& id,
-                                                             const StringPiece& path,
-                                                             io::IFile* file) {
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, const ResourceId& id,
+                                                             StringPiece path, io::IFile* file) {
   auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
   file_ref->file = file;
   return AddValue(name, id, std::move(file_ref));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
-                                                             const StringPiece& path,
+ResourceTableBuilder& ResourceTableBuilder::AddFileReference(StringPiece name, StringPiece path,
                                                              const ConfigDescription& config,
                                                              io::IFile* file) {
   auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
@@ -96,17 +88,17 @@
   return AddValue(name, config, {}, std::move(file_ref));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name,
                                                      std::unique_ptr<Value> value) {
   return AddValue(name, {}, std::move(value));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name, const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name, const ResourceId& id,
                                                      std::unique_ptr<Value> value) {
   return AddValue(name, {}, id, std::move(value));
 }
 
-ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::AddValue(StringPiece name,
                                                      const ConfigDescription& config,
                                                      const ResourceId& id,
                                                      std::unique_ptr<Value> value) {
@@ -121,8 +113,7 @@
   return *this;
 }
 
-ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(const StringPiece& name,
-                                                           const ResourceId& id,
+ResourceTableBuilder& ResourceTableBuilder::SetSymbolState(StringPiece name, const ResourceId& id,
                                                            Visibility::Level level,
                                                            bool allow_new) {
   ResourceName res_name = ParseNameOrDie(name);
@@ -136,9 +127,8 @@
   return *this;
 }
 
-ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(const StringPiece& name,
+ResourceTableBuilder& ResourceTableBuilder::SetOverlayable(StringPiece name,
                                                            const OverlayableItem& overlayable) {
-
   ResourceName res_name = ParseNameOrDie(name);
   CHECK(table_->AddResource(
       NewResourceBuilder(res_name).SetOverlayable(overlayable).SetAllowMangled(true).Build(),
@@ -159,8 +149,7 @@
   return std::move(table_);
 }
 
-std::unique_ptr<Reference> BuildReference(const StringPiece& ref,
-                                          const std::optional<ResourceId>& id) {
+std::unique_ptr<Reference> BuildReference(StringPiece ref, const std::optional<ResourceId>& id) {
   std::unique_ptr<Reference> reference = util::make_unique<Reference>(ParseNameOrDie(ref));
   reference->id = id;
   return reference;
@@ -188,7 +177,7 @@
   return *this;
 }
 
-AttributeBuilder& AttributeBuilder::AddItem(const StringPiece& name, uint32_t value) {
+AttributeBuilder& AttributeBuilder::AddItem(StringPiece name, uint32_t value) {
   attr_->symbols.push_back(
       Attribute::Symbol{Reference(ResourceName({}, ResourceType::kId, name)), value});
   return *this;
@@ -198,17 +187,17 @@
   return std::move(attr_);
 }
 
-StyleBuilder& StyleBuilder::SetParent(const StringPiece& str) {
+StyleBuilder& StyleBuilder::SetParent(StringPiece str) {
   style_->parent = Reference(ParseNameOrDie(str));
   return *this;
 }
 
-StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, std::unique_ptr<Item> value) {
+StyleBuilder& StyleBuilder::AddItem(StringPiece str, std::unique_ptr<Item> value) {
   style_->entries.push_back(Style::Entry{Reference(ParseNameOrDie(str)), std::move(value)});
   return *this;
 }
 
-StyleBuilder& StyleBuilder::AddItem(const StringPiece& str, const ResourceId& id,
+StyleBuilder& StyleBuilder::AddItem(StringPiece str, const ResourceId& id,
                                     std::unique_ptr<Item> value) {
   AddItem(str, std::move(value));
   style_->entries.back().key.id = id;
@@ -219,8 +208,7 @@
   return std::move(style_);
 }
 
-StyleableBuilder& StyleableBuilder::AddItem(const StringPiece& str,
-                                            const std::optional<ResourceId>& id) {
+StyleableBuilder& StyleableBuilder::AddItem(StringPiece str, const std::optional<ResourceId>& id) {
   styleable_->entries.push_back(Reference(ParseNameOrDie(str)));
   styleable_->entries.back().id = id;
   return *this;
@@ -230,7 +218,7 @@
   return std::move(styleable_);
 }
 
-std::unique_ptr<xml::XmlResource> BuildXmlDom(const StringPiece& str) {
+std::unique_ptr<xml::XmlResource> BuildXmlDom(StringPiece str) {
   std::string input = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
   input.append(str.data(), str.size());
   StringInputStream in(input);
@@ -241,7 +229,7 @@
 }
 
 std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context,
-                                                            const StringPiece& str) {
+                                                            StringPiece str) {
   std::unique_ptr<xml::XmlResource> doc = BuildXmlDom(str);
   doc->file.name.package = context->GetCompilationPackage();
   return doc;
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 780bd0d..f03d6fc 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -38,40 +38,35 @@
  public:
   ResourceTableBuilder() = default;
 
-  ResourceTableBuilder& AddSimple(const android::StringPiece& name, const ResourceId& id = {});
-  ResourceTableBuilder& AddSimple(const android::StringPiece& name,
+  ResourceTableBuilder& AddSimple(android::StringPiece name, const ResourceId& id = {});
+  ResourceTableBuilder& AddSimple(android::StringPiece name,
                                   const android::ConfigDescription& config,
                                   const ResourceId& id = {});
-  ResourceTableBuilder& AddReference(const android::StringPiece& name,
-                                     const android::StringPiece& ref);
-  ResourceTableBuilder& AddReference(const android::StringPiece& name, const ResourceId& id,
-                                     const android::StringPiece& ref);
-  ResourceTableBuilder& AddString(const android::StringPiece& name,
-                                  const android::StringPiece& str);
-  ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
-                                  const android::StringPiece& str);
-  ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
+  ResourceTableBuilder& AddReference(android::StringPiece name, android::StringPiece ref);
+  ResourceTableBuilder& AddReference(android::StringPiece name, const ResourceId& id,
+                                     android::StringPiece ref);
+  ResourceTableBuilder& AddString(android::StringPiece name, android::StringPiece str);
+  ResourceTableBuilder& AddString(android::StringPiece name, const ResourceId& id,
+                                  android::StringPiece str);
+  ResourceTableBuilder& AddString(android::StringPiece name, const ResourceId& id,
                                   const android::ConfigDescription& config,
-                                  const android::StringPiece& str);
-  ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
-                                         const android::StringPiece& path,
+                                  android::StringPiece str);
+  ResourceTableBuilder& AddFileReference(android::StringPiece name, android::StringPiece path,
                                          io::IFile* file = nullptr);
-  ResourceTableBuilder& AddFileReference(const android::StringPiece& name, const ResourceId& id,
-                                         const android::StringPiece& path,
-                                         io::IFile* file = nullptr);
-  ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
-                                         const android::StringPiece& path,
+  ResourceTableBuilder& AddFileReference(android::StringPiece name, const ResourceId& id,
+                                         android::StringPiece path, io::IFile* file = nullptr);
+  ResourceTableBuilder& AddFileReference(android::StringPiece name, android::StringPiece path,
                                          const android::ConfigDescription& config,
                                          io::IFile* file = nullptr);
-  ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value);
-  ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
+  ResourceTableBuilder& AddValue(android::StringPiece name, std::unique_ptr<Value> value);
+  ResourceTableBuilder& AddValue(android::StringPiece name, const ResourceId& id,
                                  std::unique_ptr<Value> value);
-  ResourceTableBuilder& AddValue(const android::StringPiece& name,
-                                 const android::ConfigDescription& config,
-                                 const ResourceId& id, std::unique_ptr<Value> value);
-  ResourceTableBuilder& SetSymbolState(const android::StringPiece& name, const ResourceId& id,
+  ResourceTableBuilder& AddValue(android::StringPiece name,
+                                 const android::ConfigDescription& config, const ResourceId& id,
+                                 std::unique_ptr<Value> value);
+  ResourceTableBuilder& SetSymbolState(android::StringPiece name, const ResourceId& id,
                                        Visibility::Level level, bool allow_new = false);
-  ResourceTableBuilder& SetOverlayable(const android::StringPiece& name,
+  ResourceTableBuilder& SetOverlayable(android::StringPiece name,
                                        const OverlayableItem& overlayable);
   ResourceTableBuilder& Add(NewResource&& res);
 
@@ -84,7 +79,7 @@
   std::unique_ptr<ResourceTable> table_ = util::make_unique<ResourceTable>();
 };
 
-std::unique_ptr<Reference> BuildReference(const android::StringPiece& ref,
+std::unique_ptr<Reference> BuildReference(android::StringPiece ref,
                                           const std::optional<ResourceId>& id = {});
 std::unique_ptr<BinaryPrimitive> BuildPrimitive(uint8_t type, uint32_t data);
 
@@ -101,7 +96,7 @@
     return *this;
   }
 
-  ValueBuilder& SetComment(const android::StringPiece& str) {
+  ValueBuilder& SetComment(android::StringPiece str) {
     value_->SetComment(str);
     return *this;
   }
@@ -121,7 +116,7 @@
   AttributeBuilder();
   AttributeBuilder& SetTypeMask(uint32_t typeMask);
   AttributeBuilder& SetWeak(bool weak);
-  AttributeBuilder& AddItem(const android::StringPiece& name, uint32_t value);
+  AttributeBuilder& AddItem(android::StringPiece name, uint32_t value);
   std::unique_ptr<Attribute> Build();
 
  private:
@@ -133,9 +128,9 @@
 class StyleBuilder {
  public:
   StyleBuilder() = default;
-  StyleBuilder& SetParent(const android::StringPiece& str);
-  StyleBuilder& AddItem(const android::StringPiece& str, std::unique_ptr<Item> value);
-  StyleBuilder& AddItem(const android::StringPiece& str, const ResourceId& id,
+  StyleBuilder& SetParent(android::StringPiece str);
+  StyleBuilder& AddItem(android::StringPiece str, std::unique_ptr<Item> value);
+  StyleBuilder& AddItem(android::StringPiece str, const ResourceId& id,
                         std::unique_ptr<Item> value);
   std::unique_ptr<Style> Build();
 
@@ -148,8 +143,7 @@
 class StyleableBuilder {
  public:
   StyleableBuilder() = default;
-  StyleableBuilder& AddItem(const android::StringPiece& str,
-                            const std::optional<ResourceId>& id = {});
+  StyleableBuilder& AddItem(android::StringPiece str, const std::optional<ResourceId>& id = {});
   std::unique_ptr<Styleable> Build();
 
  private:
@@ -158,9 +152,9 @@
   std::unique_ptr<Styleable> styleable_ = util::make_unique<Styleable>();
 };
 
-std::unique_ptr<xml::XmlResource> BuildXmlDom(const android::StringPiece& str);
+std::unique_ptr<xml::XmlResource> BuildXmlDom(android::StringPiece str);
 std::unique_ptr<xml::XmlResource> BuildXmlDomForPackageName(IAaptContext* context,
-                                                            const android::StringPiece& str);
+                                                            android::StringPiece str);
 
 class ArtifactBuilder {
  public:
diff --git a/tools/aapt2/test/Common.cpp b/tools/aapt2/test/Common.cpp
index eca0c1c..cdf24534 100644
--- a/tools/aapt2/test/Common.cpp
+++ b/tools/aapt2/test/Common.cpp
@@ -44,10 +44,9 @@
 }
 
 template <>
-Value* GetValueForConfigAndProduct<Value>(ResourceTable* table,
-                                          const android::StringPiece& res_name,
+Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, android::StringPiece res_name,
                                           const ConfigDescription& config,
-                                          const android::StringPiece& product) {
+                                          android::StringPiece product) {
   std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
   if (result) {
     ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
diff --git a/tools/aapt2/test/Common.h b/tools/aapt2/test/Common.h
index 3f28361..83a0f3f 100644
--- a/tools/aapt2/test/Common.h
+++ b/tools/aapt2/test/Common.h
@@ -39,22 +39,22 @@
 
 android::IDiagnostics* GetDiagnostics();
 
-inline ResourceName ParseNameOrDie(const android::StringPiece& str) {
+inline ResourceName ParseNameOrDie(android::StringPiece str) {
   ResourceNameRef ref;
   CHECK(ResourceUtils::ParseResourceName(str, &ref)) << "invalid resource name: " << str;
   return ref.ToResourceName();
 }
 
-inline android::ConfigDescription ParseConfigOrDie(const android::StringPiece& str) {
-    android::ConfigDescription config;
+inline android::ConfigDescription ParseConfigOrDie(android::StringPiece str) {
+  android::ConfigDescription config;
   CHECK(android::ConfigDescription::Parse(str, &config)) << "invalid configuration: " << str;
   return config;
 }
 
 template <typename T = Value>
-T* GetValueForConfigAndProduct(ResourceTable* table, const android::StringPiece& res_name,
+T* GetValueForConfigAndProduct(ResourceTable* table, android::StringPiece res_name,
                                const android::ConfigDescription& config,
-                               const android::StringPiece& product) {
+                               android::StringPiece product) {
   std::optional<ResourceTable::SearchResult> result = table->FindResource(ParseNameOrDie(res_name));
   if (result) {
     ResourceConfigValue* config_value = result.value().entry->FindValue(config, product);
@@ -66,25 +66,25 @@
 }
 
 template <>
-Value* GetValueForConfigAndProduct<Value>(ResourceTable* table,
-                                          const android::StringPiece& res_name,
+Value* GetValueForConfigAndProduct<Value>(ResourceTable* table, android::StringPiece res_name,
                                           const android::ConfigDescription& config,
-                                          const android::StringPiece& product);
+                                          android::StringPiece product);
 
 template <typename T = Value>
-T* GetValueForConfig(ResourceTable* table, const android::StringPiece& res_name,
+T* GetValueForConfig(ResourceTable* table, android::StringPiece res_name,
                      const android::ConfigDescription& config) {
   return GetValueForConfigAndProduct<T>(table, res_name, config, {});
 }
 
 template <typename T = Value>
-T* GetValue(ResourceTable* table, const android::StringPiece& res_name) {
+T* GetValue(ResourceTable* table, android::StringPiece res_name) {
   return GetValueForConfig<T>(table, res_name, {});
 }
 
 class TestFile : public io::IFile {
  public:
-  explicit TestFile(const android::StringPiece& path) : source_(path) {}
+  explicit TestFile(android::StringPiece path) : source_(path) {
+  }
 
   std::unique_ptr<io::IData> OpenAsData() override {
     return {};
diff --git a/tools/aapt2/test/Context.h b/tools/aapt2/test/Context.h
index 4e4973e..c5331fb 100644
--- a/tools/aapt2/test/Context.h
+++ b/tools/aapt2/test/Context.h
@@ -52,8 +52,8 @@
     return compilation_package_.value();
   }
 
-  void SetCompilationPackage(const android::StringPiece& package) {
-    compilation_package_ = package.to_string();
+  void SetCompilationPackage(android::StringPiece package) {
+    compilation_package_ = std::string(package);
   }
 
   uint8_t GetPackageId() override {
@@ -111,8 +111,8 @@
     return *this;
   }
 
-  ContextBuilder& SetCompilationPackage(const android::StringPiece& package) {
-    context_->compilation_package_ = package.to_string();
+  ContextBuilder& SetCompilationPackage(android::StringPiece package) {
+    context_->compilation_package_ = std::string(package);
     return *this;
   }
 
@@ -149,7 +149,7 @@
 
 class StaticSymbolSourceBuilder {
  public:
-  StaticSymbolSourceBuilder& AddPublicSymbol(const android::StringPiece& name, ResourceId id,
+  StaticSymbolSourceBuilder& AddPublicSymbol(android::StringPiece name, ResourceId id,
                                              std::unique_ptr<Attribute> attr = {}) {
     std::unique_ptr<SymbolTable::Symbol> symbol =
         util::make_unique<SymbolTable::Symbol>(id, std::move(attr), true);
@@ -159,7 +159,7 @@
     return *this;
   }
 
-  StaticSymbolSourceBuilder& AddSymbol(const android::StringPiece& name, ResourceId id,
+  StaticSymbolSourceBuilder& AddSymbol(android::StringPiece name, ResourceId id,
                                        std::unique_ptr<Attribute> attr = {}) {
     std::unique_ptr<SymbolTable::Symbol> symbol =
         util::make_unique<SymbolTable::Symbol>(id, std::move(attr), false);
diff --git a/tools/aapt2/test/Fixture.cpp b/tools/aapt2/test/Fixture.cpp
index dbc0e36..428372f 100644
--- a/tools/aapt2/test/Fixture.cpp
+++ b/tools/aapt2/test/Fixture.cpp
@@ -38,8 +38,8 @@
 
 const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
 
-void ClearDirectory(const android::StringPiece& path) {
-  const std::string root_dir = path.to_string();
+void ClearDirectory(android::StringPiece path) {
+  const std::string root_dir(path);
   std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
   if (!dir) {
     StdErrDiagnostics().Error(android::DiagMessage()
@@ -91,8 +91,7 @@
 }
 
 bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
-                                     const android::StringPiece& out_dir,
-                                     android::IDiagnostics* diag) {
+                                     android::StringPiece out_dir, android::IDiagnostics* diag) {
   WriteFile(path, contents);
   CHECK(file::mkdirs(out_dir.data()));
   return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
@@ -113,8 +112,8 @@
   return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
 }
 
-bool CommandTestFixture::Link(const std::vector<std::string>& args,
-                              const android::StringPiece& flat_dir, android::IDiagnostics* diag) {
+bool CommandTestFixture::Link(const std::vector<std::string>& args, android::StringPiece flat_dir,
+                              android::IDiagnostics* diag) {
   std::vector<android::StringPiece> link_args;
   for(const std::string& arg : args) {
     link_args.emplace_back(arg);
@@ -148,7 +147,7 @@
 }
 
 std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
-                                                              const android::StringPiece& path) {
+                                                              android::StringPiece path) {
   return apk
       ->GetFileCollection()
       ->FindFile(path)
diff --git a/tools/aapt2/test/Fixture.h b/tools/aapt2/test/Fixture.h
index 61403b7..ba4a734 100644
--- a/tools/aapt2/test/Fixture.h
+++ b/tools/aapt2/test/Fixture.h
@@ -48,7 +48,7 @@
   // Retrieves the absolute path of the specified relative path in the test directory. Directories
   // should be separated using forward slashes ('/'), and these slashes will be translated to
   // backslashes when running Windows tests.
-  std::string GetTestPath(const android::StringPiece& path) {
+  std::string GetTestPath(android::StringPiece path) {
     std::string base = temp_dir_;
     for (android::StringPiece part : util::Split(path, '/')) {
       file::AppendPath(&base, part);
@@ -73,22 +73,21 @@
   // Wries the contents of the file to the specified path. The file is compiled and the flattened
   // file is written to the out directory.
   bool CompileFile(const std::string& path, const std::string& contents,
-                   const android::StringPiece& flat_out_dir, android::IDiagnostics* diag);
+                   android::StringPiece flat_out_dir, android::IDiagnostics* diag);
 
   // Executes the link command with the specified arguments.
   bool Link(const std::vector<std::string>& args, android::IDiagnostics* diag);
 
   // Executes the link command with the specified arguments. The flattened files residing in the
   // flat directory will be added to the link command as file arguments.
-  bool Link(const std::vector<std::string>& args, const android::StringPiece& flat_dir,
+  bool Link(const std::vector<std::string>& args, android::StringPiece flat_dir,
             android::IDiagnostics* diag);
 
   // Creates a minimal android manifest within the test directory and returns the file path.
   std::string GetDefaultManifest(const char* package_name = kDefaultPackageName);
 
   // Returns pointer to data inside APK files
-  std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk,
-                                            const android::StringPiece& path);
+  std::unique_ptr<io::IData> OpenFileAsData(LoadedApk* apk, android::StringPiece path);
 
   // Asserts that loading the tree from the specified file in the apk succeeds.
   void AssertLoadXml(LoadedApk* apk, const io::IData* data,
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
index 243800c..8e491ac 100644
--- a/tools/aapt2/text/Printer.cpp
+++ b/tools/aapt2/text/Printer.cpp
@@ -26,7 +26,7 @@
 namespace aapt {
 namespace text {
 
-Printer& Printer::Println(const StringPiece& str) {
+Printer& Printer::Println(StringPiece str) {
   Print(str);
   return Print("\n");
 }
@@ -35,7 +35,7 @@
   return Print("\n");
 }
 
-Printer& Printer::Print(const StringPiece& str) {
+Printer& Printer::Print(StringPiece str) {
   if (error_) {
     return *this;
   }
@@ -47,7 +47,7 @@
     const auto new_line_iter = std::find(remaining_str_begin, remaining_str_end, '\n');
 
     // We will copy the string up until the next new-line (or end of string).
-    const StringPiece str_to_copy = str.substr(remaining_str_begin, new_line_iter);
+    const StringPiece str_to_copy(remaining_str_begin, new_line_iter - remaining_str_begin);
     if (!str_to_copy.empty()) {
       if (needs_indent_) {
         for (int i = 0; i < indent_level_; i++) {
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
index f399f8e..f7ad98b 100644
--- a/tools/aapt2/text/Printer.h
+++ b/tools/aapt2/text/Printer.h
@@ -31,8 +31,8 @@
   explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
   }
 
-  Printer& Print(const ::android::StringPiece& str);
-  Printer& Println(const ::android::StringPiece& str);
+  Printer& Print(android::StringPiece str);
+  Printer& Println(android::StringPiece str);
   Printer& Println();
 
   void Indent();
diff --git a/tools/aapt2/text/Unicode.cpp b/tools/aapt2/text/Unicode.cpp
index 3735b3e..5e25be3 100644
--- a/tools/aapt2/text/Unicode.cpp
+++ b/tools/aapt2/text/Unicode.cpp
@@ -77,7 +77,7 @@
          (codepoint == 0x3000);
 }
 
-bool IsJavaIdentifier(const StringPiece& str) {
+bool IsJavaIdentifier(StringPiece str) {
   Utf8Iterator iter(str);
 
   // Check the first character.
@@ -99,7 +99,7 @@
   return true;
 }
 
-bool IsValidResourceEntryName(const StringPiece& str) {
+bool IsValidResourceEntryName(StringPiece str) {
   Utf8Iterator iter(str);
 
   // Check the first character.
diff --git a/tools/aapt2/text/Unicode.h b/tools/aapt2/text/Unicode.h
index 546714e..ab3e82b 100644
--- a/tools/aapt2/text/Unicode.h
+++ b/tools/aapt2/text/Unicode.h
@@ -46,11 +46,11 @@
 
 // Returns true if the UTF8 string can be used as a Java identifier.
 // NOTE: This does not check against the set of reserved Java keywords.
-bool IsJavaIdentifier(const android::StringPiece& str);
+bool IsJavaIdentifier(android::StringPiece str);
 
 // Returns true if the UTF8 string can be used as the entry name of a resource name.
 // This is the `entry` part of package:type/entry.
-bool IsValidResourceEntryName(const android::StringPiece& str);
+bool IsValidResourceEntryName(android::StringPiece str);
 
 }  // namespace text
 }  // namespace aapt
diff --git a/tools/aapt2/text/Utf8Iterator.cpp b/tools/aapt2/text/Utf8Iterator.cpp
index 20b9073..0bd8a37 100644
--- a/tools/aapt2/text/Utf8Iterator.cpp
+++ b/tools/aapt2/text/Utf8Iterator.cpp
@@ -24,7 +24,7 @@
 namespace aapt {
 namespace text {
 
-Utf8Iterator::Utf8Iterator(const StringPiece& str)
+Utf8Iterator::Utf8Iterator(StringPiece str)
     : str_(str), current_pos_(0), next_pos_(0), current_codepoint_(0) {
   DoNext();
 }
diff --git a/tools/aapt2/text/Utf8Iterator.h b/tools/aapt2/text/Utf8Iterator.h
index 9318401..2bba198 100644
--- a/tools/aapt2/text/Utf8Iterator.h
+++ b/tools/aapt2/text/Utf8Iterator.h
@@ -25,7 +25,7 @@
 
 class Utf8Iterator {
  public:
-  explicit Utf8Iterator(const android::StringPiece& str);
+  explicit Utf8Iterator(android::StringPiece str);
 
   bool HasNext() const;
 
diff --git a/tools/aapt2/trace/TraceBuffer.cpp b/tools/aapt2/trace/TraceBuffer.cpp
index b4b31d9..da53739 100644
--- a/tools/aapt2/trace/TraceBuffer.cpp
+++ b/tools/aapt2/trace/TraceBuffer.cpp
@@ -103,7 +103,7 @@
   s << tag;
   s << " ";
   for (auto& arg : args) {
-    s << arg.to_string();
+    s << arg;
     s << " ";
   }
   tracebuffer::Add(s.str(), tracebuffer::kBegin);
@@ -124,7 +124,7 @@
   s << tag;
   s << " ";
   for (auto& arg : args) {
-    s << arg.to_string();
+    s << arg;
     s << " ";
   }
   tracebuffer::Add(s.str(), tracebuffer::kBegin);
diff --git a/tools/aapt2/util/Files.cpp b/tools/aapt2/util/Files.cpp
index 5d5b7cd..93c1b61 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -139,7 +139,7 @@
   return ::android::base::utf8::mkdir(path.c_str(), mode) == 0 || errno == EEXIST;
 }
 
-StringPiece GetStem(const StringPiece& path) {
+StringPiece GetStem(StringPiece path) {
   const char* start = path.begin();
   const char* end = path.end();
   for (const char* current = end - 1; current != start - 1; --current) {
@@ -150,7 +150,7 @@
   return {};
 }
 
-StringPiece GetFilename(const StringPiece& path) {
+StringPiece GetFilename(StringPiece path) {
   const char* end = path.end();
   const char* last_dir_sep = path.begin();
   for (const char* c = path.begin(); c != end; ++c) {
@@ -161,7 +161,7 @@
   return StringPiece(last_dir_sep, end - last_dir_sep);
 }
 
-StringPiece GetExtension(const StringPiece& path) {
+StringPiece GetExtension(StringPiece path) {
   StringPiece filename = GetFilename(path);
   const char* const end = filename.end();
   const char* c = std::find(filename.begin(), end, '.');
@@ -171,7 +171,7 @@
   return {};
 }
 
-bool IsHidden(const android::StringPiece& path) {
+bool IsHidden(android::StringPiece path) {
   return util::StartsWith(GetFilename(path), ".");
 }
 
@@ -193,16 +193,16 @@
   if (args.empty()) {
     return "";
   }
-  std::string out = args[0].to_string();
+  std::string out{args[0]};
   for (int i = 1; i < args.size(); i++) {
     file::AppendPath(&out, args[i]);
   }
   return out;
 }
 
-std::string PackageToPath(const StringPiece& package) {
+std::string PackageToPath(StringPiece package) {
   std::string out_path;
-  for (const StringPiece& part : util::Tokenize(package, '.')) {
+  for (StringPiece part : util::Tokenize(package, '.')) {
     AppendPath(&out_path, part);
   }
   return out_path;
@@ -241,10 +241,10 @@
   return std::move(filemap);
 }
 
-bool AppendArgsFromFile(const StringPiece& path, std::vector<std::string>* out_arglist,
+bool AppendArgsFromFile(StringPiece path, std::vector<std::string>* out_arglist,
                         std::string* out_error) {
   std::string contents;
-  if (!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
+  if (!ReadFileToString(std::string(path), &contents, true /*follow_symlinks*/)) {
     if (out_error) {
       *out_error = "failed to read argument-list file";
     }
@@ -254,16 +254,16 @@
   for (StringPiece line : util::Tokenize(contents, ' ')) {
     line = util::TrimWhitespace(line);
     if (!line.empty()) {
-      out_arglist->push_back(line.to_string());
+      out_arglist->emplace_back(line);
     }
   }
   return true;
 }
 
-bool AppendSetArgsFromFile(const StringPiece& path, std::unordered_set<std::string>* out_argset,
+bool AppendSetArgsFromFile(StringPiece path, std::unordered_set<std::string>* out_argset,
                            std::string* out_error) {
   std::string contents;
-  if(!ReadFileToString(path.to_string(), &contents, true /*follow_symlinks*/)) {
+  if (!ReadFileToString(std::string(path), &contents, true /*follow_symlinks*/)) {
     if (out_error) {
       *out_error = "failed to read argument-list file";
     }
@@ -273,13 +273,13 @@
   for (StringPiece line : util::Tokenize(contents, ' ')) {
     line = util::TrimWhitespace(line);
     if (!line.empty()) {
-      out_argset->insert(line.to_string());
+      out_argset->emplace(line);
     }
   }
   return true;
 }
 
-bool FileFilter::SetPattern(const StringPiece& pattern) {
+bool FileFilter::SetPattern(StringPiece pattern) {
   pattern_tokens_ = util::SplitAndLowercase(pattern, ':');
   return true;
 }
@@ -343,10 +343,10 @@
   return true;
 }
 
-std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
+std::optional<std::vector<std::string>> FindFiles(android::StringPiece path,
                                                   android::IDiagnostics* diag,
                                                   const FileFilter* filter) {
-  const std::string root_dir = path.to_string();
+  const auto& root_dir = path;
   std::unique_ptr<DIR, decltype(closedir)*> d(opendir(root_dir.data()), closedir);
   if (!d) {
     diag->Error(android::DiagMessage() << SystemErrorCodeToString(errno) << ": " << root_dir);
@@ -361,7 +361,7 @@
     }
 
     std::string file_name = entry->d_name;
-    std::string full_path = root_dir;
+    std::string full_path{root_dir};
     AppendPath(&full_path, file_name);
     const FileType file_type = GetFileType(full_path);
 
@@ -380,7 +380,7 @@
 
   // Now process subdirs.
   for (const std::string& subdir : subdirs) {
-    std::string full_subdir = root_dir;
+    std::string full_subdir{root_dir};
     AppendPath(&full_subdir, subdir);
     std::optional<std::vector<std::string>> subfiles = FindFiles(full_subdir, diag, filter);
     if (!subfiles) {
diff --git a/tools/aapt2/util/Files.h b/tools/aapt2/util/Files.h
index ee95712..42eeaf2 100644
--- a/tools/aapt2/util/Files.h
+++ b/tools/aapt2/util/Files.h
@@ -66,31 +66,31 @@
 bool mkdirs(const std::string& path);
 
 // Returns all but the last part of the path.
-android::StringPiece GetStem(const android::StringPiece& path);
+android::StringPiece GetStem(android::StringPiece path);
 
 // Returns the last part of the path with extension.
-android::StringPiece GetFilename(const android::StringPiece& path);
+android::StringPiece GetFilename(android::StringPiece path);
 
 // Returns the extension of the path. This is the entire string after the first '.' of the last part
 // of the path.
-android::StringPiece GetExtension(const android::StringPiece& path);
+android::StringPiece GetExtension(android::StringPiece path);
 
 // Returns whether or not the name of the file or directory is a hidden file name
-bool IsHidden(const android::StringPiece& path);
+bool IsHidden(android::StringPiece path);
 
 // Converts a package name (com.android.app) to a path: com/android/app
-std::string PackageToPath(const android::StringPiece& package);
+std::string PackageToPath(android::StringPiece package);
 
 // Creates a FileMap for the file at path.
 std::optional<android::FileMap> MmapPath(const std::string& path, std::string* out_error);
 
 // Reads the file at path and appends each line to the outArgList vector.
-bool AppendArgsFromFile(const android::StringPiece& path, std::vector<std::string>* out_arglist,
+bool AppendArgsFromFile(android::StringPiece path, std::vector<std::string>* out_arglist,
                         std::string* out_error);
 
 // Reads the file at path and appends each line to the outargset set.
-bool AppendSetArgsFromFile(const android::StringPiece& path,
-                        std::unordered_set<std::string>* out_argset, std::string* out_error);
+bool AppendSetArgsFromFile(android::StringPiece path, std::unordered_set<std::string>* out_argset,
+                           std::string* out_error);
 
 // Filter that determines which resource files/directories are
 // processed by AAPT. Takes a pattern string supplied by the user.
@@ -112,7 +112,7 @@
   // - The special filenames "." and ".." are always ignored.
   // - Otherwise the full string is matched.
   // - match is not case-sensitive.
-  bool SetPattern(const android::StringPiece& pattern);
+  bool SetPattern(android::StringPiece pattern);
 
   // Applies the filter, returning true for pass, false for fail.
   bool operator()(const std::string& filename, FileType type) const;
@@ -126,7 +126,7 @@
 
 // Returns a list of files relative to the directory identified by `path`.
 // An optional FileFilter filters out any files that don't pass.
-std::optional<std::vector<std::string>> FindFiles(const android::StringPiece& path,
+std::optional<std::vector<std::string>> FindFiles(android::StringPiece path,
                                                   android::IDiagnostics* diag,
                                                   const FileFilter* filter = nullptr);
 
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index 9b7ebdd..be87766 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -43,15 +43,14 @@
 // See frameworks/base/core/java/android/content/pm/parsing/ParsingPackageUtils.java
 constexpr static const size_t kMaxPackageNameSize = 223;
 
-static std::vector<std::string> SplitAndTransform(
-    const StringPiece& str, char sep, const std::function<char(char)>& f) {
+static std::vector<std::string> SplitAndTransform(StringPiece str, char sep, char (*f)(char)) {
   std::vector<std::string> parts;
   const StringPiece::const_iterator end = std::end(str);
   StringPiece::const_iterator start = std::begin(str);
   StringPiece::const_iterator current;
   do {
     current = std::find(start, end, sep);
-    parts.emplace_back(str.substr(start, current).to_string());
+    parts.emplace_back(start, current);
     if (f) {
       std::string& part = parts.back();
       std::transform(part.begin(), part.end(), part.begin(), f);
@@ -61,29 +60,29 @@
   return parts;
 }
 
-std::vector<std::string> Split(const StringPiece& str, char sep) {
+std::vector<std::string> Split(StringPiece str, char sep) {
   return SplitAndTransform(str, sep, nullptr);
 }
 
-std::vector<std::string> SplitAndLowercase(const StringPiece& str, char sep) {
-  return SplitAndTransform(str, sep, ::tolower);
+std::vector<std::string> SplitAndLowercase(StringPiece str, char sep) {
+  return SplitAndTransform(str, sep, [](char c) -> char { return ::tolower(c); });
 }
 
-bool StartsWith(const StringPiece& str, const StringPiece& prefix) {
+bool StartsWith(StringPiece str, StringPiece prefix) {
   if (str.size() < prefix.size()) {
     return false;
   }
   return str.substr(0, prefix.size()) == prefix;
 }
 
-bool EndsWith(const StringPiece& str, const StringPiece& suffix) {
+bool EndsWith(StringPiece str, StringPiece suffix) {
   if (str.size() < suffix.size()) {
     return false;
   }
   return str.substr(str.size() - suffix.size(), suffix.size()) == suffix;
 }
 
-StringPiece TrimLeadingWhitespace(const StringPiece& str) {
+StringPiece TrimLeadingWhitespace(StringPiece str) {
   if (str.size() == 0 || str.data() == nullptr) {
     return str;
   }
@@ -97,7 +96,7 @@
   return StringPiece(start, end - start);
 }
 
-StringPiece TrimTrailingWhitespace(const StringPiece& str) {
+StringPiece TrimTrailingWhitespace(StringPiece str) {
   if (str.size() == 0 || str.data() == nullptr) {
     return str;
   }
@@ -111,7 +110,7 @@
   return StringPiece(start, end - start);
 }
 
-StringPiece TrimWhitespace(const StringPiece& str) {
+StringPiece TrimWhitespace(StringPiece str) {
   if (str.size() == 0 || str.data() == nullptr) {
     return str;
   }
@@ -130,9 +129,9 @@
   return StringPiece(start, end - start);
 }
 
-static int IsJavaNameImpl(const StringPiece& str) {
+static int IsJavaNameImpl(StringPiece str) {
   int pieces = 0;
-  for (const StringPiece& piece : Tokenize(str, '.')) {
+  for (StringPiece piece : Tokenize(str, '.')) {
     pieces++;
     if (!text::IsJavaIdentifier(piece)) {
       return -1;
@@ -141,17 +140,17 @@
   return pieces;
 }
 
-bool IsJavaClassName(const StringPiece& str) {
+bool IsJavaClassName(StringPiece str) {
   return IsJavaNameImpl(str) >= 2;
 }
 
-bool IsJavaPackageName(const StringPiece& str) {
+bool IsJavaPackageName(StringPiece str) {
   return IsJavaNameImpl(str) >= 1;
 }
 
-static int IsAndroidNameImpl(const StringPiece& str) {
+static int IsAndroidNameImpl(StringPiece str) {
   int pieces = 0;
-  for (const StringPiece& piece : Tokenize(str, '.')) {
+  for (StringPiece piece : Tokenize(str, '.')) {
     if (piece.empty()) {
       return -1;
     }
@@ -173,15 +172,14 @@
   return pieces;
 }
 
-bool IsAndroidPackageName(const StringPiece& str) {
+bool IsAndroidPackageName(StringPiece str) {
   if (str.size() > kMaxPackageNameSize) {
     return false;
   }
   return IsAndroidNameImpl(str) > 1 || str == "android";
 }
 
-bool IsAndroidSharedUserId(const android::StringPiece& package_name,
-                           const android::StringPiece& shared_user_id) {
+bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id) {
   if (shared_user_id.size() > kMaxPackageNameSize) {
     return false;
   }
@@ -189,25 +187,24 @@
          package_name == "android";
 }
 
-bool IsAndroidSplitName(const StringPiece& str) {
+bool IsAndroidSplitName(StringPiece str) {
   return IsAndroidNameImpl(str) > 0;
 }
 
-std::optional<std::string> GetFullyQualifiedClassName(const StringPiece& package,
-                                                      const StringPiece& classname) {
+std::optional<std::string> GetFullyQualifiedClassName(StringPiece package, StringPiece classname) {
   if (classname.empty()) {
     return {};
   }
 
   if (util::IsJavaClassName(classname)) {
-    return classname.to_string();
+    return std::string(classname);
   }
 
   if (package.empty()) {
     return {};
   }
 
-  std::string result = package.to_string();
+  std::string result{package};
   if (classname.data()[0] != '.') {
     result += '.';
   }
@@ -251,7 +248,7 @@
   return static_cast<size_t>(c - start);
 }
 
-bool VerifyJavaStringFormat(const StringPiece& str) {
+bool VerifyJavaStringFormat(StringPiece str) {
   const char* c = str.begin();
   const char* const end = str.end();
 
@@ -341,7 +338,7 @@
   return true;
 }
 
-std::u16string Utf8ToUtf16(const StringPiece& utf8) {
+std::u16string Utf8ToUtf16(StringPiece utf8) {
   ssize_t utf16_length = utf8_to_utf16_length(
       reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
   if (utf16_length <= 0) {
@@ -381,7 +378,7 @@
   const char* end = str_.end();
   if (start == end) {
     end_ = true;
-    token_.assign(token_.end(), 0);
+    token_ = StringPiece(token_.end(), 0);
     return *this;
   }
 
@@ -389,12 +386,12 @@
   const char* current = start;
   while (current != end) {
     if (*current == separator_) {
-      token_.assign(start, current - start);
+      token_ = StringPiece(start, current - start);
       return *this;
     }
     ++current;
   }
-  token_.assign(start, end - start);
+  token_ = StringPiece(start, end - start);
   return *this;
 }
 
@@ -409,15 +406,17 @@
   return !(*this == rhs);
 }
 
-Tokenizer::iterator::iterator(const StringPiece& s, char sep, const StringPiece& tok, bool end)
-    : str_(s), separator_(sep), token_(tok), end_(end) {}
+Tokenizer::iterator::iterator(StringPiece s, char sep, StringPiece tok, bool end)
+    : str_(s), separator_(sep), token_(tok), end_(end) {
+}
 
-Tokenizer::Tokenizer(const StringPiece& str, char sep)
+Tokenizer::Tokenizer(StringPiece str, char sep)
     : begin_(++iterator(str, sep, StringPiece(str.begin() - 1, 0), false)),
-      end_(str, sep, StringPiece(str.end(), 0), true) {}
+      end_(str, sep, StringPiece(str.end(), 0), true) {
+}
 
-bool ExtractResFilePathParts(const StringPiece& path, StringPiece* out_prefix,
-                             StringPiece* out_entry, StringPiece* out_suffix) {
+bool ExtractResFilePathParts(StringPiece path, StringPiece* out_prefix, StringPiece* out_entry,
+                             StringPiece* out_suffix) {
   const StringPiece res_prefix("res/");
   if (!StartsWith(path, res_prefix)) {
     return false;
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index 8d3b413..40ff5b6 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -48,44 +48,44 @@
   T end;
 };
 
-std::vector<std::string> Split(const android::StringPiece& str, char sep);
-std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
+std::vector<std::string> Split(android::StringPiece str, char sep);
+std::vector<std::string> SplitAndLowercase(android::StringPiece str, char sep);
 
 // Returns true if the string starts with prefix.
-bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
+bool StartsWith(android::StringPiece str, android::StringPiece prefix);
 
 // Returns true if the string ends with suffix.
-bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
+bool EndsWith(android::StringPiece str, android::StringPiece suffix);
 
 // Creates a new StringPiece that points to a substring of the original string without leading
 // whitespace.
-android::StringPiece TrimLeadingWhitespace(const android::StringPiece& str);
+android::StringPiece TrimLeadingWhitespace(android::StringPiece str);
 
 // Creates a new StringPiece that points to a substring of the original string without trailing
 // whitespace.
-android::StringPiece TrimTrailingWhitespace(const android::StringPiece& str);
+android::StringPiece TrimTrailingWhitespace(android::StringPiece str);
 
 // Creates a new StringPiece that points to a substring of the original string without leading or
 // trailing whitespace.
-android::StringPiece TrimWhitespace(const android::StringPiece& str);
+android::StringPiece TrimWhitespace(android::StringPiece str);
 
 // Tests that the string is a valid Java class name.
-bool IsJavaClassName(const android::StringPiece& str);
+bool IsJavaClassName(android::StringPiece str);
 
 // Tests that the string is a valid Java package name.
-bool IsJavaPackageName(const android::StringPiece& str);
+bool IsJavaPackageName(android::StringPiece str);
 
 // Tests that the string is a valid Android package name. More strict than a Java package name.
 // - First character of each component (separated by '.') must be an ASCII letter.
 // - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
 // - Package must contain at least two components, unless it is 'android'.
 // - The maximum package name length is 223.
-bool IsAndroidPackageName(const android::StringPiece& str);
+bool IsAndroidPackageName(android::StringPiece str);
 
 // Tests that the string is a valid Android split name.
 // - First character of each component (separated by '.') must be an ASCII letter.
 // - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
-bool IsAndroidSplitName(const android::StringPiece& str);
+bool IsAndroidSplitName(android::StringPiece str);
 
 // Tests that the string is a valid Android shared user id.
 // - First character of each component (separated by '.') must be an ASCII letter.
@@ -93,8 +93,7 @@
 // - Must contain at least two components, unless package name is 'android'.
 // - The maximum shared user id length is 223.
 // - Treat empty string as valid, it's the case of no shared user id.
-bool IsAndroidSharedUserId(const android::StringPiece& package_name,
-                           const android::StringPiece& shared_user_id);
+bool IsAndroidSharedUserId(android::StringPiece package_name, android::StringPiece shared_user_id);
 
 // Converts the class name to a fully qualified class name from the given
 // `package`. Ex:
@@ -103,8 +102,8 @@
 // .asdf        --> package.asdf
 // .a.b         --> package.a.b
 // asdf.adsf    --> asdf.adsf
-std::optional<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
-                                                      const android::StringPiece& class_name);
+std::optional<std::string> GetFullyQualifiedClassName(android::StringPiece package,
+                                                      android::StringPiece class_name);
 
 // Retrieves the formatted name of aapt2.
 const char* GetToolName();
@@ -152,16 +151,16 @@
 // explicitly specifying an index) when there are more than one argument. This is an error
 // because translations may rearrange the order of the arguments in the string, which will
 // break the string interpolation.
-bool VerifyJavaStringFormat(const android::StringPiece& str);
+bool VerifyJavaStringFormat(android::StringPiece str);
 
-bool AppendStyledString(const android::StringPiece& input, bool preserve_spaces,
-                        std::string* out_str, std::string* out_error);
+bool AppendStyledString(android::StringPiece input, bool preserve_spaces, std::string* out_str,
+                        std::string* out_error);
 
 class StringBuilder {
  public:
   StringBuilder() = default;
 
-  StringBuilder& Append(const android::StringPiece& str);
+  StringBuilder& Append(android::StringPiece str);
   const std::string& ToString() const;
   const std::string& Error() const;
   bool IsEmpty() const;
@@ -229,7 +228,7 @@
    private:
     friend class Tokenizer;
 
-    iterator(const android::StringPiece& s, char sep, const android::StringPiece& tok, bool end);
+    iterator(android::StringPiece s, char sep, android::StringPiece tok, bool end);
 
     android::StringPiece str_;
     char separator_;
@@ -237,7 +236,7 @@
     bool end_;
   };
 
-  Tokenizer(const android::StringPiece& str, char sep);
+  Tokenizer(android::StringPiece str, char sep);
 
   iterator begin() const {
     return begin_;
@@ -252,7 +251,7 @@
   const iterator end_;
 };
 
-inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
+inline Tokenizer Tokenize(android::StringPiece str, char sep) {
   return Tokenizer(str, sep);
 }
 
@@ -263,7 +262,7 @@
 // Extracts ".xml" into outSuffix.
 //
 // Returns true if successful.
-bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
+bool ExtractResFilePathParts(android::StringPiece path, android::StringPiece* out_prefix,
                              android::StringPiece* out_entry, android::StringPiece* out_suffix);
 
 }  // namespace util
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index 4ebcb11..15135690 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -84,6 +84,14 @@
   ASSERT_THAT(*iter, Eq(StringPiece()));
 }
 
+TEST(UtilTest, TokenizeNone) {
+  auto tokenizer = util::Tokenize(StringPiece("none"), '.');
+  auto iter = tokenizer.begin();
+  ASSERT_THAT(*iter, Eq("none"));
+  ++iter;
+  ASSERT_THAT(iter, Eq(tokenizer.end()));
+}
+
 TEST(UtilTest, IsJavaClassName) {
   EXPECT_TRUE(util::IsJavaClassName("android.test.Class"));
   EXPECT_TRUE(util::IsJavaClassName("android.test.Class$Inner"));
diff --git a/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index 9bdbd22..3ccbaa2 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -84,7 +84,7 @@
         error_msg << "unexpected element ";
         PrintElementToDiagMessage(child_el, &error_msg);
         error_msg << " found in ";
-        for (const StringPiece& element : *bread_crumb) {
+        for (StringPiece element : *bread_crumb) {
           error_msg << "<" << element << ">";
         }
         if (policy == XmlActionExecutorPolicy::kAllowListWarning) {
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index f51e8a4..8dea8ea 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -169,7 +169,7 @@
   stack->last_text_node = util::make_unique<Text>();
   stack->last_text_node->line_number = XML_GetCurrentLineNumber(parser);
   stack->last_text_node->column_number = XML_GetCurrentColumnNumber(parser);
-  stack->last_text_node->text = str.to_string();
+  stack->last_text_node->text.assign(str);
 }
 
 static void XMLCALL CommentDataHandler(void* user_data, const char* comment) {
@@ -417,11 +417,11 @@
   children.insert(children.begin() + index, std::move(child));
 }
 
-Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
+Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) {
   return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
 }
 
-const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
+const Attribute* Element::FindAttribute(StringPiece ns, StringPiece name) const {
   for (const auto& attr : attributes) {
     if (ns == attr.namespace_uri && name == attr.name) {
       return &attr;
@@ -430,7 +430,7 @@
   return nullptr;
 }
 
-void Element::RemoveAttribute(const StringPiece& ns, const StringPiece& name) {
+void Element::RemoveAttribute(StringPiece ns, StringPiece name) {
   auto new_attr_end = std::remove_if(attributes.begin(), attributes.end(),
     [&](const Attribute& attr) -> bool {
       return ns == attr.namespace_uri && name == attr.name;
@@ -439,34 +439,32 @@
   attributes.erase(new_attr_end, attributes.end());
 }
 
-Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
+Attribute* Element::FindOrCreateAttribute(StringPiece ns, StringPiece name) {
   Attribute* attr = FindAttribute(ns, name);
   if (attr == nullptr) {
-    attributes.push_back(Attribute{ns.to_string(), name.to_string()});
+    attributes.push_back(Attribute{std::string(ns), std::string(name)});
     attr = &attributes.back();
   }
   return attr;
 }
 
-Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
+Element* Element::FindChild(StringPiece ns, StringPiece name) {
   return FindChildWithAttribute(ns, name, {}, {}, {});
 }
 
-const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
+const Element* Element::FindChild(StringPiece ns, StringPiece name) const {
   return FindChildWithAttribute(ns, name, {}, {}, {});
 }
 
-Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
-                                         const StringPiece& attr_ns, const StringPiece& attr_name,
-                                         const StringPiece& attr_value) {
+Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name, StringPiece attr_ns,
+                                         StringPiece attr_name, StringPiece attr_value) {
   return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
       ns, name, attr_ns, attr_name, attr_value));
 }
 
-const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
-                                               const StringPiece& attr_ns,
-                                               const StringPiece& attr_name,
-                                               const StringPiece& attr_value) const {
+const Element* Element::FindChildWithAttribute(StringPiece ns, StringPiece name,
+                                               StringPiece attr_ns, StringPiece attr_name,
+                                               StringPiece attr_value) const {
   for (const auto& child : children) {
     if (const Element* el = NodeCast<Element>(child.get())) {
       if (ns == el->namespace_uri && name == el->name) {
@@ -559,7 +557,7 @@
 }
 
 std::optional<ExtractedPackage> PackageAwareVisitor::TransformPackageAlias(
-    const StringPiece& alias) const {
+    StringPiece alias) const {
   if (alias.empty()) {
     return ExtractedPackage{{}, false /*private*/};
   }
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 5bc55b6..c253b0a 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -96,27 +96,22 @@
   void AppendChild(std::unique_ptr<Node> child);
   void InsertChild(size_t index, std::unique_ptr<Node> child);
 
-  Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
-  const Attribute* FindAttribute(const android::StringPiece& ns,
-                                 const android::StringPiece& name) const;
-  Attribute* FindOrCreateAttribute(const android::StringPiece& ns,
-                                   const android::StringPiece& name);
-  void RemoveAttribute(const android::StringPiece& ns,
-                       const android::StringPiece& name);
+  Attribute* FindAttribute(android::StringPiece ns, android::StringPiece name);
+  const Attribute* FindAttribute(android::StringPiece ns, android::StringPiece name) const;
+  Attribute* FindOrCreateAttribute(android::StringPiece ns, android::StringPiece name);
+  void RemoveAttribute(android::StringPiece ns, android::StringPiece name);
 
-  Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
-  const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
+  Element* FindChild(android::StringPiece ns, android::StringPiece name);
+  const Element* FindChild(android::StringPiece ns, android::StringPiece name) const;
 
-  Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
-                                  const android::StringPiece& attr_ns,
-                                  const android::StringPiece& attr_name,
-                                  const android::StringPiece& attr_value);
+  Element* FindChildWithAttribute(android::StringPiece ns, android::StringPiece name,
+                                  android::StringPiece attr_ns, android::StringPiece attr_name,
+                                  android::StringPiece attr_value);
 
-  const Element* FindChildWithAttribute(const android::StringPiece& ns,
-                                        const android::StringPiece& name,
-                                        const android::StringPiece& attr_ns,
-                                        const android::StringPiece& attr_name,
-                                        const android::StringPiece& attr_value) const;
+  const Element* FindChildWithAttribute(android::StringPiece ns, android::StringPiece name,
+                                        android::StringPiece attr_ns,
+                                        android::StringPiece attr_name,
+                                        android::StringPiece attr_value) const;
 
   std::vector<Element*> GetChildElements();
 
@@ -235,8 +230,7 @@
  public:
   using Visitor::Visit;
 
-  std::optional<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias) const override;
+  std::optional<ExtractedPackage> TransformPackageAlias(android::StringPiece alias) const override;
 
  protected:
   PackageAwareVisitor() = default;
diff --git a/tools/aapt2/xml/XmlPullParser.cpp b/tools/aapt2/xml/XmlPullParser.cpp
index bfa0749..d79446b 100644
--- a/tools/aapt2/xml/XmlPullParser.cpp
+++ b/tools/aapt2/xml/XmlPullParser.cpp
@@ -140,8 +140,7 @@
   return event_queue_.front().data2;
 }
 
-std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(
-    const StringPiece& alias) const {
+std::optional<ExtractedPackage> XmlPullParser::TransformPackageAlias(StringPiece alias) const {
   if (alias.empty()) {
     return ExtractedPackage{{}, false /*private*/};
   }
@@ -307,7 +306,7 @@
                                       parser->depth_ });
 }
 
-std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, const StringPiece& name) {
+std::optional<StringPiece> FindAttribute(const XmlPullParser* parser, StringPiece name) {
   auto iter = parser->FindAttribute("", name);
   if (iter != parser->end_attributes()) {
     return StringPiece(util::TrimWhitespace(iter->value));
@@ -315,8 +314,7 @@
   return {};
 }
 
-std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
-                                                 const StringPiece& name) {
+std::optional<StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser, StringPiece name) {
   auto iter = parser->FindAttribute("", name);
   if (iter != parser->end_attributes()) {
     StringPiece trimmed = util::TrimWhitespace(iter->value);
diff --git a/tools/aapt2/xml/XmlPullParser.h b/tools/aapt2/xml/XmlPullParser.h
index ab34772..fe4cd01 100644
--- a/tools/aapt2/xml/XmlPullParser.h
+++ b/tools/aapt2/xml/XmlPullParser.h
@@ -120,8 +120,7 @@
    * If xmlns:app="http://schemas.android.com/apk/res-auto", then
    * 'package' will be set to 'defaultPackage'.
    */
-  std::optional<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias) const override;
+  std::optional<ExtractedPackage> TransformPackageAlias(android::StringPiece alias) const override;
 
   struct PackageDecl {
     std::string prefix;
@@ -194,7 +193,7 @@
  * Finds the attribute in the current element within the global namespace.
  */
 std::optional<android::StringPiece> FindAttribute(const XmlPullParser* parser,
-                                                  const android::StringPiece& name);
+                                                  android::StringPiece name);
 
 /**
  * Finds the attribute in the current element within the global namespace. The
@@ -202,7 +201,7 @@
  * must not be the empty string.
  */
 std::optional<android::StringPiece> FindNonEmptyAttribute(const XmlPullParser* parser,
-                                                          const android::StringPiece& name);
+                                                          android::StringPiece name);
 
 //
 // Implementation
diff --git a/tools/aapt2/xml/XmlUtil.cpp b/tools/aapt2/xml/XmlUtil.cpp
index 114b5ba..709755e 100644
--- a/tools/aapt2/xml/XmlUtil.cpp
+++ b/tools/aapt2/xml/XmlUtil.cpp
@@ -27,7 +27,7 @@
 namespace aapt {
 namespace xml {
 
-std::string BuildPackageNamespace(const StringPiece& package, bool private_reference) {
+std::string BuildPackageNamespace(StringPiece package, bool private_reference) {
   std::string result = private_reference ? kSchemaPrivatePrefix : kSchemaPublicPrefix;
   result.append(package.data(), package.size());
   return result;
@@ -41,7 +41,7 @@
     if (package.empty()) {
       return {};
     }
-    return ExtractedPackage{package.to_string(), false /* is_private */};
+    return ExtractedPackage{std::string(package), false /* is_private */};
 
   } else if (util::StartsWith(namespace_uri, kSchemaPrivatePrefix)) {
     StringPiece schema_prefix = kSchemaPrivatePrefix;
@@ -50,7 +50,7 @@
     if (package.empty()) {
       return {};
     }
-    return ExtractedPackage{package.to_string(), true /* is_private */};
+    return ExtractedPackage{std::string(package), true /* is_private */};
 
   } else if (namespace_uri == kSchemaAuto) {
     return ExtractedPackage{std::string(), true /* is_private */};
diff --git a/tools/aapt2/xml/XmlUtil.h b/tools/aapt2/xml/XmlUtil.h
index 1ab05a9..ad676ca 100644
--- a/tools/aapt2/xml/XmlUtil.h
+++ b/tools/aapt2/xml/XmlUtil.h
@@ -59,8 +59,7 @@
 //
 // If privateReference == true, the package will be of the form:
 //   http://schemas.android.com/apk/prv/res/<package>
-std::string BuildPackageNamespace(const android::StringPiece& package,
-                                  bool private_reference = false);
+std::string BuildPackageNamespace(android::StringPiece package, bool private_reference = false);
 
 // Interface representing a stack of XML namespace declarations. When looking up the package for a
 // namespace prefix, the stack is checked from top to bottom.
@@ -69,7 +68,7 @@
 
   // Returns an ExtractedPackage struct if the alias given corresponds with a package declaration.
   virtual std::optional<ExtractedPackage> TransformPackageAlias(
-      const android::StringPiece& alias) const = 0;
+      android::StringPiece alias) const = 0;
 };
 
 // Helper function for transforming the original Reference inRef to a fully qualified reference
diff --git a/tools/fonts/font-scaling-array-generator.js b/tools/fonts/font-scaling-array-generator.js
new file mode 100644
index 0000000..9754697
--- /dev/null
+++ b/tools/fonts/font-scaling-array-generator.js
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+  Generates arrays for non-linear font scaling, to be pasted into
+  frameworks/base/core/java/android/content/res/FontScaleConverterFactory.java
+
+  To use:
+    `node font-scaling-array-generator.js`
+    or just open a browser, open DevTools, and paste into the Console.
+*/
+
+/**
+ * Modify this to match your packages/apps/Settings/res/arrays.xml#entryvalues_font_size
+ * array so that all possible scales are generated.
+ */
+const scales = [1.15, 1.30, 1.5, 1.8, 2];
+
+const commonSpSizes = [8, 10, 12, 14, 18, 20, 24, 30, 100];
+
+/**
+ * Enum for GENERATION_STYLE which determines how to generate the arrays.
+ */
+const GenerationStyle = {
+  /**
+   * Interpolates between hand-tweaked curves. This is the best option and
+   * shouldn't require any additional tweaking.
+   */
+  CUSTOM_TWEAKED: 'CUSTOM_TWEAKED',
+
+  /**
+   * Uses a curve equation that is mostly correct, but will need manual tweaking
+   * at some scales.
+   */
+  CURVE: 'CURVE',
+
+  /**
+   * Uses straight linear multiplication. Good starting point for manual
+   * tweaking.
+   */
+  LINEAR: 'LINEAR'
+}
+
+/**
+ * Determines how arrays are generated. Must be one of the GenerationStyle
+ * values.
+ */
+const GENERATION_STYLE = GenerationStyle.CUSTOM_TWEAKED;
+
+// These are hand-tweaked curves from which we will derive the other
+// interstitial curves using linear interpolation, in the case of using
+// GenerationStyle.CUSTOM_TWEAKED.
+const interpolationTargets = {
+  1.0: commonSpSizes,
+  1.5: [12, 15, 18, 22, 24, 26, 28, 30, 100],
+  2.0: [16, 20, 24, 26, 30, 34, 36, 38, 100]
+};
+
+/**
+ * Interpolate a value with specified extrema, to a new value between new
+ * extrema.
+ *
+ * @param value the current value
+ * @param inputMin minimum the input value can reach
+ * @param inputMax maximum the input value can reach
+ * @param outputMin minimum the output value can reach
+ * @param outputMax maximum the output value can reach
+ */
+function map(value, inputMin, inputMax, outputMin, outputMax) {
+  return outputMin + (outputMax - outputMin) * ((value - inputMin) / (inputMax - inputMin));
+}
+
+/***
+ * Interpolate between values a and b.
+ */
+function lerp(a, b, fraction) {
+  return (a * (1.0 - fraction)) + (b * fraction);
+}
+
+function generateRatios(scale) {
+  // Find the best two arrays to interpolate between.
+  let startTarget, endTarget;
+  let startTargetScale, endTargetScale;
+  const targetScales = Object.keys(interpolationTargets).sort();
+  for (let i = 0; i < targetScales.length - 1; i++) {
+    const targetScaleKey = targetScales[i];
+    const targetScale = parseFloat(targetScaleKey, 10);
+    const startTargetScaleKey = targetScaleKey;
+    const endTargetScaleKey = targetScales[i + 1];
+
+    if (scale < parseFloat(startTargetScaleKey, 10)) {
+      break;
+    }
+
+    startTargetScale = parseFloat(startTargetScaleKey, 10);
+    endTargetScale = parseFloat(endTargetScaleKey, 10);
+    startTarget = interpolationTargets[startTargetScaleKey];
+    endTarget = interpolationTargets[endTargetScaleKey];
+  }
+  const interpolationProgress = map(scale, startTargetScale, endTargetScale, 0, 1);
+
+  return commonSpSizes.map((sp, i) => {
+    const originalSizeDp = sp;
+    let newSizeDp;
+    switch (GENERATION_STYLE) {
+      case GenerationStyle.CUSTOM_TWEAKED:
+        newSizeDp = lerp(startTarget[i], endTarget[i], interpolationProgress);
+        break;
+      case GenerationStyle.CURVE: {
+        let coeff1;
+        let coeff2;
+        if (scale < 1) {
+          // \left(1.22^{-\left(x+5\right)}+0.5\right)\cdot x
+          coeff1 = -5;
+          coeff2 = scale;
+        } else {
+          // (1.22^{-\left(x-10\right)}+1\right)\cdot x
+          coeff1 = map(scale, 1, 2, 2, 8);
+          coeff2 = 1;
+        }
+        newSizeDp = ((Math.pow(1.22, (-(originalSizeDp - coeff1))) + coeff2) * originalSizeDp);
+        break;
+      }
+      case GenerationStyle.LINEAR:
+        newSizeDp = originalSizeDp * scale;
+        break;
+      default:
+        throw new Error('Invalid GENERATION_STYLE');
+    }
+    return {
+      fromSp: sp,
+      toDp: newSizeDp
+    }
+  });
+}
+
+const scaleArrays =
+    scales
+        .map(scale => {
+          const scaleString = (scale * 100).toFixed(0);
+          return {
+            scale,
+            name: `font_size_original_sp_to_scaled_dp_${scaleString}_percent`
+          }
+        })
+        .map(scaleArray => {
+          const items = generateRatios(scaleArray.scale);
+
+          return {
+            ...scaleArray,
+            items
+          }
+        });
+
+function formatDigit(d) {
+  const twoSignificantDigits = Math.round(d * 100) / 100;
+  return String(twoSignificantDigits).padStart(4, ' ');
+}
+
+console.log(
+    '' +
+    scaleArrays.reduce(
+        (previousScaleArray, currentScaleArray) => {
+          const itemsFromSp = currentScaleArray.items.map(d => d.fromSp)
+                                .map(formatDigit)
+                                .join('f, ');
+          const itemsToDp = currentScaleArray.items.map(d => d.toDp)
+                                .map(formatDigit)
+                                .join('f, ');
+
+          return previousScaleArray + `
+        put(
+                /* scaleKey= */ ${currentScaleArray.scale}f,
+                new FontScaleConverter(
+                        /* fromSp= */
+                        new float[] {${itemsFromSp}},
+                        /* toDp=   */
+                        new float[] {${itemsToDp}})
+        );
+     `;
+        },
+        ''));
diff --git a/tools/lint/Android.bp b/tools/lint/Android.bp
deleted file mode 100644
index 96618f4..0000000
--- a/tools/lint/Android.bp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT 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 {
-    // See: http://go/android-license-faq
-    // A large-scale-change added 'default_applicable_licenses' to import
-    // all of the 'license_kinds' from "frameworks_base_license"
-    // to get the below license kinds:
-    //   SPDX-license-identifier-Apache-2.0
-    default_applicable_licenses: ["frameworks_base_license"],
-}
-
-java_library_host {
-    name: "AndroidFrameworkLintChecker",
-    srcs: ["checks/src/main/java/**/*.kt"],
-    plugins: ["auto_service_plugin"],
-    libs: [
-        "auto_service_annotations",
-        "lint_api",
-    ],
-    kotlincflags: ["-Xjvm-default=all"],
-}
-
-java_test_host {
-    name: "AndroidFrameworkLintCheckerTest",
-    // TODO(b/239881504): Since this test was written, Android
-    // Lint was updated, and now includes classes that were
-    // compiled for java 15. The soong build doesn't support
-    // java 15 yet, so we can't compile against "lint". Disable
-    // the test until java 15 is supported.
-    enabled: false,
-    srcs: ["checks/src/test/java/**/*.kt"],
-    static_libs: [
-        "AndroidFrameworkLintChecker",
-        "junit",
-        "lint",
-        "lint_tests",
-    ],
-    test_options: {
-        unit_test: true,
-    },
-}
-
-python_binary_host {
-    name: "lint_fix",
-    main: "fix/lint_fix.py",
-    srcs: ["fix/lint_fix.py"],
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
deleted file mode 100644
index 741655b..0000000
--- a/tools/lint/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint
-
-import com.android.tools.lint.client.api.IssueRegistry
-import com.android.tools.lint.client.api.Vendor
-import com.android.tools.lint.detector.api.CURRENT_API
-import com.google.android.lint.aidl.EnforcePermissionDetector
-import com.google.android.lint.aidl.EnforcePermissionHelperDetector
-import com.google.android.lint.aidl.ManualPermissionCheckDetector
-import com.google.android.lint.parcel.SaferParcelChecker
-import com.google.auto.service.AutoService
-
-@AutoService(IssueRegistry::class)
-@Suppress("UnstableApiUsage")
-class AndroidFrameworkIssueRegistry : IssueRegistry() {
-    override val issues = listOf(
-        CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
-        CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
-        CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
-        CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
-        CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
-        CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
-        CallingIdentityTokenDetector.ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE,
-        CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
-        EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
-        EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
-        EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
-        ManualPermissionCheckDetector.ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION,
-        SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
-        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
-        RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,
-        PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
-        PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
-    )
-
-    override val api: Int
-        get() = CURRENT_API
-
-    override val minApi: Int
-        get() = 8
-
-    override val vendor: Vendor = Vendor(
-        vendorName = "Android",
-        feedbackUrl = "http://b/issues/new?component=315013",
-        contact = "brufino@google.com"
-    )
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt
deleted file mode 100644
index 1b0f035..0000000
--- a/tools/lint/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint
-
-import com.android.tools.lint.client.api.UElementHandler
-import com.android.tools.lint.detector.api.Category
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Implementation
-import com.android.tools.lint.detector.api.Issue
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.detector.api.Severity
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import com.android.tools.lint.detector.api.getUMethod
-import com.google.android.lint.aidl.hasPermissionMethodAnnotation
-import com.intellij.psi.PsiType
-import org.jetbrains.uast.UAnnotation
-import org.jetbrains.uast.UBlockExpression
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.UExpression
-import org.jetbrains.uast.UIfExpression
-import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.UQualifiedReferenceExpression
-import org.jetbrains.uast.UReturnExpression
-import org.jetbrains.uast.getContainingUMethod
-
-/**
- * Stops incorrect usage of {@link PermissionMethod}
- * TODO: add tests once re-enabled (b/240445172, b/247542171)
- */
-class PermissionMethodDetector : Detector(), SourceCodeScanner {
-
-    override fun getApplicableUastTypes(): List<Class<out UElement>> =
-        listOf(UAnnotation::class.java, UMethod::class.java)
-
-    override fun createUastHandler(context: JavaContext): UElementHandler =
-        PermissionMethodHandler(context)
-
-    private inner class PermissionMethodHandler(val context: JavaContext) : UElementHandler() {
-        override fun visitMethod(node: UMethod) {
-            if (hasPermissionMethodAnnotation(node)) return
-            if (onlyCallsPermissionMethod(node)) {
-                val location = context.getLocation(node.javaPsi.modifierList)
-                val fix = fix()
-                    .annotate(ANNOTATION_PERMISSION_METHOD)
-                    .range(location)
-                    .autoFix()
-                    .build()
-
-                context.report(
-                    ISSUE_CAN_BE_PERMISSION_METHOD,
-                    location,
-                    "Annotate method with @PermissionMethod",
-                    fix
-                )
-            }
-        }
-
-        override fun visitAnnotation(node: UAnnotation) {
-            if (node.qualifiedName != ANNOTATION_PERMISSION_METHOD) return
-            val method = node.getContainingUMethod() ?: return
-
-            if (!isPermissionMethodReturnType(method)) {
-                context.report(
-                    ISSUE_PERMISSION_METHOD_USAGE,
-                    context.getLocation(node),
-                    """
-                            Methods annotated with `@PermissionMethod` should return `void`, \
-                            `boolean`, or `@PackageManager.PermissionResult int`."
-                    """.trimIndent()
-                )
-            }
-
-            if (method.returnType == PsiType.INT &&
-                method.annotations.none { it.hasQualifiedName(ANNOTATION_PERMISSION_RESULT) }
-            ) {
-                context.report(
-                    ISSUE_PERMISSION_METHOD_USAGE,
-                    context.getLocation(node),
-                    """
-                            Methods annotated with `@PermissionMethod` that return `int` should \
-                            also be annotated with `@PackageManager.PermissionResult.`"
-                    """.trimIndent()
-                )
-            }
-        }
-    }
-
-    companion object {
-
-        private val EXPLANATION_PERMISSION_METHOD_USAGE = """
-            `@PermissionMethod` should annotate methods that ONLY perform permission lookups. \
-            Said methods should return `boolean`, `@PackageManager.PermissionResult int`, or return \
-            `void` and potentially throw `SecurityException`.
-        """.trimIndent()
-
-        @JvmField
-        val ISSUE_PERMISSION_METHOD_USAGE = Issue.create(
-            id = "PermissionMethodUsage",
-            briefDescription = "@PermissionMethod used incorrectly",
-            explanation = EXPLANATION_PERMISSION_METHOD_USAGE,
-            category = Category.CORRECTNESS,
-            priority = 5,
-            severity = Severity.ERROR,
-            implementation = Implementation(
-                PermissionMethodDetector::class.java,
-                Scope.JAVA_FILE_SCOPE
-            ),
-            enabledByDefault = true
-        )
-
-        private val EXPLANATION_CAN_BE_PERMISSION_METHOD = """
-            Methods that only call other methods annotated with @PermissionMethod (and do NOTHING else) can themselves \
-            be annotated with @PermissionMethod.  For example:
-            ```
-            void wrapperHelper() {
-              // Context.enforceCallingPermission is annotated with @PermissionMethod
-              context.enforceCallingPermission(SOME_PERMISSION)
-            }
-            ```
-        """.trimIndent()
-
-        @JvmField
-        val ISSUE_CAN_BE_PERMISSION_METHOD = Issue.create(
-            id = "CanBePermissionMethod",
-            briefDescription = "Method can be annotated with @PermissionMethod",
-            explanation = EXPLANATION_CAN_BE_PERMISSION_METHOD,
-            category = Category.SECURITY,
-            priority = 5,
-            severity = Severity.WARNING,
-            implementation = Implementation(
-                PermissionMethodDetector::class.java,
-                Scope.JAVA_FILE_SCOPE
-            ),
-            enabledByDefault = false
-        )
-
-        private fun isPermissionMethodReturnType(method: UMethod): Boolean =
-            listOf(PsiType.VOID, PsiType.INT, PsiType.BOOLEAN).contains(method.returnType)
-
-        /**
-         * Identifies methods that...
-         * DO call other methods annotated with @PermissionMethod
-         * DO NOT do anything else
-         */
-        private fun onlyCallsPermissionMethod(method: UMethod): Boolean {
-            val body = method.uastBody as? UBlockExpression ?: return false
-            if (body.expressions.isEmpty()) return false
-            for (expression in body.expressions) {
-                when (expression) {
-                    is UQualifiedReferenceExpression -> {
-                        if (!isPermissionMethodCall(expression.selector)) return false
-                    }
-                    is UReturnExpression -> {
-                        if (!isPermissionMethodCall(expression.returnExpression)) return false
-                    }
-                    is UCallExpression -> {
-                        if (!isPermissionMethodCall(expression)) return false
-                    }
-                    is UIfExpression -> {
-                        if (expression.thenExpression !is UReturnExpression) return false
-                        if (!isPermissionMethodCall(expression.condition)) return false
-                    }
-                    else -> return false
-                }
-            }
-            return true
-        }
-
-        private fun isPermissionMethodCall(expression: UExpression?): Boolean {
-            return when (expression) {
-                is UQualifiedReferenceExpression ->
-                    return isPermissionMethodCall(expression.selector)
-                is UCallExpression -> {
-                    val calledMethod = expression.resolve()?.getUMethod() ?: return false
-                    return hasPermissionMethodAnnotation(calledMethod)
-                }
-                else -> false
-            }
-        }
-    }
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
deleted file mode 100644
index d120e1d..0000000
--- a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint.aidl
-
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.Location
-import com.android.tools.lint.detector.api.getUMethod
-import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.evaluateString
-import org.jetbrains.uast.visitor.AbstractUastVisitor
-
-/**
- * Helper class that facilitates the creation of lint auto fixes
- *
- * Handles "Single" permission checks that should be migrated to @EnforcePermission(...), as well as consecutive checks
- * that should be migrated to @EnforcePermission(allOf={...})
- *
- * TODO: handle anyOf style annotations
- */
-data class EnforcePermissionFix(
-    val locations: List<Location>,
-    val permissionNames: List<String>
-) {
-    val annotation: String
-        get() {
-            val quotedPermissions = permissionNames.joinToString(", ") { """"$it"""" }
-            val annotationParameter =
-                if (permissionNames.size > 1) "allOf={$quotedPermissions}" else quotedPermissions
-            return "@$ANNOTATION_ENFORCE_PERMISSION($annotationParameter)"
-        }
-
-    companion object {
-        /**
-         * conditionally constructs EnforcePermissionFix from a UCallExpression
-         * @return EnforcePermissionFix if the called method is annotated with @PermissionMethod, else null
-         */
-        fun fromCallExpression(
-            context: JavaContext,
-            callExpression: UCallExpression
-        ): EnforcePermissionFix? =
-            if (isPermissionMethodCall(callExpression)) {
-                EnforcePermissionFix(
-                    listOf(getPermissionCheckLocation(context, callExpression)),
-                    getPermissionCheckValues(callExpression)
-                )
-            } else null
-
-
-        fun compose(individuals: List<EnforcePermissionFix>): EnforcePermissionFix =
-            EnforcePermissionFix(
-                individuals.flatMap { it.locations },
-                individuals.flatMap { it.permissionNames }
-            )
-
-        /**
-         * Given a permission check, get its proper location
-         * so that a lint fix can remove the entire expression
-         */
-        private fun getPermissionCheckLocation(
-            context: JavaContext,
-            callExpression: UCallExpression
-        ):
-                Location {
-            val javaPsi = callExpression.javaPsi!!
-            return Location.create(
-                context.file,
-                javaPsi.containingFile?.text,
-                javaPsi.textRange.startOffset,
-                // unfortunately the element doesn't include the ending semicolon
-                javaPsi.textRange.endOffset + 1
-            )
-        }
-
-        /**
-         * Given a @PermissionMethod, find arguments annotated with @PermissionName
-         * and pull out the permission value(s) being used.  Also evaluates nested calls
-         * to @PermissionMethod(s) in the given method's body.
-         */
-        private fun getPermissionCheckValues(
-            callExpression: UCallExpression
-        ): List<String> {
-            if (!isPermissionMethodCall(callExpression)) return emptyList()
-
-            val result = mutableSetOf<String>() // protect against duplicate permission values
-            val visitedCalls = mutableSetOf<UCallExpression>() // don't visit the same call twice
-            val bfsQueue = ArrayDeque(listOf(callExpression))
-
-            // Breadth First Search - evalutaing nested @PermissionMethod(s) in the available
-            // source code for @PermissionName(s).
-            while (bfsQueue.isNotEmpty()) {
-                val current = bfsQueue.removeFirst()
-                visitedCalls.add(current)
-                result.addAll(findPermissions(current))
-
-                current.resolve()?.getUMethod()?.accept(object : AbstractUastVisitor() {
-                    override fun visitCallExpression(node: UCallExpression): Boolean {
-                        if (isPermissionMethodCall(node) && node !in visitedCalls) {
-                            bfsQueue.add(node)
-                        }
-                        return false
-                    }
-                })
-            }
-
-            return result.toList()
-        }
-
-        private fun findPermissions(
-            callExpression: UCallExpression,
-        ): List<String> {
-            val indices = callExpression.resolve()?.getUMethod()
-                ?.uastParameters
-                ?.filter(::hasPermissionNameAnnotation)
-                ?.mapNotNull { it.sourcePsi?.parameterIndex() }
-                ?: emptyList()
-
-            return indices.mapNotNull {
-                callExpression.getArgumentForParameter(it)?.evaluateString()
-            }
-        }
-    }
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
deleted file mode 100644
index edbdd8d..0000000
--- a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint.aidl
-
-import com.android.tools.lint.detector.api.getUMethod
-import com.google.android.lint.ANNOTATION_PERMISSION_METHOD
-import com.google.android.lint.ANNOTATION_PERMISSION_NAME
-import com.google.android.lint.CLASS_STUB
-import com.intellij.psi.PsiAnonymousClass
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.UParameter
-
-/**
- * Given a UMethod, determine if this method is
- * an entrypoint to an interface generated by AIDL,
- * returning the interface name if so
- */
-fun getContainingAidlInterface(node: UMethod): String? {
-    if (!isInClassCalledStub(node)) return null
-    for (superMethod in node.findSuperMethods()) {
-        for (extendsInterface in superMethod.containingClass?.extendsList?.referenceElements
-            ?: continue) {
-            if (extendsInterface.qualifiedName == IINTERFACE_INTERFACE) {
-                return superMethod.containingClass?.name
-            }
-        }
-    }
-    return null
-}
-
-private fun isInClassCalledStub(node: UMethod): Boolean {
-    (node.containingClass as? PsiAnonymousClass)?.let {
-        return it.baseClassReference.referenceName == CLASS_STUB
-    }
-    return node.containingClass?.extendsList?.referenceElements?.any {
-        it.referenceName == CLASS_STUB
-    } ?: false
-}
-
-fun isPermissionMethodCall(callExpression: UCallExpression): Boolean {
-    val method = callExpression.resolve()?.getUMethod() ?: return false
-    return hasPermissionMethodAnnotation(method)
-}
-
-fun hasPermissionMethodAnnotation(method: UMethod): Boolean = method.annotations
-    .any {
-        it.hasQualifiedName(ANNOTATION_PERMISSION_METHOD)
-    }
-
-fun hasPermissionNameAnnotation(parameter: UParameter) = parameter.annotations.any {
-    it.hasQualifiedName(ANNOTATION_PERMISSION_NAME)
-}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt b/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt
deleted file mode 100644
index 2c53f39..0000000
--- a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/ManualPermissionCheckDetector.kt
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint.aidl
-
-import com.android.tools.lint.client.api.UElementHandler
-import com.android.tools.lint.detector.api.Category
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Implementation
-import com.android.tools.lint.detector.api.Issue
-import com.android.tools.lint.detector.api.JavaContext
-import com.android.tools.lint.detector.api.Scope
-import com.android.tools.lint.detector.api.Severity
-import com.android.tools.lint.detector.api.SourceCodeScanner
-import org.jetbrains.uast.UBlockExpression
-import org.jetbrains.uast.UCallExpression
-import org.jetbrains.uast.UElement
-import org.jetbrains.uast.UIfExpression
-import org.jetbrains.uast.UMethod
-import org.jetbrains.uast.UQualifiedReferenceExpression
-
-/**
- * Looks for methods implementing generated AIDL interface stubs
- * that can have simple permission checks migrated to
- * @EnforcePermission annotations
- *
- * TODO: b/242564870 (enable parse and autoFix of .aidl files)
- */
-@Suppress("UnstableApiUsage")
-class ManualPermissionCheckDetector : Detector(), SourceCodeScanner {
-    override fun getApplicableUastTypes(): List<Class<out UElement?>> =
-        listOf(UMethod::class.java)
-
-    override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context)
-
-    private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() {
-        override fun visitMethod(node: UMethod) {
-            val interfaceName = getContainingAidlInterface(node)
-                .takeUnless(EXCLUDED_CPP_INTERFACES::contains) ?: return
-            val body = (node.uastBody as? UBlockExpression) ?: return
-            val fix = accumulateSimplePermissionCheckFixes(body) ?: return
-
-            val javaRemoveFixes = fix.locations.map {
-                fix()
-                    .replace()
-                    .reformat(true)
-                    .range(it)
-                    .with("")
-                    .autoFix()
-                    .build()
-            }
-
-            val javaAnnotateFix = fix()
-                .annotate(fix.annotation)
-                .range(context.getLocation(node))
-                .autoFix()
-                .build()
-
-            val message =
-                "$interfaceName permission check can be converted to @EnforcePermission annotation"
-
-            context.report(
-                ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION,
-                fix.locations.last(),
-                message,
-                fix().composite(*javaRemoveFixes.toTypedArray(), javaAnnotateFix)
-            )
-        }
-
-        /**
-         * Walk the expressions in the method, looking for simple permission checks.
-         *
-         * If a single permission check is found at the beginning of the method,
-         * this should be migrated to @EnforcePermission(value).
-         *
-         * If multiple consecutive permission checks are found,
-         * these should be migrated to @EnforcePermission(allOf={value1, value2, ...})
-         *
-         * As soon as something other than a permission check is encountered, stop looking,
-         * as some other business logic is happening that prevents an automated fix.
-         */
-        private fun accumulateSimplePermissionCheckFixes(methodBody: UBlockExpression):
-                EnforcePermissionFix? {
-            val singleFixes = mutableListOf<EnforcePermissionFix>()
-            for (expression in methodBody.expressions) {
-                singleFixes.add(getPermissionCheckFix(expression) ?: break)
-            }
-            return when (singleFixes.size) {
-                0 -> null
-                1 -> singleFixes[0]
-                else -> EnforcePermissionFix.compose(singleFixes)
-            }
-        }
-
-        /**
-         * If an expression boils down to a permission check, return
-         * the helper for creating a lint auto fix to @EnforcePermission
-         */
-        private fun getPermissionCheckFix(startingExpression: UElement?):
-                EnforcePermissionFix? {
-            return when (startingExpression) {
-                is UQualifiedReferenceExpression -> getPermissionCheckFix(
-                    startingExpression.selector
-                )
-
-                is UIfExpression -> getPermissionCheckFix(startingExpression.condition)
-
-                is UCallExpression -> return EnforcePermissionFix
-                            .fromCallExpression(context, startingExpression)
-
-                else -> null
-            }
-        }
-    }
-
-    companion object {
-
-        private val EXPLANATION = """
-            Whenever possible, method implementations of AIDL interfaces should use the @EnforcePermission
-            annotation to declare the permissions to be enforced.  The verification code is then
-            generated by the AIDL compiler, which also takes care of annotating the generated java
-            code.
-
-            This reduces the risk of bugs around these permission checks (that often become vulnerabilities).
-            It also enables easier auditing and review.
-
-            Please migrate to an @EnforcePermission annotation. (See: go/aidl-enforce-howto)
-        """.trimIndent()
-
-        @JvmField
-        val ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION = Issue.create(
-            id = "UseEnforcePermissionAnnotation",
-            briefDescription = "Manual permission check can be @EnforcePermission annotation",
-            explanation = EXPLANATION,
-            category = Category.SECURITY,
-            priority = 5,
-            severity = Severity.WARNING,
-            implementation = Implementation(
-                ManualPermissionCheckDetector::class.java,
-                Scope.JAVA_FILE_SCOPE
-            ),
-            enabledByDefault = false, // TODO: enable once b/241171714 is resolved
-        )
-    }
-}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt b/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt
deleted file mode 100644
index d4a3497..0000000
--- a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/ManualPermissionCheckDetectorTest.kt
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.google.android.lint.aidl
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest
-import com.android.tools.lint.checks.infrastructure.TestLintTask
-import com.android.tools.lint.checks.infrastructure.TestMode
-import com.android.tools.lint.detector.api.Detector
-import com.android.tools.lint.detector.api.Issue
-
-@Suppress("UnstableApiUsage")
-class ManualPermissionCheckDetectorTest : LintDetectorTest() {
-    override fun getDetector(): Detector = ManualPermissionCheckDetector()
-    override fun getIssues(): List<Issue> = listOf(
-        ManualPermissionCheckDetector
-            .ISSUE_USE_ENFORCE_PERMISSION_ANNOTATION
-    )
-
-    override fun lint(): TestLintTask = super.lint().allowMissingSdk()
-
-    fun testClass() {
-        lint().files(
-            java(
-                """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo extends ITest.Stub {
-                        private Context mContext;
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                        }
-                    }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
-                @@ -5 +5
-                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
-                @@ -7 +8
-                -         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                """
-            )
-    }
-
-    fun testAnonClass() {
-        lint().files(
-            java(
-                """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo {
-                        private Context mContext;
-                        private ITest itest = new ITest.Stub() {
-                            @Override
-                            public void test() throws android.os.RemoteException {
-                                mContext.enforceCallingOrSelfPermission(
-                                    "android.permission.READ_CONTACTS", "foo");
-                            }
-                        };
-                    }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:8: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                            mContext.enforceCallingOrSelfPermission(
-                            ^
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 8: Annotate with @EnforcePermission:
-                @@ -6 +6
-                +         @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
-                @@ -8 +9
-                -             mContext.enforceCallingOrSelfPermission(
-                -                 "android.permission.READ_CONTACTS", "foo");
-                """
-            )
-    }
-
-    fun testConstantEvaluation() {
-        lint().files(
-            java(
-                """
-                    import android.content.Context;
-                    import android.test.ITest;
-
-                    public class Foo extends ITest.Stub {
-                        private Context mContext;
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
-                        }
-                    }
-                """
-            ).indented(),
-            *stubs,
-            manifestStub
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:8: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
-                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
-                @@ -6 +6
-                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
-                @@ -8 +9
-                -         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
-                """
-            )
-    }
-
-    fun testAllOf() {
-        lint().files(
-            java(
-                """
-                    import android.content.Context;
-                    import android.test.ITest;
-                    public class Foo {
-                        private Context mContext;
-                        private ITest itest = new ITest.Stub() {
-                            @Override
-                            public void test() throws android.os.RemoteException {
-                                mContext.enforceCallingOrSelfPermission(
-                                    "android.permission.READ_CONTACTS", "foo");
-                                mContext.enforceCallingOrSelfPermission(
-                                    "android.permission.WRITE_CONTACTS", "foo");
-                            }
-                        };
-                    }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                            mContext.enforceCallingOrSelfPermission(
-                            ^
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
-                @@ -6 +6
-                +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
-                @@ -8 +9
-                -             mContext.enforceCallingOrSelfPermission(
-                -                 "android.permission.READ_CONTACTS", "foo");
-                -             mContext.enforceCallingOrSelfPermission(
-                -                 "android.permission.WRITE_CONTACTS", "foo");
-                """
-            )
-    }
-
-    fun testPrecedingExpressions() {
-        lint().files(
-            java(
-                """
-                    import android.os.Binder;
-                    import android.test.ITest;
-                    public class Foo extends ITest.Stub {
-                        private mContext Context;
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            long uid = Binder.getCallingUid();
-                            mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                        }
-                    }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expectClean()
-    }
-
-    fun testPermissionHelper() {
-        lint().skipTestModes(TestMode.PARENTHESIZED).files(
-            java(
-                """
-                    import android.content.Context;
-                    import android.test.ITest;
-
-                    public class Foo extends ITest.Stub {
-                        private Context mContext;
-
-                        @android.content.pm.PermissionMethod
-                        private void helper() {
-                            mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                        }
-
-                        @Override
-                        public void test() throws android.os.RemoteException {
-                            helper();
-                        }
-                    }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:14: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                        helper();
-                        ~~~~~~~~~
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 14: Annotate with @EnforcePermission:
-                @@ -12 +12
-                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
-                @@ -14 +15
-                -         helper();
-                """
-            )
-    }
-
-    fun testPermissionHelperAllOf() {
-        lint().skipTestModes(TestMode.PARENTHESIZED).files(
-            java(
-                """
-                import android.content.Context;
-                import android.test.ITest;
-
-                public class Foo extends ITest.Stub {
-                    private Context mContext;
-
-                    @android.content.pm.PermissionMethod
-                    private void helper() {
-                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                        mContext.enforceCallingOrSelfPermission("android.permission.WRITE_CONTACTS", "foo");
-                    }
-
-                    @Override
-                    public void test() throws android.os.RemoteException {
-                        helper();
-                        mContext.enforceCallingOrSelfPermission("FOO", "foo");
-                    }
-                }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:16: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                        mContext.enforceCallingOrSelfPermission("FOO", "foo");
-                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 16: Annotate with @EnforcePermission:
-                @@ -13 +13
-                +     @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS", "FOO"})
-                @@ -15 +16
-                -         helper();
-                -         mContext.enforceCallingOrSelfPermission("FOO", "foo");
-                """
-            )
-    }
-
-
-    fun testPermissionHelperNested() {
-        lint().skipTestModes(TestMode.PARENTHESIZED).files(
-            java(
-                """
-                import android.content.Context;
-                import android.test.ITest;
-
-                public class Foo extends ITest.Stub {
-                    private Context mContext;
-
-                    @android.content.pm.PermissionMethod
-                    private void helperHelper() {
-                        helper("android.permission.WRITE_CONTACTS");
-                    }
-
-                    @android.content.pm.PermissionMethod
-                    private void helper(@android.content.pm.PermissionName String extraPermission) {
-                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
-                    }
-
-                    @Override
-                    public void test() throws android.os.RemoteException {
-                        helperHelper();
-                    }
-                }
-                """
-            ).indented(),
-            *stubs
-        )
-            .run()
-            .expect(
-                """
-                src/Foo.java:19: Warning: ITest permission check can be converted to @EnforcePermission annotation [UseEnforcePermissionAnnotation]
-                        helperHelper();
-                        ~~~~~~~~~~~~~~~
-                0 errors, 1 warnings
-                """
-            )
-            .expectFixDiffs(
-                """
-                Fix for src/Foo.java line 19: Annotate with @EnforcePermission:
-                @@ -17 +17
-                +     @android.annotation.EnforcePermission(allOf={"android.permission.WRITE_CONTACTS", "android.permission.READ_CONTACTS"})
-                @@ -19 +20
-                -         helperHelper();
-                """
-            )
-    }
-
-
-
-    companion object {
-        val stubs = arrayOf(
-            aidlStub,
-            contextStub,
-            binderStub,
-            permissionMethodStub,
-            permissionNameStub
-        )
-    }
-}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
deleted file mode 100644
index bd6b195..0000000
--- a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-package com.google.android.lint.aidl
-
-import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java
-import com.android.tools.lint.checks.infrastructure.TestFile
-
-val aidlStub: TestFile = java(
-    """
-        package android.test;
-        public interface ITest extends android.os.IInterface {
-            public static abstract class Stub extends android.os.Binder implements android.test.ITest {}
-            public void test() throws android.os.RemoteException;
-        }
-    """
-).indented()
-
-val contextStub: TestFile = java(
-    """
-        package android.content;
-        public class Context {
-            @android.content.pm.PermissionMethod
-            public void enforceCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {}
-        }
-    """
-).indented()
-
-val binderStub: TestFile = java(
-    """
-        package android.os;
-        public class Binder {
-            public static int getCallingUid() {}
-        }
-    """
-).indented()
-
-val permissionMethodStub: TestFile = java(
-"""
-        package android.content.pm;
-
-        import static java.lang.annotation.ElementType.METHOD;
-        import static java.lang.annotation.RetentionPolicy.CLASS;
-
-        import java.lang.annotation.Retention;
-        import java.lang.annotation.Target;
-
-        @Retention(CLASS)
-        @Target({METHOD})
-        public @interface PermissionMethod {}
-    """
-).indented()
-
-val permissionNameStub: TestFile = java(
-"""
-        package android.content.pm;
-
-        import static java.lang.annotation.ElementType.FIELD;
-        import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
-        import static java.lang.annotation.ElementType.METHOD;
-        import static java.lang.annotation.ElementType.PARAMETER;
-        import static java.lang.annotation.RetentionPolicy.CLASS;
-
-        import java.lang.annotation.Retention;
-        import java.lang.annotation.Target;
-
-        @Retention(CLASS)
-        @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
-        public @interface PermissionName {}
-    """
-).indented()
-
-val manifestStub: TestFile = java(
-    """
-        package android;
-
-        public final class Manifest {
-            public static final class permission {
-                public static final String READ_CONTACTS="android.permission.READ_CONTACTS";
-            }
-        }
-    """.trimIndent()
-)
\ No newline at end of file
diff --git a/tools/lint/common/Android.bp b/tools/lint/common/Android.bp
new file mode 100644
index 0000000..898f88b
--- /dev/null
+++ b/tools/lint/common/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library_host {
+    name: "AndroidCommonLint",
+    srcs: ["src/main/java/**/*.kt"],
+    libs: ["lint_api"],
+    kotlincflags: ["-Xjvm-default=all"],
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/Constants.kt b/tools/lint/common/src/main/java/com/google/android/lint/Constants.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/Constants.kt
rename to tools/lint/common/src/main/java/com/google/android/lint/Constants.kt
diff --git a/tools/lint/common/src/main/java/com/google/android/lint/PermissionMethodUtils.kt b/tools/lint/common/src/main/java/com/google/android/lint/PermissionMethodUtils.kt
new file mode 100644
index 0000000..0157596
--- /dev/null
+++ b/tools/lint/common/src/main/java/com/google/android/lint/PermissionMethodUtils.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint
+
+import com.android.tools.lint.detector.api.getUMethod
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.UParameter
+
+fun isPermissionMethodCall(callExpression: UCallExpression): Boolean {
+    val method = callExpression.resolve()?.getUMethod() ?: return false
+    return hasPermissionMethodAnnotation(method)
+}
+
+fun hasPermissionMethodAnnotation(method: UMethod): Boolean =
+        getPermissionMethodAnnotation(method) != null
+
+fun getPermissionMethodAnnotation(method: UMethod?): UAnnotation? = method?.uAnnotations
+        ?.firstOrNull { it.qualifiedName == ANNOTATION_PERMISSION_METHOD }
+
+fun hasPermissionNameAnnotation(parameter: UParameter) = parameter.annotations.any {
+    it.hasQualifiedName(ANNOTATION_PERMISSION_NAME)
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/model/Method.kt b/tools/lint/common/src/main/java/com/google/android/lint/model/Method.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/model/Method.kt
rename to tools/lint/common/src/main/java/com/google/android/lint/model/Method.kt
diff --git a/tools/lint/fix/Android.bp b/tools/lint/fix/Android.bp
new file mode 100644
index 0000000..5f6c6f7
--- /dev/null
+++ b/tools/lint/fix/Android.bp
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+python_binary_host {
+    name: "lint_fix",
+    main: "lint_fix.py",
+    srcs: ["lint_fix.py"],
+}
diff --git a/tools/lint/framework/Android.bp b/tools/lint/framework/Android.bp
new file mode 100644
index 0000000..7f27e8a
--- /dev/null
+++ b/tools/lint/framework/Android.bp
@@ -0,0 +1,58 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library_host {
+    name: "AndroidFrameworkLintChecker",
+    srcs: ["checks/src/main/java/**/*.kt"],
+    plugins: ["auto_service_plugin"],
+    libs: [
+        "auto_service_annotations",
+        "lint_api",
+    ],
+    static_libs: [
+        "AndroidCommonLint",
+        // TODO: remove once b/236558918 is resolved and the below checks actually run globally
+        "AndroidGlobalLintChecker",
+    ],
+    kotlincflags: ["-Xjvm-default=all"],
+}
+
+java_test_host {
+    name: "AndroidFrameworkLintCheckerTest",
+    // TODO(b/239881504): Since this test was written, Android
+    // Lint was updated, and now includes classes that were
+    // compiled for java 15. The soong build doesn't support
+    // java 15 yet, so we can't compile against "lint". Disable
+    // the test until java 15 is supported.
+    enabled: false,
+    srcs: ["checks/src/test/java/**/*.kt"],
+    static_libs: [
+        "AndroidFrameworkLintChecker",
+        "junit",
+        "lint",
+        "lint_tests",
+    ],
+    test_options: {
+        unit_test: true,
+    },
+}
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
new file mode 100644
index 0000000..c5cf0fb
--- /dev/null
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/AndroidFrameworkIssueRegistry.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.android.lint.aidl.EnforcePermissionDetector
+import com.google.android.lint.aidl.EnforcePermissionHelperDetector
+import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
+import com.google.android.lint.parcel.SaferParcelChecker
+import com.google.auto.service.AutoService
+
+@AutoService(IssueRegistry::class)
+@Suppress("UnstableApiUsage")
+class AndroidFrameworkIssueRegistry : IssueRegistry() {
+    override val issues = listOf(
+        CallingIdentityTokenDetector.ISSUE_UNUSED_TOKEN,
+        CallingIdentityTokenDetector.ISSUE_NON_FINAL_TOKEN,
+        CallingIdentityTokenDetector.ISSUE_NESTED_CLEAR_IDENTITY_CALLS,
+        CallingIdentityTokenDetector.ISSUE_RESTORE_IDENTITY_CALL_NOT_IN_FINALLY_BLOCK,
+        CallingIdentityTokenDetector.ISSUE_USE_OF_CALLER_AWARE_METHODS_WITH_CLEARED_IDENTITY,
+        CallingIdentityTokenDetector.ISSUE_CLEAR_IDENTITY_CALL_NOT_FOLLOWED_BY_TRY_FINALLY,
+        CallingIdentityTokenDetector.ISSUE_RESULT_OF_CLEAR_IDENTITY_CALL_NOT_STORED_IN_VARIABLE,
+        CallingSettingsNonUserGetterMethodsDetector.ISSUE_NON_USER_GETTER_CALLED,
+        EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
+        EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
+        EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
+        SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+        SaferParcelChecker.ISSUE_UNSAFE_API_USAGE,
+        PackageVisibilityDetector.ISSUE_PACKAGE_NAME_NO_PACKAGE_VISIBILITY_FILTERS,
+        RegisterReceiverFlagDetector.ISSUE_RECEIVER_EXPORTED_FLAG,
+        PermissionMethodDetector.ISSUE_PERMISSION_METHOD_USAGE,
+        PermissionMethodDetector.ISSUE_CAN_BE_PERMISSION_METHOD,
+    )
+
+    override val api: Int
+        get() = CURRENT_API
+
+    override val minApi: Int
+        get() = 8
+
+    override val vendor: Vendor = Vendor(
+        vendorName = "Android",
+        feedbackUrl = "http://b/issues/new?component=315013",
+        contact = "brufino@google.com"
+    )
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/CallingIdentityTokenDetector.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsDetector.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/PackageVisibilityDetector.kt
diff --git a/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt
new file mode 100644
index 0000000..e12ec3d
--- /dev/null
+++ b/tools/lint/framework/checks/src/main/java/com/google/android/lint/PermissionMethodDetector.kt
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.android.tools.lint.detector.api.getUMethod
+import com.intellij.psi.PsiType
+import org.jetbrains.uast.UAnnotation
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UExpression
+import org.jetbrains.uast.UIfExpression
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.UReturnExpression
+import org.jetbrains.uast.getContainingUMethod
+
+/**
+ * Stops incorrect usage of {@link PermissionMethod}
+ * TODO: add tests once re-enabled (b/240445172, b/247542171)
+ */
+class PermissionMethodDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableUastTypes(): List<Class<out UElement>> =
+        listOf(UAnnotation::class.java, UMethod::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler =
+        PermissionMethodHandler(context)
+
+    private inner class PermissionMethodHandler(val context: JavaContext) : UElementHandler() {
+        override fun visitMethod(node: UMethod) {
+            if (hasPermissionMethodAnnotation(node)) return
+            if (onlyCallsPermissionMethod(node)) {
+                val location = context.getLocation(node.javaPsi.modifierList)
+                val fix = fix()
+                    .annotate(ANNOTATION_PERMISSION_METHOD)
+                    .range(location)
+                    .autoFix()
+                    .build()
+
+                context.report(
+                    ISSUE_CAN_BE_PERMISSION_METHOD,
+                    location,
+                    "Annotate method with @PermissionMethod",
+                    fix
+                )
+            }
+        }
+
+        override fun visitAnnotation(node: UAnnotation) {
+            if (node.qualifiedName != ANNOTATION_PERMISSION_METHOD) return
+            val method = node.getContainingUMethod() ?: return
+
+            if (!isPermissionMethodReturnType(method)) {
+                context.report(
+                    ISSUE_PERMISSION_METHOD_USAGE,
+                    context.getLocation(node),
+                    """
+                            Methods annotated with `@PermissionMethod` should return `void`, \
+                            `boolean`, or `@PackageManager.PermissionResult int`."
+                    """.trimIndent()
+                )
+            }
+
+            if (method.returnType == PsiType.INT &&
+                method.annotations.none { it.hasQualifiedName(ANNOTATION_PERMISSION_RESULT) }
+            ) {
+                context.report(
+                    ISSUE_PERMISSION_METHOD_USAGE,
+                    context.getLocation(node),
+                    """
+                            Methods annotated with `@PermissionMethod` that return `int` should \
+                            also be annotated with `@PackageManager.PermissionResult.`"
+                    """.trimIndent()
+                )
+            }
+        }
+    }
+
+    companion object {
+
+        private val EXPLANATION_PERMISSION_METHOD_USAGE = """
+            `@PermissionMethod` should annotate methods that ONLY perform permission lookups. \
+            Said methods should return `boolean`, `@PackageManager.PermissionResult int`, or return \
+            `void` and potentially throw `SecurityException`.
+        """.trimIndent()
+
+        @JvmField
+        val ISSUE_PERMISSION_METHOD_USAGE = Issue.create(
+            id = "PermissionMethodUsage",
+            briefDescription = "@PermissionMethod used incorrectly",
+            explanation = EXPLANATION_PERMISSION_METHOD_USAGE,
+            category = Category.CORRECTNESS,
+            priority = 5,
+            severity = Severity.ERROR,
+            implementation = Implementation(
+                PermissionMethodDetector::class.java,
+                Scope.JAVA_FILE_SCOPE
+            ),
+            enabledByDefault = true
+        )
+
+        private val EXPLANATION_CAN_BE_PERMISSION_METHOD = """
+            Methods that only call other methods annotated with @PermissionMethod (and do NOTHING else) can themselves \
+            be annotated with @PermissionMethod.  For example:
+            ```
+            void wrapperHelper() {
+              // Context.enforceCallingPermission is annotated with @PermissionMethod
+              context.enforceCallingPermission(SOME_PERMISSION)
+            }
+            ```
+        """.trimIndent()
+
+        @JvmField
+        val ISSUE_CAN_BE_PERMISSION_METHOD = Issue.create(
+            id = "CanBePermissionMethod",
+            briefDescription = "Method can be annotated with @PermissionMethod",
+            explanation = EXPLANATION_CAN_BE_PERMISSION_METHOD,
+            category = Category.SECURITY,
+            priority = 5,
+            severity = Severity.WARNING,
+            implementation = Implementation(
+                PermissionMethodDetector::class.java,
+                Scope.JAVA_FILE_SCOPE
+            ),
+            enabledByDefault = false
+        )
+
+        private fun isPermissionMethodReturnType(method: UMethod): Boolean =
+            listOf(PsiType.VOID, PsiType.INT, PsiType.BOOLEAN).contains(method.returnType)
+
+        /**
+         * Identifies methods that...
+         * DO call other methods annotated with @PermissionMethod
+         * DO NOT do anything else
+         */
+        private fun onlyCallsPermissionMethod(method: UMethod): Boolean {
+            val body = method.uastBody as? UBlockExpression ?: return false
+            if (body.expressions.isEmpty()) return false
+            for (expression in body.expressions) {
+                when (expression) {
+                    is UQualifiedReferenceExpression -> {
+                        if (!isPermissionMethodCall(expression.selector)) return false
+                    }
+                    is UReturnExpression -> {
+                        if (!isPermissionMethodCall(expression.returnExpression)) return false
+                    }
+                    is UCallExpression -> {
+                        if (!isPermissionMethodCall(expression)) return false
+                    }
+                    is UIfExpression -> {
+                        if (expression.thenExpression !is UReturnExpression) return false
+                        if (!isPermissionMethodCall(expression.condition)) return false
+                    }
+                    else -> return false
+                }
+            }
+            return true
+        }
+
+        private fun isPermissionMethodCall(expression: UExpression?): Boolean {
+            return when (expression) {
+                is UQualifiedReferenceExpression ->
+                    return isPermissionMethodCall(expression.selector)
+                is UCallExpression -> {
+                    val calledMethod = expression.resolve()?.getUMethod() ?: return false
+                    return hasPermissionMethodAnnotation(calledMethod)
+                }
+                else -> false
+            }
+        }
+
+        private fun hasPermissionMethodAnnotation(method: UMethod): Boolean = method.annotations
+                .any { it.hasQualifiedName(ANNOTATION_PERMISSION_METHOD) }
+    }
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/RegisterReceiverFlagDetector.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/CallMigrators.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/Method.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/parcel/Method.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/Method.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt b/tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt
rename to tools/lint/framework/checks/src/main/java/com/google/android/lint/parcel/SaferParcelChecker.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
rename to tools/lint/framework/checks/src/test/java/com/google/android/lint/CallingIdentityTokenDetectorTest.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
rename to tools/lint/framework/checks/src/test/java/com/google/android/lint/CallingSettingsNonUserGetterMethodsIssueDetectorTest.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt
rename to tools/lint/framework/checks/src/test/java/com/google/android/lint/PackageVisibilityDetectorTest.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
rename to tools/lint/framework/checks/src/test/java/com/google/android/lint/RegisterReceiverFlagDetectorTest.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt b/tools/lint/framework/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt
rename to tools/lint/framework/checks/src/test/java/com/google/android/lint/parcel/SaferParcelCheckerTest.kt
diff --git a/tools/lint/global/Android.bp b/tools/lint/global/Android.bp
new file mode 100644
index 0000000..3756abe
--- /dev/null
+++ b/tools/lint/global/Android.bp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT 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 {
+    // See: http://go/android-license-faq
+    // A large-scale-change added 'default_applicable_licenses' to import
+    // all of the 'license_kinds' from "frameworks_base_license"
+    // to get the below license kinds:
+    //   SPDX-license-identifier-Apache-2.0
+    default_applicable_licenses: ["frameworks_base_license"],
+}
+
+java_library_host {
+    name: "AndroidGlobalLintChecker",
+    srcs: ["checks/src/main/java/**/*.kt"],
+    plugins: ["auto_service_plugin"],
+    libs: [
+        "auto_service_annotations",
+        "lint_api",
+    ],
+    static_libs: ["AndroidCommonLint"],
+    kotlincflags: ["-Xjvm-default=all"],
+    dist: {
+        targets: ["droid"],
+    },
+}
+
+java_test_host {
+    name: "AndroidGlobalLintCheckerTest",
+    // TODO(b/239881504): Since this test was written, Android
+    // Lint was updated, and now includes classes that were
+    // compiled for java 15. The soong build doesn't support
+    // java 15 yet, so we can't compile against "lint". Disable
+    // the test until java 15 is supported.
+    enabled: false,
+    srcs: ["checks/src/test/java/**/*.kt"],
+    static_libs: [
+        "AndroidGlobalLintChecker",
+        "junit",
+        "lint",
+        "lint_tests",
+    ],
+    test_options: {
+        unit_test: true,
+    },
+}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
new file mode 100644
index 0000000..a20266a
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/AndroidGlobalIssueRegistry.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint
+
+import com.android.tools.lint.client.api.IssueRegistry
+import com.android.tools.lint.client.api.Vendor
+import com.android.tools.lint.detector.api.CURRENT_API
+import com.google.android.lint.aidl.EnforcePermissionDetector
+import com.google.android.lint.aidl.EnforcePermissionHelperDetector
+import com.google.android.lint.aidl.SimpleManualPermissionEnforcementDetector
+import com.google.auto.service.AutoService
+
+@AutoService(IssueRegistry::class)
+@Suppress("UnstableApiUsage")
+class AndroidGlobalIssueRegistry : IssueRegistry() {
+    override val issues = listOf(
+            EnforcePermissionDetector.ISSUE_MISSING_ENFORCE_PERMISSION,
+            EnforcePermissionDetector.ISSUE_MISMATCHING_ENFORCE_PERMISSION,
+            EnforcePermissionHelperDetector.ISSUE_ENFORCE_PERMISSION_HELPER,
+            SimpleManualPermissionEnforcementDetector.ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+    )
+
+    override val api: Int
+        get() = CURRENT_API
+
+    override val minApi: Int
+        get() = 8
+
+    override val vendor: Vendor = Vendor(
+            vendorName = "Android",
+            feedbackUrl = "http://b/issues/new?component=315013",
+            contact = "repsonsible-apis@google.com"
+    )
+}
\ No newline at end of file
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
new file mode 100644
index 0000000..227cdcd
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/AidlImplementationDetector.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint.aidl
+
+import com.android.tools.lint.client.api.UElementHandler
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UMethod
+
+/**
+ * Abstract class for detectors that look for methods implementing
+ * generated AIDL interface stubs
+ */
+abstract class AidlImplementationDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableUastTypes(): List<Class<out UElement?>> =
+            listOf(UMethod::class.java)
+
+    override fun createUastHandler(context: JavaContext): UElementHandler = AidlStubHandler(context)
+
+    private inner class AidlStubHandler(val context: JavaContext) : UElementHandler() {
+        override fun visitMethod(node: UMethod) {
+            val interfaceName = getContainingAidlInterface(node)
+                    .takeUnless(EXCLUDED_CPP_INTERFACES::contains) ?: return
+            val body = (node.uastBody as? UBlockExpression) ?: return
+            visitAidlMethod(context, node, interfaceName, body)
+        }
+    }
+
+    abstract fun visitAidlMethod(
+            context: JavaContext,
+            node: UMethod,
+            interfaceName: String,
+            body: UBlockExpression,
+    )
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/Constants.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
rename to tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/Constants.kt
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
rename to tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionDetector.kt
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
new file mode 100644
index 0000000..ee7dd62
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionFix.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint.aidl
+
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.LintFix
+import com.android.tools.lint.detector.api.Location
+import com.android.tools.lint.detector.api.UastLintUtils.Companion.getAnnotationBooleanValue
+import com.android.tools.lint.detector.api.getUMethod
+import com.google.android.lint.getPermissionMethodAnnotation
+import com.google.android.lint.hasPermissionNameAnnotation
+import com.google.android.lint.isPermissionMethodCall
+import com.intellij.psi.PsiType
+import org.jetbrains.kotlin.psi.psiUtil.parameterIndex
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.evaluateString
+import org.jetbrains.uast.visitor.AbstractUastVisitor
+
+/**
+ * Helper class that facilitates the creation of lint auto fixes
+ *
+ * Handles "Single" permission checks that should be migrated to @EnforcePermission(...), as well as consecutive checks
+ * that should be migrated to @EnforcePermission(allOf={...})
+ *
+ * TODO: handle anyOf style annotations
+ */
+data class EnforcePermissionFix(
+    val locations: List<Location>,
+    val permissionNames: List<String>,
+    val errorLevel: Boolean,
+) {
+    fun toLintFix(annotationLocation: Location): LintFix {
+        val removeFixes = this.locations.map {
+            LintFix.create()
+                .replace()
+                .reformat(true)
+                .range(it)
+                .with("")
+                .autoFix()
+                .build()
+        }
+
+        val annotateFix = LintFix.create()
+            .annotate(this.annotation)
+            .range(annotationLocation)
+            .autoFix()
+            .build()
+
+        return LintFix.create().composite(annotateFix, *removeFixes.toTypedArray())
+    }
+
+    private val annotation: String
+        get() {
+            val quotedPermissions = permissionNames.joinToString(", ") { """"$it"""" }
+
+            val annotationParameter =
+                if (permissionNames.size > 1) "allOf={$quotedPermissions}"
+                else quotedPermissions
+
+            return "@$ANNOTATION_ENFORCE_PERMISSION($annotationParameter)"
+        }
+
+    companion object {
+        /**
+         * conditionally constructs EnforcePermissionFix from a UCallExpression
+         * @return EnforcePermissionFix if the called method is annotated with @PermissionMethod, else null
+         */
+        fun fromCallExpression(
+            context: JavaContext,
+            callExpression: UCallExpression
+        ): EnforcePermissionFix? {
+            val method = callExpression.resolve()?.getUMethod() ?: return null
+            val annotation = getPermissionMethodAnnotation(method) ?: return null
+            val enforces = method.returnType == PsiType.VOID
+            val orSelf = getAnnotationBooleanValue(annotation, "orSelf") ?: false
+            return EnforcePermissionFix(
+                    listOf(getPermissionCheckLocation(context, callExpression)),
+                    getPermissionCheckValues(callExpression),
+                    // If we detect that the PermissionMethod enforces that permission is granted,
+                    // AND is of the "orSelf" variety, we are very confident that this is a behavior
+                    // preserving migration to @EnforcePermission.  Thus, the incident should be ERROR
+                    // level.
+                    errorLevel = enforces && orSelf
+            )
+        }
+
+
+        fun compose(individuals: List<EnforcePermissionFix>): EnforcePermissionFix =
+            EnforcePermissionFix(
+                individuals.flatMap { it.locations },
+                individuals.flatMap { it.permissionNames },
+                errorLevel = individuals.all(EnforcePermissionFix::errorLevel)
+            )
+
+        /**
+         * Given a permission check, get its proper location
+         * so that a lint fix can remove the entire expression
+         */
+        private fun getPermissionCheckLocation(
+            context: JavaContext,
+            callExpression: UCallExpression
+        ):
+                Location {
+            val javaPsi = callExpression.javaPsi!!
+            return Location.create(
+                context.file,
+                javaPsi.containingFile?.text,
+                javaPsi.textRange.startOffset,
+                // unfortunately the element doesn't include the ending semicolon
+                javaPsi.textRange.endOffset + 1
+            )
+        }
+
+        /**
+         * Given a @PermissionMethod, find arguments annotated with @PermissionName
+         * and pull out the permission value(s) being used.  Also evaluates nested calls
+         * to @PermissionMethod(s) in the given method's body.
+         */
+        private fun getPermissionCheckValues(
+            callExpression: UCallExpression
+        ): List<String> {
+            if (!isPermissionMethodCall(callExpression)) return emptyList()
+
+            val result = mutableSetOf<String>() // protect against duplicate permission values
+            val visitedCalls = mutableSetOf<UCallExpression>() // don't visit the same call twice
+            val bfsQueue = ArrayDeque(listOf(callExpression))
+
+            // Breadth First Search - evalutaing nested @PermissionMethod(s) in the available
+            // source code for @PermissionName(s).
+            while (bfsQueue.isNotEmpty()) {
+                val current = bfsQueue.removeFirst()
+                visitedCalls.add(current)
+                result.addAll(findPermissions(current))
+
+                current.resolve()?.getUMethod()?.accept(object : AbstractUastVisitor() {
+                    override fun visitCallExpression(node: UCallExpression): Boolean {
+                        if (isPermissionMethodCall(node) && node !in visitedCalls) {
+                            bfsQueue.add(node)
+                        }
+                        return false
+                    }
+                })
+            }
+
+            return result.toList()
+        }
+
+        private fun findPermissions(
+            callExpression: UCallExpression,
+        ): List<String> {
+            val indices = callExpression.resolve()?.getUMethod()
+                ?.uastParameters
+                ?.filter(::hasPermissionNameAnnotation)
+                ?.mapNotNull { it.sourcePsi?.parameterIndex() }
+                ?: emptyList()
+
+            return indices.mapNotNull {
+                callExpression.getArgumentForParameter(it)?.evaluateString()
+            }
+        }
+    }
+}
diff --git a/tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
similarity index 100%
rename from tools/lint/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
rename to tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionHelperDetector.kt
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
new file mode 100644
index 0000000..250ca78
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/EnforcePermissionUtils.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint.aidl
+
+import com.google.android.lint.CLASS_STUB
+import com.intellij.psi.PsiAnonymousClass
+import org.jetbrains.uast.UMethod
+
+/**
+ * Given a UMethod, determine if this method is
+ * an entrypoint to an interface generated by AIDL,
+ * returning the interface name if so
+ */
+fun getContainingAidlInterface(node: UMethod): String? {
+    if (!isInClassCalledStub(node)) return null
+    for (superMethod in node.findSuperMethods()) {
+        for (extendsInterface in superMethod.containingClass?.extendsList?.referenceElements
+            ?: continue) {
+            if (extendsInterface.qualifiedName == IINTERFACE_INTERFACE) {
+                return superMethod.containingClass?.name
+            }
+        }
+    }
+    return null
+}
+
+private fun isInClassCalledStub(node: UMethod): Boolean {
+    (node.containingClass as? PsiAnonymousClass)?.let {
+        return it.baseClassReference.referenceName == CLASS_STUB
+    }
+    return node.containingClass?.extendsList?.referenceElements?.any {
+        it.referenceName == CLASS_STUB
+    } ?: false
+}
diff --git a/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
new file mode 100644
index 0000000..9999a0b
--- /dev/null
+++ b/tools/lint/global/checks/src/main/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetector.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint.aidl
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Incident
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import org.jetbrains.uast.UBlockExpression
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.UElement
+import org.jetbrains.uast.UIfExpression
+import org.jetbrains.uast.UMethod
+import org.jetbrains.uast.UQualifiedReferenceExpression
+import org.jetbrains.uast.skipParenthesizedExprDown
+
+/**
+ * Looks for methods implementing generated AIDL interface stubs
+ * that can have simple permission checks migrated to
+ * @EnforcePermission annotations
+ *
+ * TODO: b/242564870 (enable parse and autoFix of .aidl files)
+ */
+@Suppress("UnstableApiUsage")
+class SimpleManualPermissionEnforcementDetector : AidlImplementationDetector() {
+    override fun visitAidlMethod(
+            context: JavaContext,
+            node: UMethod,
+            interfaceName: String,
+            body: UBlockExpression
+    ) {
+        val enforcePermissionFix = accumulateSimplePermissionCheckFixes(body, context) ?: return
+        val lintFix = enforcePermissionFix.toLintFix(context.getLocation(node))
+        val message =
+                "$interfaceName permission check ${
+                    if (enforcePermissionFix.errorLevel) "should" else "can"
+                } be converted to @EnforcePermission annotation"
+
+        val incident = Incident(
+                ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT,
+                enforcePermissionFix.locations.last(),
+                message,
+                lintFix
+        )
+
+        if (enforcePermissionFix.errorLevel) {
+            incident.overrideSeverity(Severity.ERROR)
+        }
+
+        context.report(incident)
+    }
+
+    /**
+     * Walk the expressions in the method, looking for simple permission checks.
+     *
+     * If a single permission check is found at the beginning of the method,
+     * this should be migrated to @EnforcePermission(value).
+     *
+     * If multiple consecutive permission checks are found,
+     * these should be migrated to @EnforcePermission(allOf={value1, value2, ...})
+     *
+     * As soon as something other than a permission check is encountered, stop looking,
+     * as some other business logic is happening that prevents an automated fix.
+     */
+    private fun accumulateSimplePermissionCheckFixes(
+            methodBody: UBlockExpression,
+            context: JavaContext
+    ):
+            EnforcePermissionFix? {
+        val singleFixes = mutableListOf<EnforcePermissionFix>()
+        for (expression in methodBody.expressions) {
+            singleFixes.add(getPermissionCheckFix(expression.skipParenthesizedExprDown(), context)
+                    ?: break)
+        }
+        return when (singleFixes.size) {
+            0 -> null
+            1 -> singleFixes[0]
+            else -> EnforcePermissionFix.compose(singleFixes)
+        }
+    }
+
+    /**
+     * If an expression boils down to a permission check, return
+     * the helper for creating a lint auto fix to @EnforcePermission
+     */
+    private fun getPermissionCheckFix(startingExpression: UElement?, context: JavaContext):
+            EnforcePermissionFix? {
+        return when (startingExpression) {
+            is UQualifiedReferenceExpression -> getPermissionCheckFix(
+                    startingExpression.selector, context
+            )
+
+            is UIfExpression -> getPermissionCheckFix(startingExpression.condition, context)
+
+            is UCallExpression -> return EnforcePermissionFix
+                    .fromCallExpression(context, startingExpression)
+
+            else -> null
+        }
+    }
+
+    companion object {
+
+        private val EXPLANATION = """
+            Whenever possible, method implementations of AIDL interfaces should use the @EnforcePermission
+            annotation to declare the permissions to be enforced.  The verification code is then
+            generated by the AIDL compiler, which also takes care of annotating the generated java
+            code.
+
+            This reduces the risk of bugs around these permission checks (that often become vulnerabilities).
+            It also enables easier auditing and review.
+
+            Please migrate to an @EnforcePermission annotation. (See: go/aidl-enforce-howto)
+        """.trimIndent()
+
+        @JvmField
+        val ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT = Issue.create(
+                id = "SimpleManualPermissionEnforcement",
+                briefDescription = "Manual permission check can be @EnforcePermission annotation",
+                explanation = EXPLANATION,
+                category = Category.SECURITY,
+                priority = 5,
+                severity = Severity.WARNING,
+                implementation = Implementation(
+                        SimpleManualPermissionEnforcementDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE
+                ),
+                enabledByDefault = false, // TODO: enable once b/241171714 is resolved
+        )
+    }
+}
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
rename to tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionDetectorTest.kt
diff --git a/tools/lint/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt
similarity index 100%
rename from tools/lint/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt
rename to tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/EnforcePermissionHelperDetectorTest.kt
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
new file mode 100644
index 0000000..bdf9c89
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/SimpleManualPermissionEnforcementDetectorTest.kt
@@ -0,0 +1,578 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+
+@Suppress("UnstableApiUsage")
+class SimpleManualPermissionEnforcementDetectorTest : LintDetectorTest() {
+    override fun getDetector(): Detector = SimpleManualPermissionEnforcementDetector()
+    override fun getIssues(): List<Issue> = listOf(
+            SimpleManualPermissionEnforcementDetector
+            .ISSUE_SIMPLE_MANUAL_PERMISSION_ENFORCEMENT
+    )
+
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk()
+
+    fun testClass() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:7: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                @@ -5 +5
+                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                @@ -7 +8
+                -         mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                """
+            )
+    }
+
+    fun testClass_orSelfFalse_warning() {
+        lint().files(
+                java(
+                    """
+                    import android.content.Context;
+                    import android.test.ITest;
+                    public class Foo extends ITest.Stub {
+                        private Context mContext;
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.enforceCallingPermission("android.permission.READ_CONTACTS", "foo");
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                    """
+                    src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.enforceCallingPermission("android.permission.READ_CONTACTS", "foo");
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                    0 errors, 1 warnings
+                    """
+                )
+                .expectFixDiffs(
+                    """
+                    Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                    @@ -5 +5
+                    +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                    @@ -7 +8
+                    -         mContext.enforceCallingPermission("android.permission.READ_CONTACTS", "foo");
+                    """
+                )
+    }
+
+    fun testClass_enforcesFalse_warning() {
+        lint().files(
+                java(
+                    """
+                    import android.content.Context;
+                    import android.test.ITest;
+                    public class Foo extends ITest.Stub {
+                        private Context mContext;
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                        }
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                    """
+                    src/Foo.java:7: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                    0 errors, 1 warnings
+                    """
+                )
+                .expectFixDiffs(
+                    """
+                    Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                    @@ -5 +5
+                    +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                    @@ -7 +8
+                    -         mContext.checkCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    """
+                )
+    }
+
+    fun testAnonClass() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo {
+                    private Context mContext;
+                    private ITest itest = new ITest.Stub() {
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.enforceCallingOrSelfPermission(
+                                "android.permission.READ_CONTACTS", "foo");
+                        }
+                    };
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.enforceCallingOrSelfPermission(
+                            ^
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 8: Annotate with @EnforcePermission:
+                @@ -6 +6
+                +         @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                @@ -8 +9
+                -             mContext.enforceCallingOrSelfPermission(
+                -                 "android.permission.READ_CONTACTS", "foo");
+                """
+            )
+    }
+
+    fun testConstantEvaluation() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
+                    }
+                }
+                """
+            ).indented(),
+            *stubs,
+            manifestStub
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:8: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 7: Annotate with @EnforcePermission:
+                @@ -6 +6
+                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                @@ -8 +9
+                -         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_CONTACTS, "foo");
+                """
+            )
+    }
+
+    fun testAllOf() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+                public class Foo {
+                    private Context mContext;
+                    private ITest itest = new ITest.Stub() {
+                        @Override
+                        public void test() throws android.os.RemoteException {
+                            mContext.enforceCallingOrSelfPermission(
+                                "android.permission.READ_CONTACTS", "foo");
+                            mContext.enforceCallingOrSelfPermission(
+                                "android.permission.WRITE_CONTACTS", "foo");
+                        }
+                    };
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:10: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            mContext.enforceCallingOrSelfPermission(
+                            ^
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
+                @@ -6 +6
+                +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
+                @@ -8 +9
+                -             mContext.enforceCallingOrSelfPermission(
+                -                 "android.permission.READ_CONTACTS", "foo");
+                -             mContext.enforceCallingOrSelfPermission(
+                -                 "android.permission.WRITE_CONTACTS", "foo");
+                """
+            )
+    }
+
+    fun testAllOf_mixedOrSelf_warning() {
+        lint().files(
+                java(
+                    """
+                    import android.content.Context;
+                    import android.test.ITest;
+                    public class Foo {
+                        private Context mContext;
+                        private ITest itest = new ITest.Stub() {
+                            @Override
+                            public void test() throws android.os.RemoteException {
+                                mContext.enforceCallingOrSelfPermission(
+                                    "android.permission.READ_CONTACTS", "foo");
+                                mContext.enforceCallingPermission(
+                                    "android.permission.WRITE_CONTACTS", "foo");
+                            }
+                        };
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                    """
+                    src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                                mContext.enforceCallingPermission(
+                                ^
+                    0 errors, 1 warnings
+                    """
+                )
+                .expectFixDiffs(
+                    """
+                    Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
+                    @@ -6 +6
+                    +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
+                    @@ -8 +9
+                    -             mContext.enforceCallingOrSelfPermission(
+                    -                 "android.permission.READ_CONTACTS", "foo");
+                    -             mContext.enforceCallingPermission(
+                    -                 "android.permission.WRITE_CONTACTS", "foo");
+                    """
+                )
+    }
+
+    fun testAllOf_mixedEnforces_warning() {
+        lint().files(
+                java(
+                    """
+                    import android.content.Context;
+                    import android.test.ITest;
+                    public class Foo {
+                        private Context mContext;
+                        private ITest itest = new ITest.Stub() {
+                            @Override
+                            public void test() throws android.os.RemoteException {
+                                mContext.enforceCallingOrSelfPermission(
+                                    "android.permission.READ_CONTACTS", "foo");
+                                mContext.checkCallingOrSelfPermission(
+                                    "android.permission.WRITE_CONTACTS", "foo");
+                            }
+                        };
+                    }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                    """
+                    src/Foo.java:10: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                                mContext.checkCallingOrSelfPermission(
+                                ^
+                    0 errors, 1 warnings
+                    """
+                )
+                .expectFixDiffs(
+                    """
+                    Fix for src/Foo.java line 10: Annotate with @EnforcePermission:
+                    @@ -6 +6
+                    +         @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS"})
+                    @@ -8 +9
+                    -             mContext.enforceCallingOrSelfPermission(
+                    -                 "android.permission.READ_CONTACTS", "foo");
+                    -             mContext.checkCallingOrSelfPermission(
+                    -                 "android.permission.WRITE_CONTACTS", "foo");
+                    """
+                )
+    }
+
+    fun testPrecedingExpressions() {
+        lint().files(
+            java(
+                """
+                import android.os.Binder;
+                import android.test.ITest;
+                public class Foo extends ITest.Stub {
+                    private mContext Context;
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        long uid = Binder.getCallingUid();
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expectClean()
+    }
+
+    fun testPermissionHelper() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+
+                    @android.content.pm.PermissionMethod(orSelf = true)
+                    private void helper() {
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    }
+
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        helper();
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:14: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        helper();
+                        ~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 14: Annotate with @EnforcePermission:
+                @@ -12 +12
+                +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                @@ -14 +15
+                -         helper();
+                """
+            )
+    }
+
+    fun testPermissionHelper_orSelfNotBubbledUp_warning() {
+        lint().files(
+                java(
+                    """
+                    import android.content.Context;
+                    import android.test.ITest;
+
+                    public class Foo extends ITest.Stub {
+                        private Context mContext;
+
+                        @android.content.pm.PermissionMethod
+                    private void helper() {
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    }
+
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        helper();
+                    }
+                }
+                    """
+                ).indented(),
+                *stubs
+        )
+                .run()
+                .expect(
+                    """
+                    src/Foo.java:14: Warning: ITest permission check can be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                            helper();
+                            ~~~~~~~~~
+                    0 errors, 1 warnings
+                    """
+                )
+                .expectFixDiffs(
+                    """
+                    Fix for src/Foo.java line 14: Annotate with @EnforcePermission:
+                    @@ -12 +12
+                    +     @android.annotation.EnforcePermission("android.permission.READ_CONTACTS")
+                    @@ -14 +15
+                    -         helper();
+                    """
+                )
+    }
+
+    fun testPermissionHelperAllOf() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+
+                    @android.content.pm.PermissionMethod(orSelf = true)
+                    private void helper() {
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                        mContext.enforceCallingOrSelfPermission("android.permission.WRITE_CONTACTS", "foo");
+                    }
+
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        helper();
+                        mContext.enforceCallingOrSelfPermission("FOO", "foo");
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:16: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        mContext.enforceCallingOrSelfPermission("FOO", "foo");
+                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 16: Annotate with @EnforcePermission:
+                @@ -13 +13
+                +     @android.annotation.EnforcePermission(allOf={"android.permission.READ_CONTACTS", "android.permission.WRITE_CONTACTS", "FOO"})
+                @@ -15 +16
+                -         helper();
+                -         mContext.enforceCallingOrSelfPermission("FOO", "foo");
+                """
+            )
+    }
+
+
+    fun testPermissionHelperNested() {
+        lint().files(
+            java(
+                """
+                import android.content.Context;
+                import android.test.ITest;
+
+                public class Foo extends ITest.Stub {
+                    private Context mContext;
+
+                    @android.content.pm.PermissionMethod(orSelf = true)
+                    private void helperHelper() {
+                        helper("android.permission.WRITE_CONTACTS");
+                    }
+
+                    @android.content.pm.PermissionMethod(orSelf = true)
+                    private void helper(@android.content.pm.PermissionName String extraPermission) {
+                        mContext.enforceCallingOrSelfPermission("android.permission.READ_CONTACTS", "foo");
+                    }
+
+                    @Override
+                    public void test() throws android.os.RemoteException {
+                        helperHelper();
+                    }
+                }
+                """
+            ).indented(),
+            *stubs
+        )
+            .run()
+            .expect(
+                """
+                src/Foo.java:19: Error: ITest permission check should be converted to @EnforcePermission annotation [SimpleManualPermissionEnforcement]
+                        helperHelper();
+                        ~~~~~~~~~~~~~~~
+                1 errors, 0 warnings
+                """
+            )
+            .expectFixDiffs(
+                """
+                Fix for src/Foo.java line 19: Annotate with @EnforcePermission:
+                @@ -17 +17
+                +     @android.annotation.EnforcePermission(allOf={"android.permission.WRITE_CONTACTS", "android.permission.READ_CONTACTS"})
+                @@ -19 +20
+                -         helperHelper();
+                """
+            )
+    }
+
+
+
+    companion object {
+        val stubs = arrayOf(
+            aidlStub,
+            contextStub,
+            binderStub,
+            permissionMethodStub,
+            permissionNameStub
+        )
+    }
+}
diff --git a/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
new file mode 100644
index 0000000..5ac8a0b
--- /dev/null
+++ b/tools/lint/global/checks/src/test/java/com/google/android/lint/aidl/Stubs.kt
@@ -0,0 +1,84 @@
+package com.google.android.lint.aidl
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest.java
+import com.android.tools.lint.checks.infrastructure.TestFile
+
+val aidlStub: TestFile = java(
+    """
+        package android.test;
+        public interface ITest extends android.os.IInterface {
+            public static abstract class Stub extends android.os.Binder implements android.test.ITest {}
+            public void test() throws android.os.RemoteException;
+        }
+    """
+).indented()
+
+val contextStub: TestFile = java(
+    """
+        package android.content;
+        public class Context {
+            @android.content.pm.PermissionMethod(orSelf = true)
+            public void enforceCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {}
+            @android.content.pm.PermissionMethod
+            public void enforceCallingPermission(@android.content.pm.PermissionName String permission, String message) {}
+            @android.content.pm.PermissionMethod(orSelf = true)
+            public int checkCallingOrSelfPermission(@android.content.pm.PermissionName String permission, String message) {}
+        }
+    """
+).indented()
+
+val binderStub: TestFile = java(
+    """
+        package android.os;
+        public class Binder {
+            public static int getCallingUid() {}
+        }
+    """
+).indented()
+
+val permissionMethodStub: TestFile = java(
+"""
+        package android.content.pm;
+
+        import static java.lang.annotation.ElementType.METHOD;
+        import static java.lang.annotation.RetentionPolicy.CLASS;
+
+        import java.lang.annotation.Retention;
+        import java.lang.annotation.Target;
+
+        @Retention(CLASS)
+        @Target({METHOD})
+        public @interface PermissionMethod {}
+    """
+).indented()
+
+val permissionNameStub: TestFile = java(
+"""
+        package android.content.pm;
+
+        import static java.lang.annotation.ElementType.FIELD;
+        import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
+        import static java.lang.annotation.ElementType.METHOD;
+        import static java.lang.annotation.ElementType.PARAMETER;
+        import static java.lang.annotation.RetentionPolicy.CLASS;
+
+        import java.lang.annotation.Retention;
+        import java.lang.annotation.Target;
+
+        @Retention(CLASS)
+        @Target({PARAMETER, METHOD, LOCAL_VARIABLE, FIELD})
+        public @interface PermissionName {}
+    """
+).indented()
+
+val manifestStub: TestFile = java(
+    """
+        package android;
+
+        public final class Manifest {
+            public static final class permission {
+                public static final String READ_CONTACTS="android.permission.READ_CONTACTS";
+            }
+        }
+    """.trimIndent()
+)
\ No newline at end of file
diff --git a/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt b/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt
index f29d9b2..c6f6d45 100644
--- a/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt
+++ b/tools/processors/immutability/src/android/processor/immutability/ImmutabilityProcessor.kt
@@ -54,6 +54,7 @@
             "java.lang.Short",
             "java.lang.String",
             "java.lang.Void",
+            "java.util.UUID",
             "android.os.Parcelable.Creator",
         )
 
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 0d7d5f9..0fa13b8 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -167,8 +167,8 @@
             android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
                     PropertyMap::load(String8(filename));
             if (!propertyMap.ok()) {
-                error("Error %d parsing input device configuration file.\n\n",
-                      propertyMap.error().code());
+                error("Error parsing input device configuration file: %s.\n\n",
+                      propertyMap.error().message().c_str());
                 return false;
             }
             break;
diff --git a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
index d85a5bd..5da18dc 100644
--- a/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
+++ b/wifi/java/src/android/net/wifi/nl80211/WifiNl80211Manager.java
@@ -393,6 +393,21 @@
         mEventHandler = new Handler(context.getMainLooper());
     }
 
+    /**
+     * Construct WifiNl80211Manager with giving context and binder which is an interface of
+     * IWificond.
+     *
+     * @param context Android context.
+     * @param binder a binder of IWificond.
+     */
+    public WifiNl80211Manager(@NonNull Context context, @NonNull IBinder binder) {
+        this(context);
+        mWificond = IWificond.Stub.asInterface(binder);
+        if (mWificond == null) {
+            Log.e(TAG, "Failed to get reference to wificond");
+        }
+    }
+
     /** @hide */
     @VisibleForTesting
     public WifiNl80211Manager(Context context, IWificond wificond) {